wallace created this revision.
wallace added a reviewer: jj10306.
Herald added a project: All.
wallace requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

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.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D127001

Files:
  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
  
lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json

Index: lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json
===================================================================
--- /dev/null
+++ 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"
+}
Index: lldb/test/API/commands/trace/TestTraceLoad.py
===================================================================
--- lldb/test/API/commands/trace/TestTraceLoad.py
+++ lldb/test/API/commands/trace/TestTraceLoad.py
@@ -21,6 +21,18 @@
           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")
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -449,3 +449,14 @@
     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;
+}
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
@@ -52,7 +52,7 @@
   ///   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 @@
   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 @@
   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);
 
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
@@ -164,6 +164,10 @@
       "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 @@
     "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 @@
   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,15 @@
                    parsed_process.threads.end());
   }
 
-  TraceSP trace_instance(new TraceIntelPT(session, processes, threads));
+  TraceIntelPTSP trace_instance(new TraceIntelPT(session, 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;
 }
 
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
@@ -163,6 +163,15 @@
 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
@@ -209,6 +218,8 @@
   llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
 };
 
+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
@@ -473,3 +473,45 @@
 }
 
 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();
+}
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -496,6 +496,10 @@
   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.
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to