[Lldb-commits] [lldb] f9b4ea0 - [trace] Add SBTraceCursor bindings
Jakob Johnson via lldb-commits
lldb-commits at lists.llvm.org
Tue Aug 2 16:55:43 PDT 2022
Author: Jakob Johnson
Date: 2022-08-02T16:55:33-07:00
New Revision: f9b4ea0ce9efb4132a75551c40b2efc049e5b9f7
URL: https://github.com/llvm/llvm-project/commit/f9b4ea0ce9efb4132a75551c40b2efc049e5b9f7
DIFF: https://github.com/llvm/llvm-project/commit/f9b4ea0ce9efb4132a75551c40b2efc049e5b9f7.diff
LOG: [trace] Add SBTraceCursor bindings
Add bindings for the `TraceCursor` to allow for programatic traversal of
traces.
This diff adds bindings for all public `TraceCursor` methods except
`GetHwClock` and also adds `SBTrace::CreateNewCursor`. A new unittest
has been added to TestTraceLoad.py that uses the new `SBTraceCursor` API
to test that the sequential and random access APIs of the `TraceCursor`
are equivalent.
This diff depends on D130925.
Test Plan:
`ninja lldb-dotest && ./bin/lldb-dotest -p TestTraceLoad`
Differential Revision: https://reviews.llvm.org/D130930
Added:
lldb/bindings/interface/SBTraceCursor.i
lldb/include/lldb/API/SBTraceCursor.h
lldb/source/API/SBTraceCursor.cpp
Modified:
lldb/bindings/interface/SBTrace.i
lldb/bindings/interfaces.swig
lldb/include/lldb/API/SBDefines.h
lldb/include/lldb/API/SBTrace.h
lldb/include/lldb/Target/TraceCursor.h
lldb/include/lldb/lldb-defines.h
lldb/include/lldb/lldb-enumerations.h
lldb/source/API/CMakeLists.txt
lldb/source/API/SBTrace.cpp
lldb/source/Commands/CommandObjectThread.cpp
lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
lldb/source/Target/TraceDumper.cpp
lldb/test/API/commands/trace/TestTraceLoad.py
Removed:
################################################################################
diff --git a/lldb/bindings/interface/SBTrace.i b/lldb/bindings/interface/SBTrace.i
index 0d74881a3f3d8..e947572c0f848 100644
--- a/lldb/bindings/interface/SBTrace.i
+++ b/lldb/bindings/interface/SBTrace.i
@@ -15,6 +15,8 @@ class LLDB_API SBTrace {
public:
SBTrace();
+ SBTraceCursor CreateNewCursor(SBError &error, SBThread &thread);
+
const char *GetStartConfigurationHelp();
SBFileSpec SaveToDisk(SBError &error, const SBFileSpec &bundle_dir, bool compact = false);
diff --git a/lldb/bindings/interface/SBTraceCursor.i b/lldb/bindings/interface/SBTraceCursor.i
new file mode 100644
index 0000000000000..c1c73de311031
--- /dev/null
+++ b/lldb/bindings/interface/SBTraceCursor.i
@@ -0,0 +1,58 @@
+//===-- SWIG Interface for SBTraceCursor.h ----------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+namespace lldb {
+
+%feature("docstring",
+"Represents a trace cursor."
+) SBTrace;
+class LLDB_API SBTraceCursor {
+public:
+ SBTraceCursor();
+
+ SBTraceCursor(lldb::TraceCursorSP trace_cursor_sp);
+
+ void SetForwards(bool forwards);
+
+ bool IsForwards() const;
+
+ void Next();
+
+ bool HasValue();
+
+ bool GoToId(lldb::user_id_t id);
+
+ bool HasId(lldb::user_id_t id) const;
+
+ lldb::user_id_t GetId() const;
+
+ bool Seek(int64_t offset, lldb::TraceCursorSeekType origin);
+
+ lldb::TraceItemKind GetItemKind() const;
+
+ bool IsError() const;
+
+ const char *GetError() const;
+
+ bool IsEvent() const;
+
+ lldb::TraceEvent GetEventType() const;
+
+ const char *GetEventTypeAsString() const;
+
+ bool IsInstruction() const;
+
+ lldb::addr_t GetLoadAddress() const;
+
+ lldb::cpu_id_t GetCPU() const;
+
+ bool IsValid() const;
+
+ explicit operator bool() const;
+};
+} // namespace lldb
diff --git a/lldb/bindings/interfaces.swig b/lldb/bindings/interfaces.swig
index c9a6d0f060568..fb75513a0df1b 100644
--- a/lldb/bindings/interfaces.swig
+++ b/lldb/bindings/interfaces.swig
@@ -69,6 +69,7 @@
%include "./interface/SBThreadCollection.i"
%include "./interface/SBThreadPlan.i"
%include "./interface/SBTrace.i"
+%include "./interface/SBTraceCursor.i"
%include "./interface/SBType.i"
%include "./interface/SBTypeCategory.i"
%include "./interface/SBTypeEnumMember.i"
diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h
index ecf1dc34d8c58..6833c0542c168 100644
--- a/lldb/include/lldb/API/SBDefines.h
+++ b/lldb/include/lldb/API/SBDefines.h
@@ -88,6 +88,7 @@ class LLDB_API SBThread;
class LLDB_API SBThreadCollection;
class LLDB_API SBThreadPlan;
class LLDB_API SBTrace;
+class LLDB_API SBTraceCursor;
class LLDB_API SBType;
class LLDB_API SBTypeCategory;
class LLDB_API SBTypeEnumMember;
diff --git a/lldb/include/lldb/API/SBTrace.h b/lldb/include/lldb/API/SBTrace.h
index 19d759013955c..7929d217ef268 100644
--- a/lldb/include/lldb/API/SBTrace.h
+++ b/lldb/include/lldb/API/SBTrace.h
@@ -11,6 +11,7 @@
#include "lldb/API/SBDefines.h"
#include "lldb/API/SBError.h"
+#include "lldb/API/SBTraceCursor.h"
namespace lldb {
@@ -25,6 +26,20 @@ class LLDB_API SBTrace {
static SBTrace LoadTraceFromFile(SBError &error, SBDebugger &debugger,
const SBFileSpec &trace_description_file);
+ /// Get a \a TraceCursor for the given thread's trace.
+ ///
+ /// \param[out] error
+ /// This will be set with an error in case of failures.
+ //
+ /// \param[in] thread
+ /// The thread to get a \a TraceCursor for.
+ //
+ /// \return
+ /// A \a SBTraceCursor. If the thread is not traced or its trace
+ /// information failed to load, an invalid \a SBTraceCursor is returned
+ /// and the \p error parameter is set.
+ SBTraceCursor CreateNewCursor(SBError &error, SBThread &thread);
+
/// Save the trace to the specified directory, which will be created if
/// needed. This will also create a a file \a <directory>/trace.json with the
/// main properties of the trace session, along with others files which
diff --git a/lldb/include/lldb/API/SBTraceCursor.h b/lldb/include/lldb/API/SBTraceCursor.h
new file mode 100644
index 0000000000000..ce6dfa3169f35
--- /dev/null
+++ b/lldb/include/lldb/API/SBTraceCursor.h
@@ -0,0 +1,182 @@
+//===-- SBTraceCursor.h -----------------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_API_SBTRACECURSOR_H
+#define LLDB_API_SBTRACECURSOR_H
+
+#include "lldb/API/SBDefines.h"
+#include "lldb/API/SBError.h"
+#include "lldb/API/SBExecutionContext.h"
+#include "lldb/Target/TraceCursor.h"
+
+namespace lldb {
+
+class LLDB_API SBTraceCursor {
+public:
+ /// Default constructor for an invalid \a SBTraceCursor object.
+ SBTraceCursor();
+
+ /// Create a cursor that initially points to the end of the trace, i.e. the
+ /// most recent item.
+ SBTraceCursor(lldb::TraceCursorSP trace_cursor_sp);
+
+ /// Set the direction to use in the \a SBTraceCursor::Next() method.
+ ///
+ /// \param[in] forwards
+ /// If \b true, then the traversal will be forwards, otherwise backwards.
+ void SetForwards(bool forwards);
+
+ /// Check if the direction to use in the \a SBTraceCursor::Next() method is
+ /// forwards.
+ ///
+ /// \return
+ /// \b true if the current direction is forwards, \b false if backwards.
+ bool IsForwards() const;
+
+ /// Move the cursor to the next item (instruction or error).
+ ///
+ /// Direction:
+ /// The traversal is done following the current direction of the trace. If
+ /// it is forwards, the instructions are visited forwards
+ /// chronologically. Otherwise, the traversal is done in
+ /// the opposite direction. By default, a cursor moves backwards unless
+ /// changed with \a SBTraceCursor::SetForwards().
+ void Next();
+
+ /// \return
+ /// \b true if the cursor is pointing to a valid item. \b false if the
+ /// cursor has reached the end of the trace.
+ bool HasValue() const;
+
+ /// Instruction identifiers:
+ ///
+ /// When building complex higher level tools, fast random accesses in the
+ /// trace might be needed, for which each instruction requires a unique
+ /// identifier within its thread trace. For example, a tool might want to
+ /// repeatedly inspect random consecutive portions of a trace. This means that
+ /// it will need to first move quickly to the beginning of each section and
+ /// then start its iteration. Given that the number of instructions can be in
+ /// the order of hundreds of millions, fast random access is necessary.
+ ///
+ /// An example of such a tool could be an inspector of the call graph of a
+ /// trace, where each call is represented with its start and end instructions.
+ /// Inspecting all the instructions of a call requires moving to its first
+ /// instruction and then iterating until the last instruction, which following
+ /// the pattern explained above.
+ ///
+ /// Instead of using 0-based indices as identifiers, each Trace plug-in can
+ /// decide the nature of these identifiers and thus no assumptions can be made
+ /// regarding their ordering and sequentiality. The reason is that an
+ /// instruction might be encoded by the plug-in in a way that hides its actual
+ /// 0-based index in the trace, but it's still possible to efficiently find
+ /// it.
+ ///
+ /// Requirements:
+ /// - For a given thread, no two instructions have the same id.
+ /// - In terms of efficiency, moving the cursor to a given id should be as
+ /// fast as possible, but not necessarily O(1). That's why the recommended
+ /// way to traverse sequential instructions is to use the \a
+ /// SBTraceCursor::Next() method and only use \a SBTraceCursor::GoToId(id)
+ /// sparingly.
+
+ /// Make the cursor point to the item whose identifier is \p id.
+ ///
+ /// \return
+ /// \b true if the given identifier exists and the cursor effectively
+ /// moved to it. Otherwise, \b false is returned and the cursor now points
+ /// to an invalid item, i.e. calling \a HasValue() will return \b false.
+ bool GoToId(lldb::user_id_t id);
+
+ /// \return
+ /// \b true if and only if there's an instruction item with the given \p
+ /// id.
+ bool HasId(lldb::user_id_t id) const;
+
+ /// \return
+ /// A unique identifier for the instruction or error this cursor is
+ /// pointing to.
+ lldb::user_id_t GetId() const;
+ /// \}
+
+ /// Make the cursor point to an item in the trace based on an origin point and
+ /// an offset.
+ ///
+ /// The resulting position of the trace is
+ /// origin + offset
+ ///
+ /// If this resulting position would be out of bounds, the trace then points
+ /// to an invalid item, i.e. calling \a HasValue() returns \b false.
+ ///
+ /// \param[in] offset
+ /// How many items to move forwards (if positive) or backwards (if
+ /// negative) from the given origin point. For example, if origin is \b
+ /// End, then a negative offset would move backward in the trace, but a
+ /// positive offset would move past the trace to an invalid item.
+ ///
+ /// \param[in] origin
+ /// The reference point to use when moving the cursor.
+ ///
+ /// \return
+ /// \b true if and only if the cursor ends up pointing to a valid item.
+ bool Seek(int64_t offset, lldb::TraceCursorSeekType origin);
+
+ /// \return
+ /// The \a ExecutionContextRef of the backing thread from the creation time
+ /// of this cursor.
+ SBExecutionContext &GetExecutionContextRef();
+
+ /// Trace item information (instructions, errors and events)
+ /// \{
+
+ /// \return
+ /// The kind of item the cursor is pointing at.
+ lldb::TraceItemKind GetItemKind() const;
+
+ /// \return
+ /// Whether the cursor points to an error or not.
+ bool IsError() const;
+
+ /// \return
+ /// The error message the cursor is pointing at.
+ const char *GetError() const;
+
+ /// \return
+ /// Whether the cursor points to an event or not.
+ bool IsEvent() const;
+
+ /// \return
+ /// The specific kind of event the cursor is pointing at.
+ lldb::TraceEvent GetEventType() const;
+
+ /// \return
+ /// A human-readable description of the event this cursor is pointing at.
+ const char *GetEventTypeAsString() const;
+
+ /// \return
+ /// Whether the cursor points to an instruction.
+ bool IsInstruction() const;
+
+ /// \return
+ /// The load address of the instruction the cursor is pointing at.
+ lldb::addr_t GetLoadAddress() const;
+
+ /// \return
+ /// The requested CPU id, or LLDB_INVALID_CPU_ID if this information is
+ /// not available for the current item.
+ lldb::cpu_id_t GetCPU() const;
+
+ bool IsValid() const;
+
+ explicit operator bool() const;
+
+protected:
+ lldb::TraceCursorSP m_opaque_sp;
+};
+} // namespace lldb
+
+#endif // LLDB_API_SBTRACECURSOR_H
diff --git a/lldb/include/lldb/Target/TraceCursor.h b/lldb/include/lldb/Target/TraceCursor.h
index 4e405aeaab7c6..63278f315a2d0 100644
--- a/lldb/include/lldb/Target/TraceCursor.h
+++ b/lldb/include/lldb/Target/TraceCursor.h
@@ -92,18 +92,6 @@ namespace lldb_private {
/// You can read more in the documentation of these methods.
class TraceCursor {
public:
- /// Helper enum to indicate the reference point when invoking
- /// \a TraceCursor::Seek().
- /// The following values are inspired by \a std::istream::seekg.
- enum class SeekType {
- /// The beginning of the trace, i.e the oldest item.
- Beginning = 0,
- /// The current position in the trace.
- Current,
- /// The end of the trace, i.e the most recent item.
- End
- };
-
/// Create a cursor that initially points to the end of the trace, i.e. the
/// most recent item.
TraceCursor(lldb::ThreadSP thread_sp);
@@ -208,7 +196,7 @@ class TraceCursor {
///
/// \return
/// \b true if and only if the cursor ends up pointing to a valid item.
- virtual bool Seek(int64_t offset, SeekType origin) = 0;
+ virtual bool Seek(int64_t offset, lldb::TraceCursorSeekType origin) = 0;
/// \return
/// The \a ExecutionContextRef of the backing thread from the creation time
@@ -235,8 +223,7 @@ class TraceCursor {
bool IsEvent() const;
/// \return
- /// The specific kind of event the cursor is pointing at, or \b
- /// TraceEvent::eTraceEventNone if the cursor not pointing to an event.
+ /// The specific kind of event the cursor is pointing at.
virtual lldb::TraceEvent GetEventType() const = 0;
/// \return
@@ -261,9 +248,9 @@ class TraceCursor {
/// whenever an eTraceEventCPUChanged event is fired.
///
/// \return
- /// The requested CPU id, or \a llvm::None if this information is
+ /// The requested CPU id, or LLDB_INVALID_CPU_ID if this information is
/// not available for the current item.
- virtual llvm::Optional<lldb::cpu_id_t> GetCPU() const = 0;
+ virtual lldb::cpu_id_t GetCPU() const = 0;
/// Get the last hardware clock value that was emitted before the current
/// trace item.
diff --git a/lldb/include/lldb/lldb-defines.h b/lldb/include/lldb/lldb-defines.h
index ad1283bfd2299..3d23d697b5422 100644
--- a/lldb/include/lldb/lldb-defines.h
+++ b/lldb/include/lldb/lldb-defines.h
@@ -86,6 +86,7 @@
#define LLDB_INVALID_LINE_NUMBER UINT32_MAX
#define LLDB_INVALID_COLUMN_NUMBER 0
#define LLDB_INVALID_QUEUE_ID 0
+#define LLDB_INVALID_CPU_ID UINT32_MAX
/// CPU Type definitions
#define LLDB_ARCH_DEFAULT "systemArch"
diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h
index 2566a43daac87..3b0005c1f0a49 100644
--- a/lldb/include/lldb/lldb-enumerations.h
+++ b/lldb/include/lldb/lldb-enumerations.h
@@ -1179,6 +1179,19 @@ enum TraceItemKind {
eTraceItemKindInstruction,
};
+/// Enum to indicate the reference point when invoking
+/// \a TraceCursor::Seek().
+/// The following values are inspired by \a std::istream::seekg.
+enum TraceCursorSeekType {
+ /// The beginning of the trace, i.e the oldest item.
+ eTraceCursorSeekTypeBeginning = 0,
+ /// The current position in the trace.
+ eTraceCursorSeekTypeCurrent,
+ /// The end of the trace, i.e the most recent item.
+ eTraceCursorSeekTypeEnd
+};
+
+
} // namespace lldb
#endif // LLDB_LLDB_ENUMERATIONS_H
diff --git a/lldb/source/API/CMakeLists.txt b/lldb/source/API/CMakeLists.txt
index 46307b487a547..dd73ba56afef7 100644
--- a/lldb/source/API/CMakeLists.txt
+++ b/lldb/source/API/CMakeLists.txt
@@ -72,6 +72,7 @@ add_lldb_library(liblldb SHARED ${option_framework}
SBThreadCollection.cpp
SBThreadPlan.cpp
SBTrace.cpp
+ SBTraceCursor.cpp
SBType.cpp
SBTypeCategory.cpp
SBTypeEnumMember.cpp
diff --git a/lldb/source/API/SBTrace.cpp b/lldb/source/API/SBTrace.cpp
index 2b1f140161b6d..5e9d53e3d1863 100644
--- a/lldb/source/API/SBTrace.cpp
+++ b/lldb/source/API/SBTrace.cpp
@@ -43,6 +43,27 @@ SBTrace SBTrace::LoadTraceFromFile(SBError &error, SBDebugger &debugger,
return SBTrace(trace_or_err.get());
}
+SBTraceCursor SBTrace::CreateNewCursor(SBError &error, SBThread &thread) {
+ LLDB_INSTRUMENT_VA(this, error, thread);
+
+ if (!m_opaque_sp) {
+ error.SetErrorString("error: invalid trace");
+ return SBTraceCursor();
+ }
+ if (!thread.get()) {
+ error.SetErrorString("error: invalid thread");
+ return SBTraceCursor();
+ }
+
+ if (llvm::Expected<lldb::TraceCursorSP> trace_cursor_sp =
+ m_opaque_sp->CreateNewCursor(*thread.get())) {
+ return SBTraceCursor(std::move(*trace_cursor_sp));
+ } else {
+ error.SetErrorString(llvm::toString(trace_cursor_sp.takeError()).c_str());
+ return SBTraceCursor();
+ }
+}
+
SBFileSpec SBTrace::SaveToDisk(SBError &error, const SBFileSpec &bundle_dir,
bool compact) {
LLDB_INSTRUMENT_VA(this, error, bundle_dir, compact);
diff --git a/lldb/source/API/SBTraceCursor.cpp b/lldb/source/API/SBTraceCursor.cpp
new file mode 100644
index 0000000000000..6a207d732aa4a
--- /dev/null
+++ b/lldb/source/API/SBTraceCursor.cpp
@@ -0,0 +1,120 @@
+//===-- SBTraceCursor.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 "lldb/API/SBTraceCursor.h"
+#include "Utils.h"
+#include "lldb/Utility/Instrumentation.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+SBTraceCursor::SBTraceCursor() { LLDB_INSTRUMENT_VA(this); }
+
+SBTraceCursor::SBTraceCursor(TraceCursorSP trace_cursor_sp)
+ : m_opaque_sp{std::move(trace_cursor_sp)} {
+ LLDB_INSTRUMENT_VA(this, trace_cursor_sp);
+}
+
+void SBTraceCursor::SetForwards(bool forwards) {
+ LLDB_INSTRUMENT_VA(this, forwards);
+ m_opaque_sp->SetForwards(forwards);
+}
+
+bool SBTraceCursor::IsForwards() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->IsForwards();
+}
+
+void SBTraceCursor::Next() {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->Next();
+}
+
+bool SBTraceCursor::HasValue() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->HasValue();
+}
+
+bool SBTraceCursor::GoToId(lldb::user_id_t id) {
+ LLDB_INSTRUMENT_VA(this, id);
+ return m_opaque_sp->GoToId(id);
+}
+
+bool SBTraceCursor::HasId(lldb::user_id_t id) const {
+ LLDB_INSTRUMENT_VA(this, id);
+ return m_opaque_sp->HasId(id);
+}
+
+lldb::user_id_t SBTraceCursor::GetId() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetId();
+}
+
+bool SBTraceCursor::Seek(int64_t offset, lldb::TraceCursorSeekType origin) {
+ LLDB_INSTRUMENT_VA(this, offset);
+
+ return m_opaque_sp->Seek(offset, origin);
+}
+
+lldb::TraceItemKind SBTraceCursor::GetItemKind() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetItemKind();
+}
+
+bool SBTraceCursor::IsError() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->IsError();
+}
+
+const char *SBTraceCursor::GetError() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetError();
+}
+
+bool SBTraceCursor::IsEvent() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->IsEvent();
+}
+
+lldb::TraceEvent SBTraceCursor::GetEventType() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetEventType();
+}
+
+const char *SBTraceCursor::GetEventTypeAsString() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetEventTypeAsString();
+}
+
+bool SBTraceCursor::IsInstruction() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->IsInstruction();
+}
+
+lldb::addr_t SBTraceCursor::GetLoadAddress() const {
+ LLDB_INSTRUMENT_VA(this);
+ return m_opaque_sp->GetLoadAddress();
+}
+
+lldb::cpu_id_t SBTraceCursor::GetCPU() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ return m_opaque_sp->GetCPU();
+}
+
+bool SBTraceCursor::IsValid() const {
+ LLDB_INSTRUMENT_VA(this);
+ return this->operator bool();
+}
+
+SBTraceCursor::operator bool() const {
+ LLDB_INSTRUMENT_VA(this);
+
+ return m_opaque_sp.get() != nullptr;
+}
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index 9aa128aaa288f..76457d14013ea 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -2295,7 +2295,7 @@ class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
// We need to stop processing data when we already ran out of instructions
// in a previous command. We can fake this by setting the cursor past the
// end of the trace.
- cursor_sp->Seek(1, TraceCursor::SeekType::End);
+ cursor_sp->Seek(1, lldb::eTraceCursorSeekTypeEnd);
}
TraceDumper dumper(std::move(cursor_sp),
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
index 02f1d2f24d8cf..312f721fd5cc2 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -151,12 +151,9 @@ void DecodedThread::NotifyCPU(lldb::cpu_id_t cpu_id) {
}
}
-Optional<lldb::cpu_id_t>
-DecodedThread::GetCPUByIndex(uint64_t item_index) const {
+lldb::cpu_id_t DecodedThread::GetCPUByIndex(uint64_t item_index) const {
auto it = m_cpus.upper_bound(item_index);
- if (it == m_cpus.begin())
- return None;
- return prev(it)->second;
+ return it == m_cpus.begin() ? LLDB_INVALID_CPU_ID : prev(it)->second;
}
Optional<DecodedThread::TSCRange>
diff --git a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
index 9376a0af169d1..00fb1363619e5 100644
--- a/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ b/lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -173,8 +173,8 @@ class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
/// The trace item index to compare with.
///
/// \return
- /// The requested cpu id, or \a llvm::None if not available.
- llvm::Optional<lldb::cpu_id_t> GetCPUByIndex(uint64_t item_index) const;
+ /// The requested cpu id, or \a LLDB_INVALID_CPU_ID if not available.
+ lldb::cpu_id_t GetCPUByIndex(uint64_t item_index) const;
/// Get a maximal range of trace items that include the given \p item_index
/// that have the same TSC value.
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
index a4d86fb48ebee..ed0f62e75a9cb 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -24,7 +24,7 @@ TraceCursorIntelPT::TraceCursorIntelPT(
: TraceCursor(thread_sp), m_decoded_thread_sp(decoded_thread_sp),
m_tsc_conversion(tsc_conversion),
m_beginning_of_time_nanos(beginning_of_time_nanos) {
- Seek(0, SeekType::End);
+ Seek(0, lldb::eTraceCursorSeekTypeEnd);
}
void TraceCursorIntelPT::Next() {
@@ -68,15 +68,16 @@ TraceCursorIntelPT::GetNanosecondsRange() const {
return m_nanoseconds_range;
}
-bool TraceCursorIntelPT::Seek(int64_t offset, SeekType origin) {
+bool TraceCursorIntelPT::Seek(int64_t offset,
+ lldb::TraceCursorSeekType origin) {
switch (origin) {
- case TraceCursor::SeekType::Beginning:
+ case lldb::eTraceCursorSeekTypeBeginning:
m_pos = offset;
break;
- case TraceCursor::SeekType::End:
+ case lldb::eTraceCursorSeekTypeEnd:
m_pos = m_decoded_thread_sp->GetItemsCount() - 1 + offset;
break;
- case TraceCursor::SeekType::Current:
+ case lldb::eTraceCursorSeekTypeCurrent:
m_pos += offset;
}
@@ -116,7 +117,7 @@ Optional<double> TraceCursorIntelPT::GetWallClockTime() const {
return None;
}
-Optional<lldb::cpu_id_t> TraceCursorIntelPT::GetCPU() const {
+lldb::cpu_id_t TraceCursorIntelPT::GetCPU() const {
return m_decoded_thread_sp->GetCPUByIndex(m_pos);
}
diff --git a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
index 3cd9ab831f5e7..2e002bbfd22c6 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -21,7 +21,7 @@ class TraceCursorIntelPT : public TraceCursor {
const llvm::Optional<LinuxPerfZeroTscConversion> &tsc_conversion,
llvm::Optional<uint64_t> beginning_of_time_nanos);
- bool Seek(int64_t offset, SeekType origin) override;
+ bool Seek(int64_t offset, lldb::TraceCursorSeekType origin) override;
void Next() override;
@@ -33,7 +33,7 @@ class TraceCursorIntelPT : public TraceCursor {
lldb::TraceEvent GetEventType() const override;
- llvm::Optional<lldb::cpu_id_t> GetCPU() const override;
+ lldb::cpu_id_t GetCPU() const override;
llvm::Optional<uint64_t> GetHWClock() const override;
diff --git a/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp b/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
index d8e44ee66de83..0444b4da91460 100644
--- a/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
+++ b/lldb/source/Plugins/TraceExporter/common/TraceHTR.cpp
@@ -130,7 +130,7 @@ TraceHTR::TraceHTR(Thread &thread, TraceCursor &cursor)
// Move cursor to the first instruction in the trace
cursor.SetForwards(true);
- cursor.Seek(0, TraceCursor::SeekType::Beginning);
+ cursor.Seek(0, lldb::eTraceCursorSeekTypeBeginning);
// TODO: fix after persona0220's patch on a new way to access instruction
// kinds
diff --git a/lldb/source/Target/TraceDumper.cpp b/lldb/source/Target/TraceDumper.cpp
index 74f6ea0ffa522..f25b5d5939d5b 100644
--- a/lldb/source/Target/TraceDumper.cpp
+++ b/lldb/source/Target/TraceDumper.cpp
@@ -304,14 +304,14 @@ TraceDumper::TraceDumper(lldb::TraceCursorSP cursor_sp, Stream &s,
if (m_options.id)
m_cursor_sp->GoToId(*m_options.id);
else if (m_options.forwards)
- m_cursor_sp->Seek(0, TraceCursor::SeekType::Beginning);
+ m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeBeginning);
else
- m_cursor_sp->Seek(0, TraceCursor::SeekType::End);
+ m_cursor_sp->Seek(0, lldb::eTraceCursorSeekTypeEnd);
m_cursor_sp->SetForwards(m_options.forwards);
if (m_options.skip) {
m_cursor_sp->Seek((m_options.forwards ? 1 : -1) * *m_options.skip,
- TraceCursor::SeekType::Current);
+ lldb::eTraceCursorSeekTypeCurrent);
}
}
diff --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py
index 3e5488a13d92f..9ce95171256df 100644
--- a/lldb/test/API/commands/trace/TestTraceLoad.py
+++ b/lldb/test/API/commands/trace/TestTraceLoad.py
@@ -264,3 +264,114 @@ def testLoadInvalidTraces(self):
expected_substrs = ['error: missing value at traceBundle.processes[1].pid']
self.traceLoad(traceDescriptionFilePath=trace_description_file_path, error=True, substrs=expected_substrs)
self.assertEqual(self.dbg.GetNumTargets(), 0)
+
+ def testLoadTraceCursor(self):
+ src_dir = self.getSourceDir()
+ trace_description_file_path = os.path.join(src_dir, "intelpt-multi-core-trace", "trace.json")
+ traceDescriptionFile = lldb.SBFileSpec(trace_description_file_path, True)
+
+ error = lldb.SBError()
+ trace = self.dbg.LoadTraceFromFile(error, traceDescriptionFile)
+ self.assertSBError(error)
+
+ target = self.dbg.GetSelectedTarget()
+ process = target.process
+
+
+ # 1. Test some expected items of thread 1's trace cursor.
+ thread1 = process.threads[1]
+ cursor = trace.CreateNewCursor(error, thread1)
+ self.assertTrue(cursor)
+ self.assertTrue(cursor.HasValue())
+ cursor.Seek(0, lldb.eTraceCursorSeekTypeBeginning)
+ cursor.SetForwards(True)
+
+ self.assertTrue(cursor.IsEvent())
+ self.assertEqual(cursor.GetEventTypeAsString(), "HW clock tick")
+ self.assertEqual(cursor.GetCPU(), lldb.LLDB_INVALID_CPU_ID)
+
+ cursor.Next()
+
+ self.assertTrue(cursor.IsEvent())
+ self.assertEqual(cursor.GetEventTypeAsString(), "CPU core changed")
+ self.assertEqual(cursor.GetCPU(), 51)
+
+ cursor.GoToId(19531)
+
+ self.assertTrue(cursor.IsError())
+ self.assertEqual(cursor.GetError(), "expected tracing enabled event")
+
+ cursor.GoToId(19523)
+
+ self.assertTrue(cursor.IsInstruction())
+ self.assertEqual(cursor.GetLoadAddress(), 4197287)
+
+
+
+ # Helper function to check equality of the current item of two trace cursors.
+ def assertCurrentTraceCursorItemEqual(lhs, rhs):
+ self.assertTrue(lhs.HasValue() and rhs.HasValue())
+
+ self.assertEqual(lhs.GetId(), rhs.GetId())
+ self.assertEqual(lhs.GetItemKind(), rhs.GetItemKind())
+ if lhs.IsError():
+ self.assertEqual(lhs.GetError(), rhs.GetError())
+ elif lhs.IsEvent():
+ self.assertEqual(lhs.GetEventType(), rhs.GetEventType())
+ self.assertEqual(lhs.GetEventTypeAsString(), rhs.GetEventTypeAsString())
+ elif lhs.IsInstruction():
+ self.assertEqual(lhs.GetLoadAddress(), rhs.GetLoadAddress())
+ else:
+ self.fail("Unknown trace item kind")
+
+ for thread in process.threads:
+ sequentialTraversalCursor = trace.CreateNewCursor(error, thread)
+ self.assertSBError(error)
+ # Skip threads with no trace items
+ if not sequentialTraversalCursor.HasValue():
+ continue
+
+ # 2. Test "End" boundary of the trace by advancing past the trace's last item.
+ sequentialTraversalCursor.Seek(0, lldb.eTraceCursorSeekTypeEnd)
+ self.assertTrue(sequentialTraversalCursor.HasValue())
+ sequentialTraversalCursor.SetForwards(True)
+ sequentialTraversalCursor.Next()
+ self.assertFalse(sequentialTraversalCursor.HasValue())
+
+
+
+ # 3. Test sequential traversal using sequential access API (ie Next())
+ # and random access API (ie GoToId()) simultaneously.
+ randomAccessCursor = trace.CreateNewCursor(error, thread)
+ self.assertSBError(error)
+ # Reset the sequential cursor
+ sequentialTraversalCursor.Seek(0, lldb.eTraceCursorSeekTypeBeginning)
+ sequentialTraversalCursor.SetForwards(True)
+ self.assertTrue(sequentialTraversalCursor.IsForwards())
+
+ while sequentialTraversalCursor.HasValue():
+ itemId = sequentialTraversalCursor.GetId()
+ randomAccessCursor.GoToId(itemId)
+ assertCurrentTraceCursorItemEqual(sequentialTraversalCursor, randomAccessCursor)
+ sequentialTraversalCursor.Next()
+
+
+
+ # 4. Test a random access with random access API (ie Seek()) and
+ # sequential access API (ie consecutive calls to Next()).
+ TEST_SEEK_ID = 3
+ randomAccessCursor.GoToId(TEST_SEEK_ID )
+ # Reset the sequential cursor
+ sequentialTraversalCursor.Seek(0, lldb.eTraceCursorSeekTypeBeginning)
+ sequentialTraversalCursor.SetForwards(True)
+ for _ in range(TEST_SEEK_ID): sequentialTraversalCursor.Next()
+ assertCurrentTraceCursorItemEqual(sequentialTraversalCursor, randomAccessCursor)
+
+
+
+
+
+
+
+
+
More information about the lldb-commits
mailing list