jj10306 updated this revision to Diff 413985.
jj10306 marked 2 inline comments as done.
jj10306 edited the summary of this revision.
jj10306 added a comment.

Addressed most of the previous diff's comments (other than the ones from 
@wallace and @davidca that were explicitly mentioned in my previous comment). 
The naming of the conversion values is currently inconsistent, but I will 
update the naming and make it consistent across all the new changes once the 
name is agreed upon.

- Add client and server side caching of conversion values
- Update `DecodedThread` to allow for access to the conversion values from the 
`TraceCursor`
- Add `GetNanos` (to be renamed) API to `TraceCursor` to allow for conversion 
of a trace instruction's TSC value to nanoseconds
- Update `trace schema` and `trace save` commands to accommodate schema changes
- Add `resource_handle` namespace to allow for reuse of file descriptor and 
munmap resource handles
- Rename IntelPTManager to IntelPTCollector


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

https://reviews.llvm.org/D120595

Files:
  lldb/docs/lldb-gdb-remote.txt
  lldb/include/lldb/Target/Trace.h
  lldb/include/lldb/Target/TraceCursor.h
  lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
  lldb/source/Plugins/Process/Linux/IntelPTManager.cpp
  lldb/source/Plugins/Process/Linux/IntelPTManager.h
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
  lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
  lldb/source/Plugins/Trace/intel-pt/DecodedThread.cpp
  lldb/source/Plugins/Trace/intel-pt/DecodedThread.h
  lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceCursorIntelPT.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
  lldb/source/Target/Trace.cpp
  lldb/source/Target/TraceInstructionDumper.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,51 @@
   return base;
 }
 
+uint64_t PerfTimestampCounterRate::ToNanos(uint64_t tsc) {
+  // See 'time_zero' section of https://man7.org/linux/man-pages/man2/perf_event_open.2.html
+    uint64_t quot = tsc >> m_time_shift;
+    uint64_t rem_flag = (((uint64_t)1 << m_time_shift) - 1);
+    uint64_t rem  = tsc & rem_flag;
+    return m_time_zero + quot * m_time_mult + ((rem * m_time_mult) >> m_time_shift);
+}
+
+bool fromJSON(const llvm::json::Value &value, TimestampCounterRateSP &tsc_rate, llvm::json::Path path) {
+  std::string tsc_rate_kind;
+  ObjectMapper o(value, path);
+
+  if(!o.map("kind", tsc_rate_kind))
+    return false;
+
+  if (tsc_rate_kind == "perf") {
+    int64_t time_mult, time_shift, time_zero;
+    if (!o.map("time_mult", time_mult) || !o.map("time_shift", time_shift) || !o.map("time_zero", time_zero))
+      return false;
+    tsc_rate = std::make_shared<PerfTimestampCounterRate>((uint32_t)time_mult, (uint16_t)time_shift, (uint64_t)time_zero);
+    return true;
+  }
+  path.report("Unsupported TSC rate kind");
+  return false;
+}
+
+bool fromJSON(const json::Value &value, TraceIntelPTGetStateResponse &packet, Path path) {
+  ObjectMapper o(value, path);
+  return o && fromJSON(value, (TraceGetStateResponse &)packet, path) && o.mapOptional("tsc_rate", packet.tsc_rate);
+}
+
+llvm::json::Value PerfTimestampCounterRate::toJSON() {
+  return json::Value(json::Object{
+    {"kind", "perf"},
+    {"time_mult", (int64_t) m_time_mult},
+    {"time_shift", (int64_t) m_time_shift},
+    {"time_zero", (int64_t) m_time_zero},
+  });
+}
+
+json::Value toJSON(const TraceIntelPTGetStateResponse &packet) {
+  json::Value base = toJSON((const TraceGetStateResponse &)packet);
+  if (packet.tsc_rate)
+    base.getAsObject()->try_emplace("tsc_rate", packet.tsc_rate->toJSON());
+
+  return base;
+}
 } // namespace lldb_private
Index: lldb/source/Target/TraceInstructionDumper.cpp
===================================================================
--- lldb/source/Target/TraceInstructionDumper.cpp
+++ lldb/source/Target/TraceInstructionDumper.cpp
@@ -185,6 +185,10 @@
 
       if (Optional<uint64_t> timestamp = m_cursor_up->GetTimestampCounter())
         s.Printf("0x%016" PRIx64, *timestamp);
+      // TODO: temporary hacky way to see new timestamp functionality
+      // How do we want to incorporate the nanosecon values into the dump output?
+      if (Optional<uint64_t> timestamp_nanos = m_cursor_up->GetNanos())
+        s.Printf(" NANOS 0x%016" PRIx64, *timestamp_nanos);
       else
         s.Printf("unavailable");
 
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,20 +188,12 @@
   m_stop_id = new_stop_id;
   m_live_thread_data.clear();
 
-  Expected<std::string> json_string = GetLiveProcessState();
-  if (!json_string) {
-    DoRefreshLiveProcessState(json_string.takeError());
+  llvm::Optional<TraceGetStateResponse> live_process_state = DoRefreshLiveProcessState(GetLiveProcessState());
+  if (!live_process_state)
     return;
-  }
-  Expected<TraceGetStateResponse> live_process_state =
-      json::parse<TraceGetStateResponse>(*json_string, "TraceGetStateResponse");
-  if (!live_process_state) {
-    DoRefreshLiveProcessState(live_process_state.takeError());
-    return;
-  }
 
   for (const TraceThreadState &thread_state :
-       live_process_state->tracedThreads) {
+      live_process_state->tracedThreads) {
     for (const TraceBinaryData &item : thread_state.binaryData)
       m_live_thread_data[thread_state.tid][item.kind] = item.size;
   }
@@ -208,7 +201,6 @@
   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/TraceIntelPTSessionSaver.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionSaver.cpp
@@ -75,5 +75,6 @@
     return cpu_info.takeError();
 
   return JSONTraceIntelPTTrace{"intel-pt",
-                               JSONTraceIntelPTCPUInfo(cpu_info.get())};
+                               JSONTraceIntelPTCPUInfo(cpu_info.get()),
+                               trace_ipt.GetTimestampCounterRate()};
 }
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
@@ -43,7 +43,8 @@
 
   lldb::TraceSP
   CreateTraceIntelPTInstance(const pt_cpu &cpu_info,
-                             std::vector<ParsedProcess> &parsed_processes);
+                             std::vector<ParsedProcess> &parsed_processes,
+                             TimestampCounterRateSP tsc_conversion_params_sp);
 
 private:
   static pt_cpu ParsePTCPU(const JSONTraceIntelPTCPUInfo &cpu_info);
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
@@ -19,6 +19,10 @@
 StringRef TraceIntelPTSessionFileParser::GetSchema() {
   static std::string schema;
   if (schema.empty()) {
+    // TODO: how to cleanly describe tsc_conversion_params in the schema strings
+    // given its potential different variants and it being optional?
+    // For now just putting perf variant until
+    // feedback is gathered
     schema = TraceSessionFileParser::BuildSchema(R"({
     "type": "intel-pt",
     "cpuInfo": {
@@ -26,6 +30,12 @@
       "family": integer,
       "model": integer,
       "stepping": integer
+    },
+    "tsc_conversion_params"?: {
+        "kind": "perf",
+        "time_mult": integer,
+        "time_shift": integer,
+        "time_zero": integer
     }
   })");
   }
@@ -41,13 +51,14 @@
 }
 
 TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
-    const pt_cpu &cpu_info, std::vector<ParsedProcess> &parsed_processes) {
+    const pt_cpu &cpu_info, std::vector<ParsedProcess> &parsed_processes,
+    TimestampCounterRateSP tsc_conversion_params_sp) {
   std::vector<ThreadPostMortemTraceSP> threads;
   for (const ParsedProcess &parsed_process : parsed_processes)
     threads.insert(threads.end(), parsed_process.threads.begin(),
                    parsed_process.threads.end());
 
-  TraceSP trace_instance(new TraceIntelPT(cpu_info, threads));
+  TraceSP trace_instance(new TraceIntelPT(cpu_info, threads, tsc_conversion_params_sp));
   for (const ParsedProcess &parsed_process : parsed_processes)
     parsed_process.target_sp->SetTrace(trace_instance);
 
@@ -63,7 +74,7 @@
   if (Expected<std::vector<ParsedProcess>> parsed_processes =
           ParseCommonSessionFile(session))
     return CreateTraceIntelPTInstance(ParsePTCPU(session.trace.cpuInfo),
-                                      *parsed_processes);
+                                      *parsed_processes, session.trace.tsc_conversion_params);
   else
     return parsed_processes.takeError();
 }
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTJSONSTRUCTS_H
 #define LLDB_SOURCE_PLUGINS_TRACE_INTEL_PT_TRACEINTELPTJSONSTRUCTS_H
 
+#include "lldb/Utility/TraceIntelPTGDBRemotePackets.h"
 #include "../common/TraceJSONStructs.h"
 #include <intel-pt.h>
 
@@ -34,6 +35,7 @@
 struct JSONTraceIntelPTTrace {
   std::string type;
   JSONTraceIntelPTCPUInfo cpuInfo;
+  TimestampCounterRateSP tsc_conversion_params;
 };
 
 struct JSONTraceIntelPTSession {
@@ -43,6 +45,7 @@
 
 struct JSONTraceIntelPTSettings : JSONTracePluginSettings {
   JSONTraceIntelPTCPUInfo cpuInfo;
+  TimestampCounterRateSP tsc_conversion_params;
 };
 
 } // namespace trace_intel_pt
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.cpp
@@ -22,8 +22,9 @@
 bool fromJSON(const Value &value, JSONTraceIntelPTSettings &plugin_settings,
               Path path) {
   ObjectMapper o(value, path);
-  return o && o.map("cpuInfo", plugin_settings.cpuInfo) &&
-         fromJSON(value, (JSONTracePluginSettings &)plugin_settings, path);
+  return o && o.map("cpuInfo", plugin_settings.cpuInfo)
+         && o.mapOptional("tsc_conversion_params", plugin_settings.tsc_conversion_params)
+         && fromJSON(value, (JSONTracePluginSettings &)plugin_settings, path);
 }
 
 bool fromJSON(const json::Value &value, JSONTraceIntelPTCPUInfo &cpu_info,
@@ -45,6 +46,7 @@
   llvm::json::Object json_trace;
   json_trace["type"] = trace.type;
   json_trace["cpuInfo"] = toJSON(trace.cpuInfo);
+  json_trace["tsc_conversion_params"] = trace.tsc_conversion_params->toJSON();
   return std::move(json_trace);
 }
 
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;
+  llvm::Optional<TraceGetStateResponse> DoRefreshLiveProcessState(
+      llvm::Expected<std::string> json_string) override;
 
   bool IsTraced(lldb::tid_t tid) override;
 
@@ -142,6 +143,9 @@
 
   llvm::Expected<pt_cpu> GetCPUInfo();
 
+  // TODO: rename and add docs after naming convention is agreed upon
+  TimestampCounterRateSP GetTimestampCounterRate();
+
   /// Get the current traced live process.
   ///
   /// \return
@@ -159,7 +163,8 @@
   ///     files are fixed.
   TraceIntelPT(
       const pt_cpu &cpu_info,
-      const std::vector<lldb::ThreadPostMortemTraceSP> &traced_threads);
+      const std::vector<lldb::ThreadPostMortemTraceSP> &traced_threads,
+      const TimestampCounterRateSP tsc_conversion_params_sp);
 
   /// Constructor for live processes
   TraceIntelPT(Process &live_process)
@@ -183,8 +188,13 @@
   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;
+  /// \a llvm::None indicates that the program has not yet attempted to fetch the timestamp conversion rate.
+  /// After attempting to fetch, this represents the timestamp counter rate if one exists, otherwise `nullptr`.
+  llvm::Optional<TimestampCounterRateSP> m_tsc_rate;
 };
 
+using TraceIntelPTSP = std::shared_ptr<TraceIntelPT>;
+
 } // namespace trace_intel_pt
 } // namespace lldb_private
 
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,6 +17,7 @@
 #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"
 
 using namespace lldb;
@@ -76,8 +77,9 @@
 
 TraceIntelPT::TraceIntelPT(
     const pt_cpu &cpu_info,
-    const std::vector<ThreadPostMortemTraceSP> &traced_threads)
-    : m_cpu_info(cpu_info) {
+    const std::vector<ThreadPostMortemTraceSP> &traced_threads,
+    const TimestampCounterRateSP tsc_conversion_params_sp)
+    : m_cpu_info(cpu_info), m_tsc_rate(tsc_conversion_params_sp) {
   for (const ThreadPostMortemTraceSP &thread : traced_threads)
     m_thread_decoders.emplace(
         thread->GetID(),
@@ -183,15 +185,28 @@
   return *m_cpu_info;
 }
 
+TimestampCounterRateSP TraceIntelPT::GetTimestampCounterRate() {
+  return m_tsc_rate ? *m_tsc_rate : nullptr;
+}
+
 Process *TraceIntelPT::GetLiveProcess() { return m_live_process; }
 
-void TraceIntelPT::DoRefreshLiveProcessState(
-    Expected<TraceGetStateResponse> state) {
+llvm::Optional<TraceGetStateResponse> TraceIntelPT::DoRefreshLiveProcessState(
+    Expected<std::string> json_string) {
+
+  if (!json_string) {
+    m_live_refresh_error = toString(json_string.takeError());
+    return llvm::None;
+  }
+
   m_thread_decoders.clear();
 
+  Expected<TraceIntelPTGetStateResponse> state =
+      json::parse<TraceIntelPTGetStateResponse>(*json_string, "TraceIntelPTGetStateResponse");
+
   if (!state) {
     m_live_refresh_error = toString(state.takeError());
-    return;
+    return llvm::None;
   }
 
   for (const TraceThreadState &thread_state : state->tracedThreads) {
@@ -200,6 +215,8 @@
     m_thread_decoders.emplace(
         thread_state.tid, std::make_unique<LiveThreadDecoder>(thread, *this));
   }
+  m_tsc_rate = state->tsc_rate;
+  return state.get();
 }
 
 bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
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
@@ -30,6 +30,8 @@
 
   llvm::Optional<uint64_t> GetTimestampCounter() override;
 
+  llvm::Optional<uint64_t> GetNanos() override;
+
   lldb::TraceInstructionControlFlowType
   GetInstructionControlFlowType() override;
 
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
@@ -7,11 +7,13 @@
 //===----------------------------------------------------------------------===//
 
 #include "TraceCursorIntelPT.h"
+
 #include "DecodedThread.h"
-#include "TraceIntelPT.h"
 
+#include <cstdint>
 #include <cstdlib>
 
+
 using namespace lldb;
 using namespace lldb_private;
 using namespace lldb_private::trace_intel_pt;
@@ -89,6 +91,14 @@
   return m_decoded_thread_sp->GetInstructions()[m_pos].GetTimestampCounter();
 }
 
+Optional<uint64_t> TraceCursorIntelPT::GetNanos() {
+  if (Optional<uint64_t> tsc = GetTimestampCounter()) {
+    if (TimestampCounterRateSP conversion_params_sp = m_decoded_thread_sp->GetTscConversionParams())
+      return conversion_params_sp->ToNanos(*tsc);
+  }
+  return llvm::None;
+}
+
 TraceInstructionControlFlowType
 TraceCursorIntelPT::GetInstructionControlFlowType() {
   lldb::addr_t next_load_address =
Index: lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
+++ lldb/source/Plugins/Trace/intel-pt/IntelPTDecoder.cpp
@@ -258,7 +258,7 @@
                           m_trace_thread->GetTraceFile(), raw_trace_size))
     return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
                                            std::move(*instructions),
-                                           raw_trace_size);
+                                           raw_trace_size, m_trace);
   else
     return std::make_shared<DecodedThread>(m_trace_thread->shared_from_this(),
                                            instructions.takeError());
@@ -272,7 +272,7 @@
   if (Expected<std::vector<IntelPTInstruction>> instructions =
           DecodeLiveThread(*m_thread_sp, m_trace, raw_trace_size))
     return std::make_shared<DecodedThread>(
-        m_thread_sp, std::move(*instructions), raw_trace_size);
+        m_thread_sp, std::move(*instructions), raw_trace_size, m_trace);
   else
     return std::make_shared<DecodedThread>(m_thread_sp,
                                            instructions.takeError());
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
@@ -22,6 +22,9 @@
 namespace lldb_private {
 namespace trace_intel_pt {
 
+// Forward declaration for use in DecodedThread class
+class TraceIntelPT;
+
 /// Class for representing a libipt decoding error.
 class IntelPTError : public llvm::ErrorInfo<IntelPTError> {
 public:
@@ -128,7 +131,8 @@
 public:
   DecodedThread(lldb::ThreadSP thread_sp,
                 std::vector<IntelPTInstruction> &&instructions,
-                size_t raw_trace_size);
+                size_t raw_trace_size,
+                TraceIntelPT &trace);
 
   /// Constructor with a single error signaling a complete failure of the
   /// decoding process.
@@ -144,6 +148,9 @@
   /// Get a new cursor for the decoded thread.
   lldb::TraceCursorUP GetCursor();
 
+  /// Get the TSC conversion params for the decoded thread.
+  TimestampCounterRateSP GetTscConversionParams() const;
+
   /// Get the size in bytes of the corresponding Intel PT raw trace
   ///
   /// \return
@@ -154,6 +161,7 @@
   lldb::ThreadSP m_thread_sp;
   std::vector<IntelPTInstruction> m_instructions;
   size_t m_raw_trace_size;
+  TimestampCounterRateSP m_tsc_conversion_params;
 };
 
 using DecodedThreadSP = std::shared_ptr<DecodedThread>;
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
@@ -105,9 +105,10 @@
 
 DecodedThread::DecodedThread(ThreadSP thread_sp,
                              std::vector<IntelPTInstruction> &&instructions,
-                             size_t raw_trace_size)
+                             size_t raw_trace_size,
+                             TraceIntelPT &trace)
     : m_thread_sp(thread_sp), m_instructions(std::move(instructions)),
-      m_raw_trace_size(raw_trace_size) {
+      m_raw_trace_size(raw_trace_size), m_tsc_conversion_params(trace.GetTimestampCounterRate()) {
   if (m_instructions.empty())
     m_instructions.emplace_back(
         createStringError(inconvertibleErrorCode(), "empty trace"));
@@ -116,3 +117,7 @@
 lldb::TraceCursorUP DecodedThread::GetCursor() {
   return std::make_unique<TraceCursorIntelPT>(m_thread_sp, shared_from_this());
 }
+
+TimestampCounterRateSP DecodedThread::GetTscConversionParams() const {
+  return m_tsc_conversion_params;
+}
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.h
@@ -241,7 +241,7 @@
   Status PopulateMemoryRegionCache();
 
   /// Manages Intel PT process and thread traces.
-  IntelPTManager m_intel_pt_manager;
+  IntelPTCollector m_intel_pt_collector;
 
   // Handle a clone()-like event.
   bool MonitorClone(NativeThreadLinux &parent, lldb::pid_t child_pid,
Index: lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
+++ lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp
@@ -312,7 +312,7 @@
                                        const ArchSpec &arch, MainLoop &mainloop,
                                        llvm::ArrayRef<::pid_t> tids)
     : NativeProcessELF(pid, terminal_fd, delegate), m_arch(arch),
-      m_main_loop(mainloop), m_intel_pt_manager(pid) {
+      m_main_loop(mainloop), m_intel_pt_collector(pid) {
   if (m_terminal_fd != -1) {
     Status status = EnsureFDFlags(m_terminal_fd, O_NONBLOCK);
     assert(status.Success());
@@ -983,7 +983,7 @@
           e; // Save the error, but still attempt to detach from other threads.
   }
 
-  m_intel_pt_manager.Clear();
+  m_intel_pt_collector.Clear();
 
   return error;
 }
@@ -1666,7 +1666,7 @@
 
 Status NativeProcessLinux::NotifyTracersOfNewThread(lldb::tid_t tid) {
   Log *log = GetLog(POSIXLog::Thread);
-  Status error(m_intel_pt_manager.OnThreadCreated(tid));
+  Status error(m_intel_pt_collector.OnThreadCreated(tid));
   if (error.Fail())
     LLDB_LOG(log, "Failed to trace a new thread with intel-pt, tid = {0}. {1}",
              tid, error.AsCString());
@@ -1675,7 +1675,7 @@
 
 Status NativeProcessLinux::NotifyTracersOfThreadDestroyed(lldb::tid_t tid) {
   Log *log = GetLog(POSIXLog::Thread);
-  Status error(m_intel_pt_manager.OnThreadDestroyed(tid));
+  Status error(m_intel_pt_collector.OnThreadDestroyed(tid));
   if (error.Fail())
     LLDB_LOG(log,
              "Failed to stop a destroyed thread with intel-pt, tid = {0}. {1}",
@@ -1938,7 +1938,7 @@
 }
 
 llvm::Expected<TraceSupportedResponse> NativeProcessLinux::TraceSupported() {
-  if (IntelPTManager::IsSupported())
+  if (IntelPTCollector::IsSupported())
     return TraceSupportedResponse{"intel-pt", "Intel Processor Trace"};
   return NativeProcessProtocol::TraceSupported();
 }
@@ -1951,7 +1951,7 @@
       std::vector<lldb::tid_t> process_threads;
       for (auto &thread : m_threads)
         process_threads.push_back(thread->GetID());
-      return m_intel_pt_manager.TraceStart(*request, process_threads);
+      return m_intel_pt_collector.TraceStart(*request, process_threads);
     } else
       return request.takeError();
   }
@@ -1961,19 +1961,19 @@
 
 Error NativeProcessLinux::TraceStop(const TraceStopRequest &request) {
   if (request.type == "intel-pt")
-    return m_intel_pt_manager.TraceStop(request);
+    return m_intel_pt_collector.TraceStop(request);
   return NativeProcessProtocol::TraceStop(request);
 }
 
 Expected<json::Value> NativeProcessLinux::TraceGetState(StringRef type) {
   if (type == "intel-pt")
-    return m_intel_pt_manager.GetState();
+    return m_intel_pt_collector.GetState();
   return NativeProcessProtocol::TraceGetState(type);
 }
 
 Expected<std::vector<uint8_t>> NativeProcessLinux::TraceGetBinaryData(
     const TraceGetBinaryDataRequest &request) {
   if (request.type == "intel-pt")
-    return m_intel_pt_manager.GetBinaryData(request);
+    return m_intel_pt_collector.GetBinaryData(request);
   return NativeProcessProtocol::TraceGetBinaryData(request);
 }
Index: lldb/source/Plugins/Process/Linux/IntelPTManager.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTManager.h
+++ lldb/source/Plugins/Process/Linux/IntelPTManager.h
@@ -23,6 +23,36 @@
 
 namespace process_linux {
 
+namespace resource_handle {
+
+class munmap_delete {
+  size_t m_length;
+
+public:
+  munmap_delete(size_t length) : m_length(length) {}
+  void operator()(void *ptr) {
+    if (m_length)
+      munmap(ptr, m_length);
+  }
+};
+
+class file_close {
+
+public:
+  file_close() = default;
+  void operator()(int *ptr) {
+    if (ptr == nullptr)
+      return;
+    if (*ptr == -1)
+      return;
+    close(*ptr);
+  std::default_delete<int>()(ptr);
+}
+};
+
+} // namespace resource_handle
+
+
 /// This class keeps track of one tracing instance of
 /// Intel(R) Processor Trace on Linux OS at thread level.
 ///
@@ -32,34 +62,9 @@
 
 class IntelPTThreadTrace {
 
-  class munmap_delete {
-    size_t m_length;
-
-  public:
-    munmap_delete(size_t length) : m_length(length) {}
-    void operator()(void *ptr) {
-      if (m_length)
-        munmap(ptr, m_length);
-    }
-  };
-
-  class file_close {
-
-  public:
-    file_close() = default;
-    void operator()(int *ptr) {
-      if (ptr == nullptr)
-        return;
-      if (*ptr == -1)
-        return;
-      close(*ptr);
-      std::default_delete<int>()(ptr);
-    }
-  };
-
-  std::unique_ptr<perf_event_mmap_page, munmap_delete> m_mmap_meta;
-  std::unique_ptr<uint8_t, munmap_delete> m_mmap_aux;
-  std::unique_ptr<int, file_close> m_fd;
+  std::unique_ptr<perf_event_mmap_page, resource_handle::munmap_delete> m_mmap_meta;
+  std::unique_ptr<uint8_t, resource_handle::munmap_delete> m_mmap_aux;
+  std::unique_ptr<int, resource_handle::file_close> m_fd;
   lldb::tid_t m_tid;
 
   /// Start tracing a thread
@@ -88,8 +93,8 @@
   llvm::MutableArrayRef<uint8_t> GetDataBuffer() const;
 
   IntelPTThreadTrace()
-      : m_mmap_meta(nullptr, munmap_delete(0)),
-        m_mmap_aux(nullptr, munmap_delete(0)), m_fd(nullptr, file_close()) {}
+      : m_mmap_meta(nullptr, resource_handle::munmap_delete(0)),
+        m_mmap_aux(nullptr, resource_handle::munmap_delete(0)), m_fd(nullptr, resource_handle::file_close()) {}
 
 public:
   /// Get the content of /proc/cpuinfo that can be later used to decode traces.
@@ -203,11 +208,20 @@
 };
 
 /// Main class that manages intel-pt process and thread tracing.
-class IntelPTManager {
+class IntelPTCollector {
 public:
-  IntelPTManager(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {}
+  IntelPTCollector(lldb::pid_t pid) : m_pid(pid), m_thread_traces(pid) {}
 
   static bool IsSupported();
+  /// Start tracing a thread
+  ///
+  /// \param[in] pid
+  ///     The process id of the thread being traced.
+  ///
+  /// \return
+  ///     \a The timestamp counter rate if one exists, \a nullptr if no conversion exists.
+  static TimestampCounterRateSP GetTscRate(lldb::pid_t pid);
+
 
   /// If "process tracing" is enabled, then trace the given thread.
   llvm::Error OnThreadCreated(lldb::tid_t tid);
@@ -235,6 +249,9 @@
   /// Dispose of all traces
   void Clear();
 
+  /// Server-side cache of timestamp counter rate
+  static llvm::Optional<TimestampCounterRateSP> g_tsc_rate;
+
 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
@@ -8,8 +8,10 @@
 
 #include <algorithm>
 #include <fstream>
+#include <linux/perf_event.h>
 #include <sstream>
 
+#include "llvm/ADT/Optional.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/Support/Error.h"
 #include "llvm/Support/MathExtras.h"
@@ -18,8 +20,10 @@
 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
 #include "lldb/Host/linux/Support.h"
 #include "lldb/Utility/StreamString.h"
+#include "lldb/lldb-types.h"
 
 #include <sys/ioctl.h>
+#include <sys/mman.h>
 #include <sys/syscall.h>
 
 using namespace lldb;
@@ -42,6 +46,8 @@
 const char *kPSBPeriodBitOffsetFile =
     "/sys/bus/event_source/devices/intel_pt/format/psb_period";
 
+llvm::Optional<TimestampCounterRateSP> IntelPTCollector::g_tsc_rate = llvm::None;
+
 enum IntelPTConfigFileType {
   Hex = 0,
   // 0 or 1
@@ -236,7 +242,7 @@
                              "perf event syscall failed");
   }
 
-  m_fd = std::unique_ptr<int, file_close>(new int(fd), file_close());
+  m_fd = std::unique_ptr<int, resource_handle::file_close>(new int(fd), resource_handle::file_close());
 
   errno = 0;
   auto base =
@@ -248,9 +254,9 @@
                              "Meta buffer allocation failed");
   }
 
-  m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
+  m_mmap_meta = std::unique_ptr<perf_event_mmap_page, resource_handle::munmap_delete>(
       reinterpret_cast<perf_event_mmap_page *>(base),
-      munmap_delete(buffer_size + page_size));
+      resource_handle::munmap_delete(buffer_size + page_size));
 
   m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size;
   m_mmap_meta->aux_size = buffer_size;
@@ -264,8 +270,8 @@
     return createStringError(inconvertibleErrorCode(),
                              "Trace buffer allocation failed");
   }
-  m_mmap_aux = std::unique_ptr<uint8_t, munmap_delete>(
-      reinterpret_cast<uint8_t *>(mmap_aux), munmap_delete(buffer_size));
+  m_mmap_aux = std::unique_ptr<uint8_t, resource_handle::munmap_delete>(
+      reinterpret_cast<uint8_t *>(mmap_aux), resource_handle::munmap_delete(buffer_size));
   return Error::success();
 #endif
 }
@@ -564,15 +570,15 @@
   return m_thread_traces;
 }
 
-/// IntelPTManager
+/// IntelPTCollector
 
-Error IntelPTManager::TraceStop(lldb::tid_t tid) {
+Error IntelPTCollector::TraceStop(lldb::tid_t tid) {
   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
     return m_process_trace->TraceStop(tid);
   return m_thread_traces.TraceStop(tid);
 }
 
-Error IntelPTManager::TraceStop(const TraceStopRequest &request) {
+Error IntelPTCollector::TraceStop(const TraceStopRequest &request) {
   if (request.IsProcessTracing()) {
     Clear();
     return Error::success();
@@ -585,7 +591,7 @@
   }
 }
 
-Error IntelPTManager::TraceStart(
+Error IntelPTCollector::TraceStart(
     const TraceIntelPTStartRequest &request,
     const std::vector<lldb::tid_t> &process_threads) {
   if (request.IsProcessTracing()) {
@@ -609,13 +615,13 @@
   }
 }
 
-Error IntelPTManager::OnThreadCreated(lldb::tid_t tid) {
+Error IntelPTCollector::OnThreadCreated(lldb::tid_t tid) {
   if (!IsProcessTracingEnabled())
     return Error::success();
   return m_process_trace->TraceStart(tid);
 }
 
-Error IntelPTManager::OnThreadDestroyed(lldb::tid_t tid) {
+Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
     return m_process_trace->TraceStop(tid);
   else if (m_thread_traces.TracesThread(tid))
@@ -623,12 +629,12 @@
   return Error::success();
 }
 
-Expected<json::Value> IntelPTManager::GetState() const {
+Expected<json::Value> IntelPTCollector::GetState() const {
   Expected<ArrayRef<uint8_t>> cpu_info = IntelPTThreadTrace::GetCPUInfo();
   if (!cpu_info)
     return cpu_info.takeError();
 
-  TraceGetStateResponse state;
+  TraceIntelPTGetStateResponse state;
   state.processBinaryData.push_back(
       {"cpuInfo", static_cast<int64_t>(cpu_info->size())});
 
@@ -642,18 +648,20 @@
     state.tracedThreads.insert(state.tracedThreads.end(), thread_states.begin(),
                                thread_states.end());
   }
+
+  state.tsc_rate = IntelPTCollector::GetTscRate(m_pid);
   return toJSON(state);
 }
 
 Expected<const IntelPTThreadTrace &>
-IntelPTManager::GetTracedThread(lldb::tid_t tid) const {
+IntelPTCollector::GetTracedThread(lldb::tid_t tid) const {
   if (IsProcessTracingEnabled() && m_process_trace->TracesThread(tid))
     return m_process_trace->GetThreadTraces().GetTracedThread(tid);
   return m_thread_traces.GetTracedThread(tid);
 }
 
 Expected<std::vector<uint8_t>>
-IntelPTManager::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
+IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const {
   if (request.kind == "threadTraceBuffer") {
     if (Expected<const IntelPTThreadTrace &> trace =
             GetTracedThread(*request.tid))
@@ -668,9 +676,9 @@
                            request.kind.c_str());
 }
 
-void IntelPTManager::ClearProcessTracing() { m_process_trace = None; }
+void IntelPTCollector::ClearProcessTracing() { m_process_trace = None; }
 
-bool IntelPTManager::IsSupported() {
+bool IntelPTCollector::IsSupported() {
   Expected<uint32_t> intel_pt_type = GetOSEventType();
   if (!intel_pt_type) {
     llvm::consumeError(intel_pt_type.takeError());
@@ -679,11 +687,70 @@
   return true;
 }
 
-bool IntelPTManager::IsProcessTracingEnabled() const {
+bool IntelPTCollector::IsProcessTracingEnabled() const {
   return (bool)m_process_trace;
 }
 
-void IntelPTManager::Clear() {
+void IntelPTCollector::Clear() {
   ClearProcessTracing();
   m_thread_traces.Clear();
 }
+
+llvm::Expected<TimestampCounterRateSP> PerfGetTscRate(lldb::pid_t pid) {
+    Log *log = GetLog(POSIXLog::Ptrace);
+    perf_event_attr attr;
+    memset(&attr, 0, sizeof(attr));
+    // Set the minimum attributes necessary to access the mmap metadata page.
+    attr.size = sizeof(attr);
+    attr.type = PERF_TYPE_SOFTWARE;
+    attr.config = PERF_COUNT_SW_DUMMY;
+    attr.sample_type = PERF_SAMPLE_TIME;
+
+    errno = 0;
+    auto fd =
+        syscall(SYS_perf_event_open, &attr, pid, -1, -1, 0);
+    if (fd == -1) {
+      LLDB_LOG(log, "syscall error {0}", errno);
+      return createStringError(inconvertibleErrorCode(), "perf event syscall failed");
+    }
+    auto fd_handle = std::unique_ptr<int, resource_handle::file_close>(new int(fd), resource_handle::file_close());
+
+    uint64_t page_size = getpagesize();
+    errno = 0;
+    auto base =
+        mmap(nullptr, page_size, PROT_READ, MAP_SHARED, fd, 0);
+
+    if (base == MAP_FAILED) {
+      // TODO: should logging be done in this function or should the error just be returned here and let
+      // the caller log/consume the error?
+      LLDB_LOG(log, "mmap base error {0}", errno);
+      return createStringError(inconvertibleErrorCode(), "perf mmap meta allocation failed");
+    }
+    auto perf_mmap_meta_handle =
+          std::unique_ptr<perf_event_mmap_page, resource_handle::munmap_delete>(
+            reinterpret_cast<perf_event_mmap_page *>(base),
+            resource_handle::munmap_delete(page_size));
+
+    if (perf_mmap_meta_handle->cap_user_time && perf_mmap_meta_handle->cap_user_time_zero) {
+      return std::make_shared<PerfTimestampCounterRate>(perf_mmap_meta_handle->time_mult, perf_mmap_meta_handle->time_shift, perf_mmap_meta_handle->time_zero);
+    } else {
+      auto err_cap = !perf_mmap_meta_handle->cap_user_time ? "cap_user_time" : "cap_user_time_zero";
+      LLDB_LOG(log, "{0} not supported. TSC cannot be converted to time unit", err_cap);
+      return createStringError(inconvertibleErrorCode(), "TSC cannot be converted to time unit due to unsupported capabilities");
+    }
+}
+
+TimestampCounterRateSP IntelPTCollector::GetTscRate(lldb::pid_t pid) {
+#ifndef PERF_ATTR_SIZE_VER5
+  llvm_unreachable("Intel PT Linux perf event not supported");
+#else
+  if (!g_tsc_rate) {
+    g_tsc_rate = nullptr;
+    // Try to get a TSC rate from each different source until one succeeds
+    // Add additional sources of TSC rate, as necessary
+    if (llvm::Expected<TimestampCounterRateSP> perf_tsc_rate = PerfGetTscRate(pid))
+      g_tsc_rate = *perf_tsc_rate;
+  }
+  return *g_tsc_rate;
+#endif
+}
Index: lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
===================================================================
--- lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
+++ lldb/include/lldb/Utility/TraceIntelPTGDBRemotePackets.h
@@ -38,6 +38,50 @@
               llvm::json::Path path);
 
 llvm::json::Value toJSON(const TraceIntelPTStartRequest &packet);
+
+/// Class that can be extended to represent different CPU Timestamp Counter (TSC) conversion
+/// rates, which can be used to convert TSCs to common units of time, such as nanoseconds. More
+/// on TSCs can be found here https://en.wikipedia.org/wiki/Time_Stamp_Counter.
+// TODO: update after naming convention is agreed upon
+class TimestampCounterRate {
+  public:
+    virtual ~TimestampCounterRate() = default;
+    /// Convert a TSC value to nanoseconds. This represents the number of nanoseconds since
+    /// the TSC's reset.
+    virtual uint64_t ToNanos(uint64_t tsc) = 0;
+    virtual llvm::json::Value toJSON() = 0;
+};
+
+using TimestampCounterRateSP = std::shared_ptr<TimestampCounterRate> ;
+
+/// TSC to nanoseconds conversion values defined by the Linux perf_event API when the
+/// capibilities cap_user_time and cap_user_time_zero are set. See the documentation of
+/// `time_zero` in https://man7.org/linux/man-pages/man2/perf_event_open.2.html for more information.
+class PerfTimestampCounterRate : public TimestampCounterRate {
+  public:
+    PerfTimestampCounterRate(uint32_t time_mult, uint16_t time_shift, uint64_t time_zero) :
+      m_time_mult(time_mult), m_time_shift(time_shift), m_time_zero(time_zero) {}
+    uint64_t ToNanos(uint64_t tsc) override;
+    llvm::json::Value toJSON() override;
+
+  private:
+    uint32_t m_time_mult;
+    uint16_t m_time_shift;
+    uint64_t m_time_zero;
+};
+
+/// jLLDBTraceGetState gdb-remote packet
+struct TraceIntelPTGetStateResponse : TraceGetStateResponse {
+  /// Timestamp counter rate if one exists, otherwise `nullptr`.
+  TimestampCounterRateSP tsc_rate;
+};
+
+bool fromJSON(const llvm::json::Value &value, TimestampCounterRateSP &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/TraceCursor.h
===================================================================
--- lldb/include/lldb/Target/TraceCursor.h
+++ lldb/include/lldb/Target/TraceCursor.h
@@ -189,6 +189,9 @@
   ///     The timestamp or \b llvm::None if not available.
   virtual llvm::Optional<uint64_t> GetTimestampCounter() = 0;
 
+  // TODO: add docs and rename once naming convention is agreed upon
+  virtual llvm::Optional<uint64_t> GetNanos() = 0;
+
   /// \return
   ///     The \a lldb::TraceInstructionControlFlowType categories the
   ///     instruction the cursor is pointing at falls into. If the cursor points
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -302,10 +302,14 @@
   ///
   /// 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
+  ///     JSON string representing the jLLDBTraceGetState response,
+  ///     it may be invalid.
+  ///
+  /// \return
+  ///     The packet response, None if response parsing failed.
+  virtual llvm::Optional<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,16 @@
 //        "size": <decimal integer>,
 //            Size in bytes of this thread data.
 //      },
-//    }]
+//    }],
+//    "tsc_conversion"?: Optional<{
+//      "kind": <string>,
+//           Timestamp counter conversion rate kind, e.g. perf.
+//           The kind strings can be found in the overriden toJSON method
+//           of each TimestampCounterRate subclass. The kind determines
+//           what fields are available in the remainder of the response.
+//
+//      ... additional parameters specific to the provided tracing type and tsc_conversion kind
+//    }>
 //  }
 //
 // NOTES
@@ -463,6 +472,33 @@
 //  Binary data kinds:
 //    - threadTraceBuffer: trace buffer for a thread.
 //    - cpuInfo: contents of the /proc/cpuinfo file.
+//
+//  Additional params in the tsc_conversion output schema when kind == "perf":
+//   {
+//     "time_mult": <decimal integer>,
+//         time_mult field of the Linux perf_event_mmap_page struct available when
+//         cap_usr_time is set. Used in TSC to nanosecond conversion calculation defined
+//         by the Linux perf_event API.
+//
+//     "time_shift": <decimal integer>,
+//         time_shift field of the Linux perf_event_mmap_page struct available when
+//         cap_usr_time is set. Used in TSC to nanosecond conversion calculation defined
+//         by the Linux perf_event API.
+//
+//     "time_zero": <decimal integer>,
+//         time_zero field of the Linux perf_event_mmap_page struct available when
+//         cap_usr_time_zero is set. Used in TSC to nanosecond conversion calculation defined
+//         by the Linux perf_event API.
+//   }
+//
+//  Notes:
+//   - See https://en.wikipedia.org/wiki/Time_Stamp_Counter for information on the timestamp counter (TSC).
+//   - "tsc_conversion" optionally represents the information for converting the timestamp counter to the
+//     number of nanoseconds since its reset.
+//   - "time_mult", "time_shift" and "time_zero" are the three values needed to convert TSC to nanoseconds defined by
+//     the Linux perf_event API when cap_user_time and cap_user_time_zero are set. See the documentation of time_zero in
+//     https://man7.org/linux/man-pages/man2/perf_event_open.2.html for the conversion calculation.
+//
 //----------------------------------------------------------------------
 
 send packet: jLLDBTraceGetState:{"type":<type>}]
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to