jj10306 created this revision.
jj10306 added reviewers: wallace, davidca.
jj10306 requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

Begin implementing Tsc to timestamp conversion for IntelPT traces:

- Add TscConverter and stub out first implementor (PerfTscConverter)
- Add tsc_converter to TraceIntelPT and update DoRefreshLiveProcess to 
accomodate different trace implementation's TraceGetState responses

This is a work in progress, creating diff now to get feedback on initial 
changes before proceeding with decoder and schema changes.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D120595

Files:
  lldb/docs/lldb-gdb-remote.txt
  lldb/include/lldb/Target/Trace.h
  lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
  lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
  lldb/source/Plugins/Process/Linux/IntelPTManager.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Target/Trace.cpp
  lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp

Index: lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
===================================================================
--- lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
+++ lldb/source/Utility/TraceIntelPTGDBRemotePackets.cpp
@@ -7,6 +7,7 @@
 //===----------------------------------------------------------------------===//
 
 #include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 
 using namespace llvm;
 using namespace llvm::json;
@@ -43,4 +44,55 @@
   return base;
 }
 
+uint64_t PerfTscConverter::TscToNanos(uint64_t tsc) {
+  // conversion logic here
+  return 1;
+}
+
+bool fromJSON(const llvm::json::Value &value, std::shared_ptr<TscConverter> &tsc_converter, llvm::json::Path path) {
+  std::string tsc_converter_kind;
+  ObjectMapper o(value, path);
+
+  bool ret = o.map("kind", tsc_converter_kind);
+
+  if (tsc_converter_kind == "perf") {
+    std::shared_ptr<PerfTscConverter> perf_tsc_converter_sp = std::make_shared<PerfTscConverter>(PerfTscConverter());
+    ret = ret && o.map("time_mult", perf_tsc_converter_sp->m_perf_conversion.m_time_mult) && o.map("time_shift", perf_tsc_converter_sp->m_perf_conversion.m_time_shift) && o.map("time_zero", perf_tsc_converter_sp->m_perf_conversion.m_time_zero);
+    // should we check ret here?
+    tsc_converter = perf_tsc_converter_sp;
+  } else if (tsc_converter_kind == "freq") {
+    // TODO
+    tsc_converter = nullptr;
+  } else {
+    tsc_converter = nullptr;
+  }
+  return ret;
+}
+
+bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet, Path path) {
+  ObjectMapper o(value, path);
+  bool base_bool = o && fromJSON(value, (TraceGetStateResponse &)packet, path) && o.map("tsc_conversion", packet.tsc_converter);
+  // call perftscconverter
+  // get an instance of perftscconverter and wrap it in optional<shared<
+  return base_bool;
+
+}
+
+llvm::json::Value PerfTscConverter::toJSON() {
+  return json::Value(json::Object{
+    {"kind", "perf"},
+    {"time_mult",m_perf_conversion.m_time_mult},
+    {"time_shift", m_perf_conversion.m_time_shift},
+    {"time_zero", m_perf_conversion.m_time_zero},
+  });
+}
+
+json::Value toJSON(const TraceIntelPTGetStateResponse &packet) {
+  json::Value base = toJSON((const TraceGetStateResponse &)packet);
+  if (packet.tsc_converter) {
+    json::Value tsc_converter_json = packet.tsc_converter->toJSON();
+    base.getAsObject()->try_emplace("tsc_conversion", std::move(tsc_converter_json));
+  }
+  return base;
+}
 } // namespace lldb_private
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -18,6 +18,7 @@
 #include "lldb/Target/SectionLoadList.h"
 #include "lldb/Target/Thread.h"
 #include "lldb/Utility/Stream.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 
 using namespace lldb;
 using namespace lldb_private;
@@ -187,28 +188,19 @@
   m_stop_id = new_stop_id;
   m_live_thread_data.clear();
 
-  Expected<std::string> json_string = GetLiveProcessState();
-  if (!json_string) {
-    DoRefreshLiveProcessState(json_string.takeError());
-    return;
-  }
-  Expected<TraceGetStateResponse> live_process_state =
-      json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse");
-  if (!live_process_state) {
-    DoRefreshLiveProcessState(live_process_state.takeError());
-    return;
-  }
+  std::unique_ptr<TraceGetStateResponse> live_process_state = DoRefreshLiveProcessState(GetLiveProcessState());
 
-  for (const TraceThreadState &thread_state :
-       live_process_state->tracedThreads) {
-    for (const TraceBinaryData &item : thread_state.binaryData)
-      m_live_thread_data[thread_state.tid][item.kind] = item.size;
-  }
+  if (live_process_state) {
+    for (const TraceThreadState &thread_state :
+        live_process_state->tracedThreads) {
+      for (const TraceBinaryData &item : thread_state.binaryData)
+        m_live_thread_data[thread_state.tid][item.kind] = item.size;
+    }
 
-  for (const TraceBinaryData &item : live_process_state->processBinaryData)
-    m_live_process_data[item.kind] = item.size;
+    for (const TraceBinaryData &item : live_process_state->processBinaryData)
+      m_live_process_data[item.kind] = item.size;
+  }
 
-  DoRefreshLiveProcessState(std::move(live_process_state));
 }
 
 uint32_t Trace::GetStopID() {
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -12,6 +12,7 @@
 #include "IntelPTDecoder.h"
 #include "TraceIntelPTSessionFileParser.h"
 #include "lldb/Utility/FileSpec.h"
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
 #include "lldb/lldb-types.h"
 #include "llvm/Support/raw_ostream.h"
 
@@ -74,8 +75,8 @@
 
   llvm::Optional<size_t> GetRawTraceSize(Thread &thread);
 
-  void DoRefreshLiveProcessState(
-      llvm::Expected<TraceGetStateResponse> state) override;
+  std::unique_ptr<TraceGetStateResponse> DoRefreshLiveProcessState(
+      llvm::Expected<std::string> json_string) override;
 
   bool IsTraced(lldb::tid_t tid) override;
 
@@ -183,6 +184,8 @@
   std::map<lldb::tid_t, std::unique_ptr<ThreadDecoder>> m_thread_decoders;
   /// Error gotten after a failed live process update, if any.
   llvm::Optional<std::string> m_live_refresh_error;
+  /// TSC to nano converter. nullptr if no conversion exists.
+  std::shared_ptr<TscConverter> m_tsc_converter;
 };
 
 } // namespace trace_intel_pt
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
@@ -17,7 +17,9 @@
 #include "lldb/Core/PluginManager.h"
 #include "lldb/Target/Process.h"
 #include "lldb/Target/Target.h"
+#include "lldb/Utility/TraceGDBRemotePackets.h"
 #include "llvm/ADT/None.h"
+#include <memory>
 
 using namespace lldb;
 using namespace lldb_private;
@@ -185,13 +187,22 @@
 
 Process *TraceIntelPT::GetLiveProcess() { return m_live_process; }
 
-void TraceIntelPT::DoRefreshLiveProcessState(
-    Expected<TraceGetStateResponse> state) {
+std::unique_ptr<TraceGetStateResponse> TraceIntelPT::DoRefreshLiveProcessState(
+    Expected<std::string> json_string) {
+
+  if (!json_string) {
+    m_live_refresh_error = toString(json_string.takeError());
+    return nullptr;
+  }
+
   m_thread_decoders.clear();
 
+  Expected<TraceIntelPTGetStateResponse> state =
+      json::parse<TraceIntelPTGetStateResponse>(*json_string, "TraceIntelPTGetStateResponse");
+
   if (!state) {
     m_live_refresh_error = toString(state.takeError());
-    return;
+    return nullptr;
   }
 
   for (const TraceThreadState &thread_state : state->tracedThreads) {
@@ -200,6 +211,10 @@
     m_thread_decoders.emplace(
         thread_state.tid, std::make_unique<LiveThreadDecoder>(thread, *this));
   }
+  if (!m_tsc_converter && state->tsc_converter)
+    m_tsc_converter = state->tsc_converter;
+
+  return std::make_unique<TraceGetStateResponse>(state.get());
 }
 
 bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
Index: lldb/source/Plugins/Process/Linux/IntelPTManager.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTManager.h
+++ lldb/source/Plugins/Process/Linux/IntelPTManager.h
@@ -235,6 +235,8 @@
   /// Dispose of all traces
   void Clear();
 
+  static std::shared_ptr<TscConverter> tsc_converter;
+
 private:
   llvm::Error TraceStop(lldb::tid_t tid);
 
Index: lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
@@ -42,6 +42,8 @@
 const char *kPSBPeriodBitOffsetFile =
     "/sys/bus/event_source/devices/intel_pt/format/psb_period";
 
+std::shared_ptr<TscConverter> IntelPTManager::tsc_converter = nullptr;
+
 enum IntelPTConfigFileType {
   Hex = 0,
   // 0 or 1
@@ -252,6 +254,10 @@
       reinterpret_cast<perf_event_mmap_page *>(base),
       munmap_delete(buffer_size + page_size));
 
+  if (m_mmap_meta->cap_user_time_zero) {
+    IntelPTManager::tsc_converter = std::make_shared<PerfTscConverter>(PerfTscConverter(m_mmap_meta->time_mult, m_mmap_meta->time_shift, m_mmap_meta->time_zero));
+  }
+
   m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
   m_mmap_meta->aux_size = buffer_size;
 
@@ -628,7 +634,7 @@
   if (!cpu_info)
     return cpu_info.takeError();
 
-  TraceGetStateResponse state;
+  TraceIntelPTGetStateResponse state;
   state.processBinaryData.push_back(
       {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
 
@@ -642,6 +648,9 @@
     state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
                                thread_states.end());
   }
+
+  state.tsc_converter = IntelPTManager::tsc_converter;
+
   return toJSON(state);
 }
 
Index: lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
===================================================================
--- lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -11,6 +11,7 @@
 
 #include "lldb/Utility/TraceGDBRemotePackets.h"
 
+
 /// See docs/lldb-gdb-remote.txt for more information.
 namespace lldb_private {
 
@@ -38,6 +39,59 @@
               llvm::json::Path path);
 
 llvm::json::Value toJSON(const TraceIntelPTStartRequest &packet);
+
+/// TSC to nanoseconds conversion values defined in struct perf_event_mmap_page.
+/// See https://man7.org/linux/man-pages/man2/perf_event_open.2.html for more information.
+struct PerfTscConversionValues {
+  // units should be uint32_t, uint16_t, uint64_t, respectively but since this will be converted to json these must be int64_t.
+  // This would only possibly be problematic for m_time_zero.
+  // TODO: how should the above issue be handled? Currently blindly casting time_zero to narrower type.
+  int64_t m_time_mult;
+  int64_t m_time_shift;
+  int64_t m_time_zero;
+};
+
+/// TSC to nanosecond conversion.
+struct TscConverter {
+  virtual ~TscConverter() = default;
+  /// Convert TSC value to nanoseconds.
+  virtual uint64_t TscToNanos(uint64_t tsc) = 0;
+  virtual llvm::json::Value toJSON() = 0;
+};
+
+/// Conversion based on values define in perf_event_mmap_page.
+struct PerfTscConverter : TscConverter {
+  PerfTscConverter() = default;
+  PerfTscConverter(uint32_t time_mult, uint16_t time_shift, uint64_t time_zero) :
+    m_perf_conversion{time_mult, time_shift, static_cast<int64_t>(time_zero)} {}
+  uint64_t TscToNanos(uint64_t tsc) override;
+  llvm::json::Value toJSON() override;
+
+  PerfTscConversionValues m_perf_conversion;
+};
+
+/// Conversion based on frequency conversion value defined in sys/fs file(s).
+//struct FreqTscConverter : TscConverter {
+//  FreqTscConverter(uint64_t freq_conversion) = default;
+//  FreqTscConverter(uint64_t freq_conversion) : m_freq_conversion(freq_conversion) {}
+//  uint64_t TscToNanos(uint64_t tsc) override;
+//  uint64_t m_freq_conversion;
+//};
+
+/// jLLDBTraceGetState gdb-remote packet
+/// Contains additional information related to TSC -> nanosecond conversion.
+struct TraceIntelPTGetStateResponse : TraceGetStateResponse {
+  /// Implementor of `TscConverter` interface.
+  /// `nullptr` if no TscConverter exists.
+  std::shared_ptr<TscConverter> tsc_converter;
+};
+
+bool fromJSON(const llvm::json::Value &value, std::shared_ptr<TscConverter> &tsc_converter, llvm::json::Path path);
+
+bool fromJSON(const llvm::json::Value &value, TraceIntelPTGetStateResponse &packet, llvm::json::Path path);
+
+llvm::json::Value toJSON(const TraceIntelPTGetStateResponse &packet);
+
 /// \}
 
 } // namespace lldb_private
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -302,10 +302,13 @@
   ///
   /// This is invoked by RefreshLiveProcessState when a new state is found.
   ///
-  /// \param[in] state
-  ///     The jLLDBTraceGetState response.
-  virtual void
-  DoRefreshLiveProcessState(llvm::Expected<TraceGetStateResponse> state) = 0;
+  /// \param[in] json_string
+  ///     String representation of the jLLDBTraceGetState response.
+  ///
+  /// \return
+  ///     Unique pointer to the packet response, nullptr if response parsing failed.
+  virtual std::unique_ptr<TraceGetStateResponse>
+  DoRefreshLiveProcessState(llvm::Expected<std::string> json_string) = 0;
 
   /// Method to be invoked by the plug-in to refresh the live process state.
   ///
Index: lldb/docs/lldb-gdb-remote.txt
===================================================================
--- lldb/docs/lldb-gdb-remote.txt
+++ lldb/docs/lldb-gdb-remote.txt
@@ -451,7 +451,8 @@
 //        "size": <decimal integer>,
 //            Size in bytes of this thread data.
 //      },
-//    }]
+//    }],
+//    ... other parameters specific to the provided tracing type
 //  }
 //
 // NOTES
@@ -463,6 +464,19 @@
 //  Binary data kinds:
 //    - threadTraceBuffer: trace buffer for a thread.
 //    - cpuInfo: contents of the /proc/cpuinfo file.
+//  Additional parameters in the output schema:
+//
+//    tsc_conversion: {
+//      kind: "perf",
+//      time_mult: int,
+//      time_shift: int,
+//      time_zero: int
+//      |
+//      kind: "freq"
+//      freq_conversion: int,
+//    }
+
+}
 //----------------------------------------------------------------------
 
 send packet: jLLDBTraceGetState:{"type":<type>}]
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits
  • [Lldb-commits] [PATCH] D120... Jakob Johnson via Phabricator via lldb-commits

Reply via email to