zrthxn updated this revision to Diff 419348.
zrthxn added a comment.

Change tsc check anyway


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D122603/new/

https://reviews.llvm.org/D122603

Files:
  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/Trace/intel-pt/TraceIntelPT.cpp

Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -119,8 +119,9 @@
   s.Printf("  Total number of instructions: %zu\n", insn_len);
   s.Printf("  Total approximate memory usage: %0.2lf KiB\n",
            (double)mem_used / 1024);
-  s.Printf("  Average memory usage per instruction: %zu bytes\n",
-           mem_used / insn_len);
+  if (insn_len != 0)
+    s.Printf("  Average memory usage per instruction: %zu bytes\n",
+             mem_used / insn_len);
   return;
 }
 
Index: lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
@@ -42,6 +42,8 @@
   DecodedThreadSP m_decoded_thread_sp;
   /// Internal instruction index currently pointing at.
   size_t m_pos;
+  /// Tsc range covering the current instruction.
+  llvm::Optional<DecodedThread::TscRange> m_current_tsc;
 };
 
 } // namespace trace_intel_pt
Index: lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
@@ -23,6 +23,7 @@
   assert(!m_decoded_thread_sp->GetInstructions().empty() &&
          "a trace should have at least one instruction or error");
   m_pos = m_decoded_thread_sp->GetInstructions().size() - 1;
+  m_current_tsc = m_decoded_thread_sp->CalculateTscRange(m_pos);
 }
 
 size_t TraceCursorIntelPT::GetInternalInstructionSize() {
@@ -40,6 +41,13 @@
 
   while (canMoveOne()) {
     m_pos += IsForwards() ? 1 : -1;
+
+    if (!m_current_tsc)
+      m_current_tsc = m_decoded_thread_sp->CalculateTscRange(m_pos);
+    else if (!m_current_tsc->InRange(m_pos))
+      m_current_tsc =
+          IsForwards() ? m_current_tsc->Next() : m_current_tsc->Prev();
+
     if (!m_ignore_errors && IsError())
       return true;
     if (GetInstructionControlFlowType() & m_granularity)
@@ -61,20 +69,23 @@
   switch (origin) {
   case TraceCursor::SeekType::Set:
     m_pos = fitPosToBounds(offset);
+    m_current_tsc = m_decoded_thread_sp->CalculateTscRange(m_pos);
     return m_pos;
   case TraceCursor::SeekType::End:
     m_pos = fitPosToBounds(offset + last_index);
+    m_current_tsc = m_decoded_thread_sp->CalculateTscRange(last_index - m_pos);
     return last_index - m_pos;
   case TraceCursor::SeekType::Current:
     int64_t new_pos = fitPosToBounds(offset + m_pos);
     int64_t dist = m_pos - new_pos;
     m_pos = new_pos;
+    m_current_tsc = m_decoded_thread_sp->CalculateTscRange(m_pos);
     return std::abs(dist);
   }
 }
 
 bool TraceCursorIntelPT::IsError() {
-  return m_decoded_thread_sp->GetInstructions()[m_pos].IsError();
+  return m_decoded_thread_sp->IsInstructionAnError(m_pos);
 }
 
 const char *TraceCursorIntelPT::GetError() {
@@ -85,10 +96,14 @@
   return m_decoded_thread_sp->GetInstructions()[m_pos].GetLoadAddress();
 }
 
-Optional<uint64_t> TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) {
+Optional<uint64_t>
+TraceCursorIntelPT::GetCounter(lldb::TraceCounter counter_type) {
   switch (counter_type) {
-    case lldb::eTraceCounterTSC:
-      return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter();
+  case lldb::eTraceCounterTSC:
+    if (m_current_tsc)
+      return m_current_tsc->GetTsc();
+    else
+      return llvm::None;
   }
 }
 
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
@@ -62,9 +62,6 @@
 /// As mentioned, any gap is represented as an error in this class.
 class IntelPTInstruction {
 public:
-  IntelPTInstruction(const pt_insn &pt_insn, uint64_t timestamp)
-      : m_pt_insn(pt_insn), m_timestamp(timestamp), m_is_error(false) {}
-
   IntelPTInstruction(const pt_insn &pt_insn)
       : m_pt_insn(pt_insn), m_is_error(false) {}
 
@@ -85,13 +82,6 @@
   /// Get the size in bytes of an instance of this class
   static size_t GetMemoryUsage();
 
-  /// Get the timestamp associated with the current instruction. The timestamp
-  /// is similar to what a rdtsc instruction would return.
-  ///
-  /// \return
-  ///     The timestamp or \b llvm::None if not available.
-  llvm::Optional<uint64_t> GetTimestampCounter() const;
-
   /// Get the \a lldb::TraceInstructionControlFlowType categories of the
   /// instruction.
   ///
@@ -113,7 +103,6 @@
   // When adding new members to this class, make sure to update
   // IntelPTInstruction::GetNonErrorMemoryUsage() if needed.
   pt_insn m_pt_insn;
-  llvm::Optional<uint64_t> m_timestamp;
   bool m_is_error;
 };
 
@@ -126,11 +115,66 @@
 /// stopped at. See \a Trace::GetCursorPosition for more information.
 class DecodedThread : public std::enable_shared_from_this<DecodedThread> {
 public:
+  /// \class TscRange
+  /// Class that represents the trace range associated with a given TSC.
+  /// It provides efficient iteration to the previous or next TSC range in the
+  /// decoded trace.
+  ///
+  /// TSC timestamps are emitted by the decoder infrequently, which means
+  /// that each TSC covers a range of instruction indices, which can be used to
+  /// speed up TSC lookups.
+  class TscRange {
+  public:
+    /// Check if this TSC range includes the given instruction index.
+    bool InRange(size_t insn_index);
+
+    /// Get the next range chronologically.
+    llvm::Optional<TscRange> Next();
+
+    /// Get the previous range chronologically.
+    llvm::Optional<TscRange> Prev();
+
+    /// Get the TSC value.
+    size_t GetTsc() const;
+    /// Get the smallest instruction index that has this TSC.
+    size_t GetStart() const;
+    /// Get the largest instruction index that has this TSC.
+    size_t GetEnd() const;
+
+    TscRange &operator=(const TscRange &r) {
+      m_it = r.m_it;
+      m_end_index = r.m_end_index;
+      return *this;
+    }
+
+  private:
+    friend class DecodedThread;
+
+    TscRange(std::map<size_t, uint64_t>::const_iterator it,
+             const DecodedThread &decoded_thread);
+
+    /// The current range
+    std::map<size_t, uint64_t>::const_iterator m_it;
+    /// The largest instruction index that has this TSC.
+    size_t m_end_index;
+
+    const DecodedThread &m_decoded_thread;
+  };
+
   DecodedThread(lldb::ThreadSP thread_sp);
 
   /// Utility constructor that initializes the trace with a provided error.
   DecodedThread(lldb::ThreadSP thread_sp, llvm::Error &&err);
 
+  /// Append a successfully decoded instruction.
+  void AppendInstruction(const pt_insn &instruction);
+
+  /// Append a sucessfully decoded instruction with an associated TSC timestamp.
+  void AppendInstruction(const pt_insn &instruction, uint64_t tsc);
+
+  /// Append a decoding error (i.e. an instruction that failed to be decoded).
+  void AppendError(llvm::Error &&error);
+
   /// Get the instructions from the decoded trace. Some of them might indicate
   /// errors (i.e. gaps) in the trace. For an instruction error, you can access
   /// its underlying error message with the \a GetErrorByInstructionIndex()
@@ -140,20 +184,19 @@
   ///   The instructions of the trace.
   llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
 
+  /// Construct the TSC range that covers the given instruction index.
+  /// This operation is O(logn) and should be used sparingly.
+  llvm::Optional<TscRange> CalculateTscRange(size_t insn_index) const;
+
+  /// Check if an instruction given by its index is an error.
+  bool IsInstructionAnError(size_t insn_idx) const;
+
   /// Get the error associated with a given instruction index.
   ///
   /// \return
   ///   The error message of \b nullptr if the given index
   ///   points to a valid instruction.
-  const char *GetErrorByInstructionIndex(uint64_t ins_idx);
-
-  /// Append a successfully decoded instruction.
-  template <typename... Ts> void AppendInstruction(Ts... instruction_args) {
-    m_instructions.emplace_back(instruction_args...);
-  }
-
-  /// Append a decoding error (i.e. an instruction that failed to be decoded).
-  void AppendError(llvm::Error &&error);
+  const char *GetErrorByInstructionIndex(size_t ins_idx);
 
   /// Get a new cursor for the decoded thread.
   lldb::TraceCursorUP GetCursor();
@@ -177,8 +220,23 @@
   /// When adding new members to this class, make sure
   /// to update \a CalculateApproximateMemoryUsage() accordingly.
   lldb::ThreadSP m_thread_sp;
+  /// The low level storage of all instruction addresses. Each instruction has
+  /// an index in this vector and it will be used in other parts of the code.
   std::vector<IntelPTInstruction> m_instructions;
+  /// This map contains the TSCs of the decoded instructions. It maps
+  /// `instruction index -> TSC`, where `instruction index` is the first index
+  /// at which the mapped TSC appears. We use this representation because TSCs
+  /// are sporadic and we can think of them as ranges. If TSCs are present in
+  /// the trace, all instructions will have an associated TSC, including the
+  /// first one. Otherwise, this map will be empty.
+  std::map<size_t, uint64_t> m_instruction_timestamps;
+  /// This is the chronologically last TSC that has been added.
+  llvm::Optional<uint64_t> m_last_tsc = llvm::None;
+  // This variables stores the messages of all the error instructions in the
+  // trace. It maps `instruction index -> error message`.
   llvm::DenseMap<uint64_t, std::string> m_errors;
+  /// The size in bytes of the raw buffer before decoding. It might be None if
+  /// the decoding failed.
   llvm::Optional<size_t> m_raw_trace_size;
 };
 
Index: lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
+++ lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
@@ -49,10 +49,6 @@
   return sizeof(IntelPTInstruction);
 }
 
-Optional<uint64_t> IntelPTInstruction::GetTimestampCounter() const {
-  return m_timestamp;
-}
-
 Optional<size_t> DecodedThread::GetRawTraceSize() const {
   return m_raw_trace_size;
 }
@@ -90,6 +86,18 @@
 
 ThreadSP DecodedThread::GetThread() { return m_thread_sp; }
 
+void DecodedThread::AppendInstruction(const pt_insn &insn) {
+  m_instructions.emplace_back(insn);
+}
+
+void DecodedThread::AppendInstruction(const pt_insn &insn, uint64_t tsc) {
+  m_instructions.emplace_back(insn);
+  if (!m_last_tsc || *m_last_tsc != tsc) {
+    m_instruction_timestamps.emplace(m_instructions.size() - 1, tsc);
+    m_last_tsc = tsc;
+  }
+}
+
 void DecodedThread::AppendError(llvm::Error &&error) {
   m_errors.try_emplace(m_instructions.size(), toString(std::move(error)));
   m_instructions.emplace_back();
@@ -99,8 +107,21 @@
   return makeArrayRef(m_instructions);
 }
 
-const char *DecodedThread::GetErrorByInstructionIndex(uint64_t idx) {
-  auto it = m_errors.find(idx);
+Optional<DecodedThread::TscRange>
+DecodedThread::CalculateTscRange(size_t insn_index) const {
+  auto it = m_instruction_timestamps.upper_bound(insn_index);
+  if (it == m_instruction_timestamps.begin())
+    return None;
+
+  return TscRange(--it, *this);
+}
+
+bool DecodedThread::IsInstructionAnError(size_t insn_idx) const {
+  return m_instructions[insn_idx].IsError();
+}
+
+const char *DecodedThread::GetErrorByInstructionIndex(size_t insn_idx) {
+  auto it = m_errors.find(insn_idx);
   if (it == m_errors.end())
     return nullptr;
 
@@ -125,7 +146,42 @@
 }
 
 size_t DecodedThread::CalculateApproximateMemoryUsage() const {
-  return m_raw_trace_size.getValueOr(0) +
-         IntelPTInstruction::GetMemoryUsage() * m_instructions.size() +
+  return IntelPTInstruction::GetMemoryUsage() * m_instructions.size() +
          m_errors.getMemorySize();
 }
+
+DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
+                                  const DecodedThread &decoded_thread)
+    : m_it(it), m_decoded_thread(decoded_thread) {
+  auto next_it = m_it;
+  ++next_it;
+  m_end_index = (next_it == m_decoded_thread.m_instruction_timestamps.end())
+                    ? m_decoded_thread.GetInstructions().size() - 1
+                    : next_it->first - 1;
+}
+
+size_t DecodedThread::TscRange::GetTsc() const { return m_it->second; }
+
+size_t DecodedThread::TscRange::GetStart() const { return m_it->first; }
+
+size_t DecodedThread::TscRange::GetEnd() const { return m_end_index; }
+
+bool DecodedThread::TscRange::InRange(size_t insn_index) {
+  return GetStart() <= insn_index && insn_index <= m_end_index;
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() {
+  auto next_it = m_it;
+  ++next_it;
+  if (next_it == m_decoded_thread.m_instruction_timestamps.end())
+    return None;
+  return TscRange(next_it, m_decoded_thread);
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() {
+  if (m_it == m_decoded_thread.m_instruction_timestamps.begin())
+    return None;
+  auto prev_it = m_it;
+  --prev_it;
+  return TscRange(prev_it, m_decoded_thread);
+}
\ No newline at end of file
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to