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

Update memory calc function


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
@@ -120,7 +120,7 @@
   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);
+           (mem_used - *raw_size) / 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;
+  /// Current instruction timestamp.
+  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,16 @@
 
   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)) {
+      if (m_pos > m_current_tsc->GetEnd())
+        m_current_tsc = m_current_tsc->Next();
+      if (m_pos < m_current_tsc->GetStart())
+        m_current_tsc = m_current_tsc->Prev();
+    }
+
     if (!m_ignore_errors && IsError())
       return true;
     if (GetInstructionControlFlowType() & m_granularity)
@@ -61,20 +72,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 +99,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) {
+  if (!m_current_tsc)
+    return None;
+
   switch (counter_type) {
-    case lldb::eTraceCounterTSC:
-      return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter();
+  case lldb::eTraceCounterTSC:
+    return m_current_tsc->GetTsc();
   }
 }
 
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;
 };
 
@@ -131,6 +120,15 @@
   /// 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 +138,71 @@
   ///   The instructions of the trace.
   llvm::ArrayRef<IntelPTInstruction> GetInstructions() const;
 
+  /// \class TscRange
+  /// Class that represents the instruction 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 we can use to
+  /// speed up TSC lookups.
+  class TscRange {
+  public:
+    // Check if current TSC range covers 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_tsc = r.m_tsc;
+      m_start_index = r.m_start_index;
+      m_end_index = r.m_end_index;
+      return *this;
+    }
+
+  private:
+    friend class DecodedThread;
+
+    // Construct TscRange respecting bounds of timestamp map in thread
+    TscRange(std::map<size_t, uint64_t>::const_iterator it,
+             const DecodedThread &decoded_thread);
+
+    std::map<size_t, uint64_t>::const_iterator m_it;
+    const DecodedThread &m_decoded_thread;
+
+    /// The TSC value
+    uint64_t m_tsc;
+    /// The smallest instruction index that has this TSC.
+    size_t m_start_index;
+    /// The largest instruction index that has this TSC.
+    size_t m_end_index;
+  };
+
+  /// Construct a TSC range of an instruction by its 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 +226,22 @@
   /// 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 might be empty
+  /// if the trace doesn't contain TSCs. 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 it as ranges.
+  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;
+  // 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,18 +107,35 @@
   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 {
+  if (m_instruction_timestamps.empty())
+    return None;
+
+  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;
 
   return it->second.c_str();
 }
 
-DecodedThread::DecodedThread(ThreadSP thread_sp) : m_thread_sp(thread_sp) {}
+DecodedThread::DecodedThread(ThreadSP thread_sp)
+    : m_thread_sp(thread_sp), m_last_tsc(None) {}
 
 DecodedThread::DecodedThread(ThreadSP thread_sp, Error &&error)
-    : m_thread_sp(thread_sp) {
+    : m_thread_sp(thread_sp), m_last_tsc(None) {
   AppendError(std::move(error));
 }
 
@@ -129,3 +154,40 @@
          IntelPTInstruction::GetMemoryUsage() * m_instructions.size() +
          m_errors.getMemorySize();
 }
+
+DecodedThread::TscRange::TscRange(std::map<size_t, uint64_t>::const_iterator it,
+                                  const DecodedThread &ref)
+    : m_it(it), m_decoded_thread(ref) {
+  m_start_index = it->first;
+  m_tsc = it->second;
+
+  auto end = m_decoded_thread.m_instruction_timestamps.end();
+  if (it != end)
+    m_end_index = (++it--)->first - 1;
+  else
+    m_end_index = end->first;
+}
+
+size_t DecodedThread::TscRange::GetTsc() const { return m_tsc; }
+
+size_t DecodedThread::TscRange::GetStart() const { return m_start_index; }
+
+size_t DecodedThread::TscRange::GetEnd() const { return m_end_index; }
+
+bool DecodedThread::TscRange::InRange(size_t insn_index) {
+  if (insn_index < m_end_index && insn_index > m_start_index)
+    return true;
+  return false;
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Next() {
+  if (m_it == m_decoded_thread.m_instruction_timestamps.end())
+    return None;
+  return TscRange(++m_it, m_decoded_thread);
+}
+
+Optional<DecodedThread::TscRange> DecodedThread::TscRange::Prev() {
+  if (m_it == m_decoded_thread.m_instruction_timestamps.end())
+    return None;
+  return TscRange(--m_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