[Lldb-commits] [lldb] ff15efc - [trace][intelpt] Support system-wide tracing [16] - Create threads automatically from context switch data in the post-mortem case

Walter Erquinigo via lldb-commits lldb-commits at lists.llvm.org
Thu Jun 16 11:23:18 PDT 2022


Author: Walter Erquinigo
Date: 2022-06-16T11:23:02-07:00
New Revision: ff15efc1a701a8e76242ca2a105b5adf7d68e980

URL: https://github.com/llvm/llvm-project/commit/ff15efc1a701a8e76242ca2a105b5adf7d68e980
DIFF: https://github.com/llvm/llvm-project/commit/ff15efc1a701a8e76242ca2a105b5adf7d68e980.diff

LOG: [trace][intelpt] Support system-wide tracing [16] - Create threads automatically from context switch data in the post-mortem case

For some context, The context switch data contains information of which threads were
executed by each traced process, therefore it's not necessary to specify
them in the trace file.

So this diffs adds support for that automatic feature. Eventually we
could include it to live processes as well.

Differential Revision: https://reviews.llvm.org/D127001

Added: 
    lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json

Modified: 
    lldb/include/lldb/Target/Trace.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
    lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
    lldb/source/Target/Trace.cpp
    lldb/test/API/commands/trace/TestTraceLoad.py

Removed: 
    


################################################################################
diff  --git a/lldb/include/lldb/Target/Trace.h b/lldb/include/lldb/Target/Trace.h
index 89e129079393..67585c22511f 100644
--- a/lldb/include/lldb/Target/Trace.h
+++ b/lldb/include/lldb/Target/Trace.h
@@ -496,6 +496,10 @@ class Trace : public PluginInterface,
   DoRefreshLiveProcessState(TraceGetStateResponse state,
                             llvm::StringRef json_response) = 0;
 
+  /// Return the list of processes traced by this instance. None of the returned
+  /// pointers are invalid.
+  std::vector<Process *> GetTracedProcesses() const;
+
   /// Method to be invoked by the plug-in to refresh the live process state. It
   /// will invoked DoRefreshLiveProcessState at some point, which should be
   /// implemented by the plug-in for custom state handling.

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
index 59454a0320be..af95c20117cb 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
@@ -75,6 +75,7 @@ Expected<TraceSP> TraceIntelPT::CreateInstanceForLiveProcess(Process &process) {
 }
 
 TraceIntelPT::TraceIntelPT(JSONTraceSession &session,
+                           const FileSpec &session_file_dir,
                            ArrayRef<ProcessSP> traced_processes,
                            ArrayRef<ThreadPostMortemTraceSP> traced_threads)
     : Trace(traced_processes, session.GetCoreIds()),
@@ -92,11 +93,19 @@ TraceIntelPT::TraceIntelPT(JSONTraceSession &session,
     std::vector<core_id_t> cores;
 
     for (const JSONCore &core : *session.cores) {
+      FileSpec trace_buffer(core.trace_buffer);
+      if (trace_buffer.IsRelative())
+        trace_buffer.PrependPathComponent(session_file_dir);
+
       SetPostMortemCoreDataFile(core.core_id, IntelPTDataKinds::kTraceBuffer,
-                                FileSpec(core.trace_buffer));
+                                trace_buffer);
+
+      FileSpec context_switch(core.context_switch_trace);
+      if (context_switch.IsRelative())
+        context_switch.PrependPathComponent(session_file_dir);
       SetPostMortemCoreDataFile(core.core_id,
                                 IntelPTDataKinds::kPerfContextSwitchTrace,
-                                FileSpec(core.context_switch_trace));
+                                context_switch);
       cores.push_back(core.core_id);
     }
 
@@ -473,3 +482,45 @@ Error TraceIntelPT::OnThreadBufferRead(lldb::tid_t tid,
 }
 
 TaskTimer &TraceIntelPT::GetTimer() { return m_task_timer; }
+
+Error TraceIntelPT::CreateThreadsFromContextSwitches() {
+  DenseMap<lldb::pid_t, DenseSet<lldb::tid_t>> pids_to_tids;
+
+  for (core_id_t core_id : GetTracedCores()) {
+    Error err = OnCoreBinaryDataRead(
+        core_id, IntelPTDataKinds::kPerfContextSwitchTrace,
+        [&](ArrayRef<uint8_t> data) -> Error {
+          Expected<std::vector<ThreadContinuousExecution>> executions =
+              DecodePerfContextSwitchTrace(data, core_id, *m_tsc_conversion);
+          if (!executions)
+            return executions.takeError();
+          for (const ThreadContinuousExecution &execution : *executions)
+            pids_to_tids[execution.pid].insert(execution.tid);
+          return Error::success();
+        });
+    if (err)
+      return err;
+  }
+
+  DenseMap<lldb::pid_t, Process *> processes;
+  for (Process *proc : GetTracedProcesses())
+    processes.try_emplace(proc->GetID(), proc);
+
+  for (const auto &pid_to_tids : pids_to_tids) {
+    lldb::pid_t pid = pid_to_tids.first;
+    auto it = processes.find(pid);
+    if (it == processes.end())
+      continue;
+
+    Process &process = *it->second;
+    ThreadList &thread_list = process.GetThreadList();
+
+    for (lldb::tid_t tid : pid_to_tids.second) {
+      if (!thread_list.FindThreadByID(tid)) {
+        thread_list.AddThread(std::make_shared<ThreadPostMortemTrace>(
+            process, tid, /*trace_file*/ None));
+      }
+    }
+  }
+  return Error::success();
+}

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
index 70b3674bbd32..a0db4aebe143 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
@@ -163,6 +163,15 @@ class TraceIntelPT : public Trace {
 private:
   friend class TraceIntelPTSessionFileParser;
 
+  /// Create post-mortem threads associated with the processes traced by this
+  /// instance using the context switch traces.
+  ///
+  /// This does nothing if the threads already exist.
+  ///
+  /// \return
+  ///   An \a llvm::Error in case of failures.
+  llvm::Error CreateThreadsFromContextSwitches();
+
   llvm::Expected<pt_cpu> GetCPUInfoForLiveProcess();
 
   /// Postmortem trace constructor
@@ -176,7 +185,7 @@ class TraceIntelPT : public Trace {
   /// \param[in] trace_threads
   ///     The threads traced in the live session. They must belong to the
   ///     processes mentioned above.
-  TraceIntelPT(JSONTraceSession &session,
+  TraceIntelPT(JSONTraceSession &session, const FileSpec &session_file_dir,
                llvm::ArrayRef<lldb::ProcessSP> traced_processes,
                llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads);
 
@@ -209,6 +218,8 @@ class TraceIntelPT : public Trace {
   llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
 };
 
+using TraceIntelPTSP = std::shared_ptr<TraceIntelPT>;
+
 } // namespace trace_intel_pt
 } // namespace lldb_private
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
index 85e04ff6ec6a..50ef4b4f8520 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.cpp
@@ -164,6 +164,10 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
       "triple"?: string,
           // Optional clang/llvm target triple.
       "threads": [
+          // A list of known threads for the given process. When context switch
+          // data is provided, LLDB will automatically create threads for the
+          // this process whenever it finds new threads when traversing the
+          // context switches.
         {
           "tid": integer,
           "traceBuffer"?: string
@@ -205,6 +209,10 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
     "timeShift": integer,
     "timeZero": integer,
   }
+  "dontCreateThreadsFromContextSwitches"?: boolean,
+    // If this is true, then the automatic creation of threads from context switch
+    // data is disabled, and thus only the threads provided in the "processes.threads"
+    // section will be created.
 }
 
 Notes:
@@ -217,7 +225,7 @@ StringRef TraceIntelPTSessionFileParser::GetSchema() {
   return schema;
 }
 
-TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
+Expected<TraceSP> TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
     JSONTraceSession &session, std::vector<ParsedProcess> &parsed_processes) {
   std::vector<ThreadPostMortemTraceSP> threads;
   std::vector<ProcessSP> processes;
@@ -227,10 +235,16 @@ TraceSP TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
                    parsed_process.threads.end());
   }
 
-  TraceSP trace_instance(new TraceIntelPT(session, processes, threads));
+  TraceIntelPTSP trace_instance(new TraceIntelPT(
+      session, FileSpec(m_session_file_dir), processes, threads));
   for (const ParsedProcess &parsed_process : parsed_processes)
     parsed_process.target_sp->SetTrace(trace_instance);
 
+  if (session.cores) {
+    if (Error err = trace_instance->CreateThreadsFromContextSwitches())
+      return std::move(err);
+  }
+
   return trace_instance;
 }
 

diff  --git a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
index 9a54cc1854d1..04d981178954 100644
--- a/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
+++ b/lldb/source/Plugins/Trace/intel-pt/TraceIntelPTSessionFileParser.h
@@ -52,7 +52,7 @@ class TraceIntelPTSessionFileParser {
   ///   errors, return a null pointer.
   llvm::Expected<lldb::TraceSP> Parse();
 
-  lldb::TraceSP
+  llvm::Expected<lldb::TraceSP>
   CreateTraceIntelPTInstance(JSONTraceSession &session,
                              std::vector<ParsedProcess> &parsed_processes);
 
@@ -64,6 +64,11 @@ class TraceIntelPTSessionFileParser {
   lldb::ThreadPostMortemTraceSP ParseThread(lldb::ProcessSP &process_sp,
                                             const JSONThread &thread);
 
+  /// Create the corresponding Threads and Process objects given the JSON
+  /// process definition.
+  ///
+  /// \param[in] process
+  ///   The JSON process definition
   llvm::Expected<ParsedProcess> ParseProcess(const JSONProcess &process);
 
   llvm::Error ParseModule(lldb::TargetSP &target_sp, const JSONModule &module);
@@ -82,6 +87,8 @@ class TraceIntelPTSessionFileParser {
   llvm::Error CreateJSONError(llvm::json::Path::Root &root,
                               const llvm::json::Value &value);
 
+  /// Create the corresponding Process, Thread and Module objects given this
+  /// session file.
   llvm::Expected<std::vector<ParsedProcess>>
   ParseSessionFile(const JSONTraceSession &session);
 

diff  --git a/lldb/source/Target/Trace.cpp b/lldb/source/Target/Trace.cpp
index 3112060a6301..b6c84de35245 100644
--- a/lldb/source/Target/Trace.cpp
+++ b/lldb/source/Target/Trace.cpp
@@ -449,3 +449,14 @@ ArrayRef<lldb::core_id_t> Trace::GetTracedCores() {
     return *m_cores;
   return {};
 }
+
+std::vector<Process *> Trace::GetTracedProcesses() const {
+  std::vector<Process *> processes;
+
+  for (Process *proc : m_postmortem_processes)
+    processes.push_back(proc);
+
+  if (m_live_process)
+    processes.push_back(m_live_process);
+  return processes;
+}

diff  --git a/lldb/test/API/commands/trace/TestTraceLoad.py b/lldb/test/API/commands/trace/TestTraceLoad.py
index be91a4d15a90..352ccf9e201f 100644
--- a/lldb/test/API/commands/trace/TestTraceLoad.py
+++ b/lldb/test/API/commands/trace/TestTraceLoad.py
@@ -21,6 +21,18 @@ def testLoadMultiCoreTrace(self):
           substrs=["67910: [tsc=0x008fb5211bfdf270] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
                    "m.out`bar() + 26 at multi_thread.cpp:20:6"])
 
+    def testLoadMultiCoreTraceWithMissingThreads(self):
+        src_dir = self.getSourceDir()
+        trace_definition_file = os.path.join(src_dir, "intelpt-multi-core-trace", "trace_missing_threads.json")
+        self.expect("trace load -v " + trace_definition_file, substrs=["intel-pt"])
+        self.expect("thread trace dump instructions 3 -t",
+          substrs=["19521: [tsc=0x008fb5211c143fd8] error: expected tracing enabled event",
+                   "m.out`foo() + 65 at multi_thread.cpp:12:21",
+                   "19520: [tsc=0x008fb5211bfbc69e] 0x0000000000400ba7    jg     0x400bb3"])
+        self.expect("thread trace dump instructions 2 -t",
+          substrs=["67910: [tsc=0x008fb5211bfdf270] 0x0000000000400bd7    addl   $0x1, -0x4(%rbp)",
+                   "m.out`bar() + 26 at multi_thread.cpp:20:6"])
+
     def testLoadTrace(self):
         src_dir = self.getSourceDir()
         trace_definition_file = os.path.join(src_dir, "intelpt-trace", "trace.json")

diff  --git a/lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json b/lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json
new file mode 100644
index 000000000000..e03c8e41ec9a
--- /dev/null
+++ b/lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json
@@ -0,0 +1,44 @@
+{
+  "cores": [
+    {
+      "contextSwitchTrace": "/tmp/trace8/cores/45.perf_context_switch_trace",
+      "coreId": 45,
+      "traceBuffer": "/tmp/trace8/cores/45.intelpt_trace"
+    },
+    {
+      "contextSwitchTrace": "/tmp/trace8/cores/51.perf_context_switch_trace",
+      "coreId": 51,
+      "traceBuffer": "/tmp/trace8/cores/51.intelpt_trace"
+    }
+  ],
+  "cpuInfo": {
+    "family": 6,
+    "model": 85,
+    "stepping": 4,
+    "vendor": "GenuineIntel"
+  },
+  "processes": [
+    {
+      "modules": [
+        {
+          "file": "modules/m.out",
+          "systemPath": "/tmp/m.out",
+          "loadAddress": 4194304,
+          "uuid": "AEFB0D59-233F-80FF-6D3C-4DED498534CF-11017B3B"
+        }
+      ],
+      "pid": 3497234,
+      "threads": [
+        {
+          "tid": 3497234
+        }
+      ]
+    }
+  ],
+  "tscPerfZeroConversion": {
+    "timeMult": 1076264588,
+    "timeShift": 31,
+    "timeZero": 18433473881008870804
+  },
+  "type": "intel-pt"
+}


        


More information about the lldb-commits mailing list