Files
clang-p2996/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
Walter Erquinigo 4a843d9282 [trace][intel pt] Create a CPU change event and expose it in the dumper
Thanks to fredzhou@fb.com for coming up with this feature.

When tracing in per-cpu mode, we have information of in which cpu we are execution each instruction, which comes from the context switch trace. This diff makes this information available as a `cpu changed event`, which an additional accessor in the cursor `GetCPU()`. As cpu changes are very infrequent, any consumer should listen to cpu change events instead of querying the actual cpu of a trace item. Once a cpu change event is seen, the consumer can invoke GetCPU() to get that information. Also, it's possible to invoke GetCPU() on an arbitrary instruction item, which will return the last cpu seen. However, this call is O(logn) and should be used sparingly.

Manually tested with a sample program that starts on cpu 52, then goes to 18, and then goes back to 52.

Differential Revision: https://reviews.llvm.org/D129340
2022-07-13 12:26:11 -07:00

109 lines
3.1 KiB
C++

//===-- TraceCursorIntelPT.cpp --------------------------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
#include "TraceCursorIntelPT.h"
#include "DecodedThread.h"
#include "TraceIntelPT.h"
#include <cstdlib>
using namespace lldb;
using namespace lldb_private;
using namespace lldb_private::trace_intel_pt;
using namespace llvm;
TraceCursorIntelPT::TraceCursorIntelPT(ThreadSP thread_sp,
DecodedThreadSP decoded_thread_sp)
: TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp) {
Seek(0, SeekType::End);
}
void TraceCursorIntelPT::CalculateTscRange() {
// If we failed, then we look for the exact range
if (!m_tsc_range || !m_tsc_range->InRange(m_pos))
m_tsc_range = m_decoded_thread_sp->CalculateTscRange(
m_pos, /*hit_range=*/m_tsc_range);
}
void TraceCursorIntelPT::Next() {
m_pos += IsForwards() ? 1 : -1;
// We try to go to a neighbor tsc range that might contain the current pos
if (m_tsc_range && !m_tsc_range->InRange(m_pos))
m_tsc_range = IsForwards() ? m_tsc_range->Next() : m_tsc_range->Prev();
// If we failed, this call will fix it
CalculateTscRange();
}
bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
switch (origin) {
case TraceCursor::SeekType::Beginning:
m_pos = offset;
break;
case TraceCursor::SeekType::End:
m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
break;
case TraceCursor::SeekType::Current:
m_pos += offset;
}
CalculateTscRange();
return HasValue();
}
bool TraceCursorIntelPT::HasValue() const {
return m_pos >= 0 && m_pos < m_decoded_thread_sp->GetItemsCount();
}
lldb::TraceItemKind TraceCursorIntelPT::GetItemKind() const {
return m_decoded_thread_sp->GetItemKindByIndex(m_pos);
}
const char *TraceCursorIntelPT::GetError() const {
return m_decoded_thread_sp->GetErrorByIndex(m_pos);
}
lldb::addr_t TraceCursorIntelPT::GetLoadAddress() const {
return m_decoded_thread_sp->GetInstructionLoadAddress(m_pos);
}
Optional<uint64_t>
TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) const {
switch (counter_type) {
case lldb::eTraceCounterTSC:
if (m_tsc_range)
return m_tsc_range->GetTsc();
else
return llvm::None;
}
}
Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
return m_decoded_thread_sp->GetCPUByIndex(m_pos);
}
lldb::TraceEvent TraceCursorIntelPT::GetEventType() const {
return m_decoded_thread_sp->GetEventByIndex(m_pos);
}
bool TraceCursorIntelPT::GoToId(user_id_t id) {
if (!HasId(id))
return false;
m_pos = id;
m_tsc_range = m_decoded_thread_sp->CalculateTscRange(m_pos, m_tsc_range);
return true;
}
bool TraceCursorIntelPT::HasId(lldb::user_id_t id) const {
return static_cast<int64_t>(id) < m_decoded_thread_sp->GetItemsCount();
}
user_id_t TraceCursorIntelPT::GetId() const { return m_pos; }