This revision was landed with ongoing or failed builds.
This revision was automatically updated to reflect the committed changes.
Closed by commit rG03cc58ff2a7a: [trace][intelpt] Support system-wide tracing 
[17] - Some improvements (authored by Walter Erquinigo <wall...@fb.com>).

Repository:
  rG LLVM Github Monorepo

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

https://reviews.llvm.org/D127456

Files:
  lldb/include/lldb/Target/Trace.h
  lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
  lldb/source/Plugins/Process/Linux/IntelPTCollector.h
  lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
  lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
  lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.cpp
  lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.h
  lldb/source/Plugins/Process/Linux/IntelPTProcessTrace.h
  lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
  lldb/source/Plugins/Process/Linux/Perf.cpp
  lldb/source/Plugins/Process/Linux/Perf.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPT.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTJSONStructs.h
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
  lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.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/test/API/commands/trace/intelpt-multi-core-trace/trace.json
  
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
===================================================================
--- lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json
+++ lldb/test/API/commands/trace/intelpt-multi-core-trace/trace_missing_threads.json
@@ -1,14 +1,14 @@
 {
   "cores": [
     {
-      "contextSwitchTrace": "/tmp/trace8/cores/45.perf_context_switch_trace",
+      "contextSwitchTrace": "cores/45.perf_context_switch_trace",
       "coreId": 45,
-      "traceBuffer": "/tmp/trace8/cores/45.intelpt_trace"
+      "traceBuffer": "cores/45.intelpt_trace"
     },
     {
-      "contextSwitchTrace": "/tmp/trace8/cores/51.perf_context_switch_trace",
+      "contextSwitchTrace": "cores/51.perf_context_switch_trace",
       "coreId": 51,
-      "traceBuffer": "/tmp/trace8/cores/51.intelpt_trace"
+      "traceBuffer": "cores/51.intelpt_trace"
     }
   ],
   "cpuInfo": {
Index: lldb/test/API/commands/trace/intelpt-multi-core-trace/trace.json
===================================================================
--- lldb/test/API/commands/trace/intelpt-multi-core-trace/trace.json
+++ lldb/test/API/commands/trace/intelpt-multi-core-trace/trace.json
@@ -1,14 +1,14 @@
 {
   "cores": [
     {
-      "contextSwitchTrace": "/tmp/trace8/cores/45.perf_context_switch_trace",
+      "contextSwitchTrace": "cores/45.perf_context_switch_trace",
       "coreId": 45,
-      "traceBuffer": "/tmp/trace8/cores/45.intelpt_trace"
+      "traceBuffer": "cores/45.intelpt_trace"
     },
     {
-      "contextSwitchTrace": "/tmp/trace8/cores/51.perf_context_switch_trace",
+      "contextSwitchTrace": "cores/51.perf_context_switch_trace",
       "coreId": 51,
-      "traceBuffer": "/tmp/trace8/cores/51.intelpt_trace"
+      "traceBuffer": "cores/51.intelpt_trace"
     }
   ],
   "cpuInfo": {
Index: lldb/source/Target/Trace.cpp
===================================================================
--- lldb/source/Target/Trace.cpp
+++ lldb/source/Target/Trace.cpp
@@ -116,8 +116,9 @@
 
 Optional<uint64_t> Trace::GetLiveThreadBinaryDataSize(lldb::tid_t tid,
                                                       llvm::StringRef kind) {
-  auto it = m_live_thread_data.find(tid);
-  if (it == m_live_thread_data.end())
+  Storage &storage = GetUpdatedStorage();
+  auto it = storage.live_thread_data.find(tid);
+  if (it == storage.live_thread_data.end())
     return None;
   std::unordered_map<std::string, uint64_t> &single_thread_data = it->second;
   auto single_thread_data_it = single_thread_data.find(kind.str());
@@ -128,8 +129,9 @@
 
 Optional<uint64_t> Trace::GetLiveCoreBinaryDataSize(lldb::core_id_t core_id,
                                                     llvm::StringRef kind) {
-  auto it = m_live_core_data_sizes.find(core_id);
-  if (it == m_live_core_data_sizes.end())
+  Storage &storage = GetUpdatedStorage();
+  auto it = storage.live_core_data_sizes.find(core_id);
+  if (it == storage.live_core_data_sizes.end())
     return None;
   std::unordered_map<std::string, uint64_t> &single_core_data = it->second;
   auto single_thread_data_it = single_core_data.find(kind.str());
@@ -139,8 +141,9 @@
 }
 
 Optional<uint64_t> Trace::GetLiveProcessBinaryDataSize(llvm::StringRef kind) {
-  auto data_it = m_live_process_data.find(kind.str());
-  if (data_it == m_live_process_data.end())
+  Storage &storage = GetUpdatedStorage();
+  auto data_it = storage.live_process_data.find(kind.str());
+  if (data_it == storage.live_process_data.end())
     return None;
   return data_it->second;
 }
@@ -197,6 +200,11 @@
   return m_live_process->TraceGetBinaryData(request);
 }
 
+Trace::Storage &Trace::GetUpdatedStorage() {
+  RefreshLiveProcessState();
+  return m_storage;
+}
+
 const char *Trace::RefreshLiveProcessState() {
   if (!m_live_process)
     return nullptr;
@@ -209,15 +217,11 @@
   LLDB_LOG(log, "Trace::RefreshLiveProcessState invoked");
 
   m_stop_id = new_stop_id;
-  m_live_thread_data.clear();
-  m_live_refresh_error.reset();
-  m_live_core_data_sizes.clear();
-  m_live_core_data.clear();
-  m_cores.reset();
+  m_storage = Trace::Storage();
 
   auto HandleError = [&](Error &&err) -> const char * {
-    m_live_refresh_error = toString(std::move(err));
-    return m_live_refresh_error->c_str();
+    m_storage.live_refresh_error = toString(std::move(err));
+    return m_storage.live_refresh_error->c_str();
   };
 
   Expected<std::string> json_string = GetLiveProcessState();
@@ -237,18 +241,19 @@
   for (const TraceThreadState &thread_state :
        live_process_state->traced_threads) {
     for (const TraceBinaryData &item : thread_state.binary_data)
-      m_live_thread_data[thread_state.tid][item.kind] = item.size;
+      m_storage.live_thread_data[thread_state.tid][item.kind] = item.size;
   }
 
   LLDB_LOG(log, "== Found {0} threads being traced",
            live_process_state->traced_threads.size());
 
   if (live_process_state->cores) {
-    m_cores.emplace();
+    m_storage.cores.emplace();
     for (const TraceCoreState &core_state : *live_process_state->cores) {
-      m_cores->push_back(core_state.core_id);
+      m_storage.cores->push_back(core_state.core_id);
       for (const TraceBinaryData &item : core_state.binary_data)
-        m_live_core_data_sizes[core_state.core_id][item.kind] = item.size;
+        m_storage.live_core_data_sizes[core_state.core_id][item.kind] =
+            item.size;
     }
     LLDB_LOG(log, "== Found {0} cpu cores being traced",
             live_process_state->cores->size());
@@ -256,7 +261,7 @@
 
 
   for (const TraceBinaryData &item : live_process_state->process_binary_data)
-    m_live_process_data[item.kind] = item.size;
+    m_storage.live_process_data[item.kind] = item.size;
 
   if (Error err = DoRefreshLiveProcessState(std::move(*live_process_state),
                                             *json_string))
@@ -268,14 +273,14 @@
 Trace::Trace(ArrayRef<ProcessSP> postmortem_processes,
              Optional<std::vector<lldb::core_id_t>> postmortem_cores) {
   for (ProcessSP process_sp : postmortem_processes)
-    m_postmortem_processes.push_back(process_sp.get());
-  m_cores = postmortem_cores;
+    m_storage.postmortem_processes.push_back(process_sp.get());
+  m_storage.cores = postmortem_cores;
 }
 
 Process *Trace::GetLiveProcess() { return m_live_process; }
 
 ArrayRef<Process *> Trace::GetPostMortemProcesses() {
-  return m_postmortem_processes;
+  return m_storage.postmortem_processes;
 }
 
 std::vector<Process *> Trace::GetAllProcesses() {
@@ -298,8 +303,9 @@
                 tid, kind));
   };
 
-  auto it = m_postmortem_thread_data.find(tid);
-  if (it == m_postmortem_thread_data.end())
+  Storage &storage = GetUpdatedStorage();
+  auto it = storage.postmortem_thread_data.find(tid);
+  if (it == storage.postmortem_thread_data.end())
     return NotFoundError();
 
   std::unordered_map<std::string, FileSpec> &data_kind_to_file_spec_map =
@@ -320,8 +326,9 @@
                 core_id, kind));
   };
 
-  auto it = m_postmortem_core_data.find(core_id);
-  if (it == m_postmortem_core_data.end())
+  Storage &storage = GetUpdatedStorage();
+  auto it = storage.postmortem_core_data.find(core_id);
+  if (it == storage.postmortem_core_data.end())
     return NotFoundError();
 
   std::unordered_map<std::string, FileSpec> &data_kind_to_file_spec_map =
@@ -334,13 +341,15 @@
 
 void Trace::SetPostMortemThreadDataFile(lldb::tid_t tid, llvm::StringRef kind,
                                         FileSpec file_spec) {
-  m_postmortem_thread_data[tid][kind.str()] = file_spec;
+  Storage &storage = GetUpdatedStorage();
+  storage.postmortem_thread_data[tid][kind.str()] = file_spec;
 }
 
 void Trace::SetPostMortemCoreDataFile(lldb::core_id_t core_id,
                                       llvm::StringRef kind,
                                       FileSpec file_spec) {
-  m_postmortem_core_data[core_id][kind.str()] = file_spec;
+  Storage &storage = GetUpdatedStorage();
+  storage.postmortem_core_data[core_id][kind.str()] = file_spec;
 }
 
 llvm::Error
@@ -355,8 +364,9 @@
 llvm::Error Trace::OnLiveCoreBinaryDataRead(lldb::core_id_t core_id,
                                             llvm::StringRef kind,
                                             OnBinaryDataReadCallback callback) {
-  auto core_data_entries = m_live_core_data.find(core_id);
-  if (core_data_entries != m_live_core_data.end()) {
+  Storage &storage = GetUpdatedStorage();
+  auto core_data_entries = storage.live_core_data.find(core_id);
+  if (core_data_entries != storage.live_core_data.end()) {
     auto core_data = core_data_entries->second.find(kind.str());
     if (core_data != core_data_entries->second.end())
       return callback(core_data->second);
@@ -365,7 +375,8 @@
   Expected<std::vector<uint8_t>> data = GetLiveCoreBinaryData(core_id, kind);
   if (!data)
     return data.takeError();
-  auto it = m_live_core_data[core_id].insert({kind.str(), std::move(*data)});
+  auto it =
+      storage.live_core_data[core_id].insert({kind.str(), std::move(*data)});
   return callback(it.first->second);
 }
 
@@ -374,7 +385,9 @@
   ErrorOr<std::unique_ptr<MemoryBuffer>> trace_or_error =
       MemoryBuffer::getFile(file.GetPath());
   if (std::error_code err = trace_or_error.getError())
-    return errorCodeToError(err);
+    return createStringError(
+        inconvertibleErrorCode(), "Failed fetching trace-related file %s. %s",
+        file.GetCString(), toString(errorCodeToError(err)).c_str());
 
   MemoryBuffer &data = **trace_or_error;
   ArrayRef<uint8_t> array_ref(
@@ -404,7 +417,6 @@
 
 llvm::Error Trace::OnThreadBinaryDataRead(lldb::tid_t tid, llvm::StringRef kind,
                                           OnBinaryDataReadCallback callback) {
-  RefreshLiveProcessState();
   if (m_live_process)
     return OnLiveThreadBinaryDataRead(tid, kind, callback);
   else
@@ -412,14 +424,16 @@
 }
 
 llvm::Error
-Trace::OnCoresBinaryDataRead(const std::set<lldb::core_id_t> core_ids,
-                             llvm::StringRef kind,
-                             OnCoresBinaryDataReadCallback callback) {
+Trace::OnAllCoresBinaryDataRead(llvm::StringRef kind,
+                                OnCoresBinaryDataReadCallback callback) {
   DenseMap<core_id_t, ArrayRef<uint8_t>> buffers;
+  Storage &storage = GetUpdatedStorage();
+  if (!storage.cores)
+    return Error::success();
 
-  std::function<Error(std::set<core_id_t>::iterator)> process_core =
-      [&](std::set<core_id_t>::iterator core_id) -> Error {
-    if (core_id == core_ids.end())
+  std::function<Error(std::vector<core_id_t>::iterator)> process_core =
+      [&](std::vector<core_id_t>::iterator core_id) -> Error {
+    if (core_id == storage.cores->end())
       return callback(buffers);
 
     return OnCoreBinaryDataRead(*core_id, kind,
@@ -430,13 +444,12 @@
                                   return process_core(next_id);
                                 });
   };
-  return process_core(core_ids.begin());
+  return process_core(storage.cores->begin());
 }
 
 llvm::Error Trace::OnCoreBinaryDataRead(lldb::core_id_t core_id,
                                         llvm::StringRef kind,
                                         OnBinaryDataReadCallback callback) {
-  RefreshLiveProcessState();
   if (m_live_process)
     return OnLiveCoreBinaryDataRead(core_id, kind, callback);
   else
@@ -444,16 +457,17 @@
 }
 
 ArrayRef<lldb::core_id_t> Trace::GetTracedCores() {
-  RefreshLiveProcessState();
-  if (m_cores)
-    return *m_cores;
+  Storage &storage = GetUpdatedStorage();
+  if (storage.cores)
+    return *storage.cores;
   return {};
 }
 
-std::vector<Process *> Trace::GetTracedProcesses() const {
+std::vector<Process *> Trace::GetTracedProcesses() {
   std::vector<Process *> processes;
+  Storage &storage = GetUpdatedStorage();
 
-  for (Process *proc : m_postmortem_processes)
+  for (Process *proc : storage.postmortem_processes)
     processes.push_back(proc);
 
   if (m_live_process)
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
@@ -262,7 +262,7 @@
     return json_modules.takeError();
 
   return JSONProcess{
-      static_cast<int64_t>(process.GetID()),
+      process.GetID(),
       process.GetTarget().GetArchitecture().GetTriple().getTriple(),
       json_threads.get(), json_modules.get()};
 }
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
@@ -57,9 +57,8 @@
                              std::vector<ParsedProcess> &parsed_processes);
 
 private:
-  /// Resolve non-absolute paths relative to the session file folder. It
-  /// modifies the given file_spec.
-  void NormalizePath(lldb_private::FileSpec &file_spec);
+  /// Resolve non-absolute paths relative to the session file folder.
+  FileSpec NormalizePath(const std::string &path);
 
   lldb::ThreadPostMortemTraceSP ParseThread(lldb::ProcessSP &process_sp,
                                             const JSONThread &thread);
@@ -92,6 +91,19 @@
   llvm::Expected<std::vector<ParsedProcess>>
   ParseSessionFile(const JSONTraceSession &session);
 
+  /// When applicable, augment the list of threads in the session file by
+  /// inspecting the context switch trace. This only applies for threads of
+  /// processes already specified in this session file.
+  ///
+  /// \return
+  ///   An \a llvm::Error in case if failures, or \a llvm::Error::success
+  ///   otherwise.
+  llvm::Error AugmentThreadsFromContextSwitches(JSONTraceSession &session);
+
+  /// Modifiy the session file by normalizing all the paths relative to the
+  /// session file directory.
+  void NormalizeAllPaths(JSONTraceSession &session);
+
   Debugger &m_debugger;
   const llvm::json::Value &m_trace_session_file;
   std::string m_session_file_dir;
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
@@ -22,39 +22,45 @@
 using namespace lldb_private::trace_intel_pt;
 using namespace llvm;
 
-void TraceIntelPTSessionFileParser::NormalizePath(
-    lldb_private::FileSpec &file_spec) {
+FileSpec TraceIntelPTSessionFileParser::NormalizePath(const std::string &path) {
+  FileSpec file_spec(path);
   if (file_spec.IsRelative())
     file_spec.PrependPathComponent(m_session_file_dir);
+  return file_spec;
 }
 
 Error TraceIntelPTSessionFileParser::ParseModule(lldb::TargetSP &target_sp,
                                                  const JSONModule &module) {
-  FileSpec system_file_spec(module.system_path);
-  NormalizePath(system_file_spec);
+  auto do_parse = [&]() -> Error {
+    FileSpec system_file_spec(module.system_path);
 
-  FileSpec local_file_spec(module.file.hasValue() ? *module.file
-                                                  : module.system_path);
-  NormalizePath(local_file_spec);
+    FileSpec local_file_spec(module.file.hasValue() ? *module.file
+                                                    : module.system_path);
 
-  ModuleSpec module_spec;
-  module_spec.GetFileSpec() = local_file_spec;
-  module_spec.GetPlatformFileSpec() = system_file_spec;
+    ModuleSpec module_spec;
+    module_spec.GetFileSpec() = local_file_spec;
+    module_spec.GetPlatformFileSpec() = system_file_spec;
 
-  if (module.uuid.hasValue())
-    module_spec.GetUUID().SetFromStringRef(*module.uuid);
+    if (module.uuid.hasValue())
+      module_spec.GetUUID().SetFromStringRef(*module.uuid);
 
-  Status error;
-  ModuleSP module_sp =
-      target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error);
+    Status error;
+    ModuleSP module_sp =
+        target_sp->GetOrCreateModule(module_spec, /*notify*/ false, &error);
 
-  if (error.Fail())
-    return error.ToError();
+    if (error.Fail())
+      return error.ToError();
 
-  bool load_addr_changed = false;
-  module_sp->SetLoadAddress(*target_sp, module.load_address, false,
-                            load_addr_changed);
-  return llvm::Error::success();
+    bool load_addr_changed = false;
+    module_sp->SetLoadAddress(*target_sp, module.load_address, false,
+                              load_addr_changed);
+    return Error::success();
+  };
+  if (Error err = do_parse())
+    return createStringError(
+        inconvertibleErrorCode(), "Error when parsing module %s. %s",
+        module.system_path.c_str(), toString(std::move(err)).c_str());
+  return Error::success();
 }
 
 Error TraceIntelPTSessionFileParser::CreateJSONError(json::Path::Root &root,
@@ -73,10 +79,8 @@
   lldb::tid_t tid = static_cast<lldb::tid_t>(thread.tid);
 
   Optional<FileSpec> trace_file;
-  if (thread.trace_buffer) {
-    trace_file.emplace(*thread.trace_buffer);
-    NormalizePath(*trace_file);
-  }
+  if (thread.trace_buffer)
+    trace_file = FileSpec(*thread.trace_buffer);
 
   ThreadPostMortemTraceSP thread_sp =
       std::make_shared<ThreadPostMortemTrace>(*process_sp, tid, trace_file);
@@ -225,6 +229,54 @@
   return schema;
 }
 
+Error TraceIntelPTSessionFileParser::AugmentThreadsFromContextSwitches(
+    JSONTraceSession &session) {
+  if (!session.cores)
+    return Error::success();
+
+  if (!session.tsc_perf_zero_conversion)
+    return createStringError(inconvertibleErrorCode(),
+                             "TSC to nanos conversion values are needed when "
+                             "context switch information is provided.");
+
+  DenseMap<lldb::pid_t, JSONProcess *> indexed_processes;
+  DenseMap<JSONProcess *, DenseSet<tid_t>> indexed_threads;
+
+  for (JSONProcess &process : session.processes) {
+    indexed_processes[process.pid] = &process;
+    for (JSONThread &thread : process.threads)
+      indexed_threads[&process].insert(thread.tid);
+  }
+
+  auto on_thread_seen = [&](lldb::pid_t pid, tid_t tid) {
+    auto proc = indexed_processes.find(pid);
+    if (proc == indexed_processes.end())
+      return;
+    if (indexed_threads[proc->second].count(tid))
+      return;
+    indexed_threads[proc->second].insert(tid);
+    proc->second->threads.push_back({tid, /*trace_buffer=*/None});
+  };
+
+  for (const JSONCore &core : *session.cores) {
+    Error err = Trace::OnDataFileRead(
+        FileSpec(core.context_switch_trace),
+        [&](ArrayRef<uint8_t> data) -> Error {
+          Expected<std::vector<ThreadContinuousExecution>> executions =
+              DecodePerfContextSwitchTrace(data, core.core_id,
+                                           *session.tsc_perf_zero_conversion);
+          if (!executions)
+            return executions.takeError();
+          for (const ThreadContinuousExecution &execution : *executions)
+            on_thread_seen(execution.pid, execution.tid);
+          return Error::success();
+        });
+    if (err)
+      return err;
+  }
+  return Error::success();
+}
+
 Expected<TraceSP> TraceIntelPTSessionFileParser::CreateTraceIntelPTInstance(
     JSONTraceSession &session, std::vector<ParsedProcess> &parsed_processes) {
   std::vector<ThreadPostMortemTraceSP> threads;
@@ -235,17 +287,33 @@
                    parsed_process.threads.end());
   }
 
-  TraceIntelPTSP trace_instance(new TraceIntelPT(
-      session, FileSpec(m_session_file_dir), processes, threads));
+  TraceSP trace_instance(new TraceIntelPT(session, processes, threads));
   for (const ParsedProcess &parsed_process : parsed_processes)
     parsed_process.target_sp->SetTrace(trace_instance);
 
+  return trace_instance;
+}
+
+void TraceIntelPTSessionFileParser::NormalizeAllPaths(
+    JSONTraceSession &session) {
+  for (JSONProcess &process : session.processes) {
+    for (JSONModule &module : process.modules) {
+      module.system_path = NormalizePath(module.system_path).GetPath();
+      if (module.file)
+        module.file = NormalizePath(*module.file).GetPath();
+    }
+    for (JSONThread &thread : process.threads) {
+      if (thread.trace_buffer)
+        thread.trace_buffer = NormalizePath(*thread.trace_buffer).GetPath();
+    }
+  }
   if (session.cores) {
-    if (Error err = trace_instance->CreateThreadsFromContextSwitches())
-      return std::move(err);
+    for (JSONCore &core : *session.cores) {
+      core.context_switch_trace =
+          NormalizePath(core.context_switch_trace).GetPath();
+      core.trace_buffer = NormalizePath(core.trace_buffer).GetPath();
+    }
   }
-
-  return trace_instance;
 }
 
 Expected<TraceSP> TraceIntelPTSessionFileParser::Parse() {
@@ -254,6 +322,11 @@
   if (!fromJSON(m_trace_session_file, session, root))
     return CreateJSONError(root, m_trace_session_file);
 
+  NormalizeAllPaths(session);
+
+  if (Error err = AugmentThreadsFromContextSwitches(session))
+    return std::move(err);
+
   if (Expected<std::vector<ParsedProcess>> parsed_processes =
           ParseSessionFile(session))
     return CreateTraceIntelPTInstance(session, *parsed_processes);
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.h
@@ -24,20 +24,14 @@
 /// to contention or race conditions. Finally, it assumes that a tid is not
 /// repeated twice for two different threads because of the shortness of the
 /// intel pt trace.
+///
+/// This object should be recreated after every stop in the case of live
+/// processes.
 class TraceIntelPTMultiCoreDecoder {
 public:
-  /// \param[in] core_ids
-  ///   The list of cores where the traced programs were running on.
-  ///
-  /// \param[in] tids
-  ///   The full list of tids that were traced.
-  ///
-  /// \param[in] tsc_conversion
-  ///   The conversion values for converting between nanoseconds and TSCs.
-  TraceIntelPTMultiCoreDecoder(
-      TraceIntelPT &trace, llvm::ArrayRef<lldb::core_id_t> core_ids,
-      llvm::ArrayRef<lldb::tid_t> tids,
-      const LinuxPerfZeroTscConversion &tsc_conversion);
+  /// \param[in] TraceIntelPT
+  ///   The trace object to be decoded
+  TraceIntelPTMultiCoreDecoder(TraceIntelPT &trace);
 
   /// \return
   ///   A \a DecodedThread for the \p thread by decoding its instructions on all
@@ -68,16 +62,14 @@
       llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
   CorrelateContextSwitchesAndIntelPtTraces();
 
-  TraceIntelPT &m_trace;
-  std::set<lldb::core_id_t> m_cores;
+  TraceIntelPT *m_trace;
   std::set<lldb::tid_t> m_tids;
   llvm::Optional<
       llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>>
       m_continuous_executions_per_thread;
   llvm::DenseMap<lldb::tid_t, DecodedThreadSP> m_decoded_threads;
-  LinuxPerfZeroTscConversion m_tsc_conversion;
   /// This variable will be non-None if a severe error happened during the setup
-  /// of the decoder.
+  /// of the decoder and we don't want decoding to be reattempted.
   llvm::Optional<std::string> m_setup_error;
   uint64_t m_unattributed_intelpt_subtraces;
 };
Index: lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
===================================================================
--- lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
+++ lldb/source/Plugins/Trace/intel-pt/TraceIntelPTMultiCoreDecoder.cpp
@@ -17,11 +17,14 @@
 using namespace lldb_private::trace_intel_pt;
 using namespace llvm;
 
-TraceIntelPTMultiCoreDecoder::TraceIntelPTMultiCoreDecoder(
-    TraceIntelPT &trace, ArrayRef<core_id_t> core_ids, ArrayRef<tid_t> tids,
-    const LinuxPerfZeroTscConversion &tsc_conversion)
-    : m_trace(trace), m_cores(core_ids.begin(), core_ids.end()),
-      m_tids(tids.begin(), tids.end()), m_tsc_conversion(tsc_conversion) {}
+TraceIntelPTMultiCoreDecoder::TraceIntelPTMultiCoreDecoder(TraceIntelPT &trace)
+    : m_trace(&trace) {
+  for (Process *proc : trace.GetAllProcesses()) {
+    for (ThreadSP thread_sp : proc->GetThreadList().Threads()) {
+      m_tids.insert(thread_sp->GetID());
+    }
+  }
+}
 
 bool TraceIntelPTMultiCoreDecoder::TracesThread(lldb::tid_t tid) const {
   return m_tids.count(tid);
@@ -38,12 +41,12 @@
   DecodedThreadSP decoded_thread_sp =
       std::make_shared<DecodedThread>(thread.shared_from_this());
 
-  Error err = m_trace.OnCoresBinaryDataRead(
-      m_cores, IntelPTDataKinds::kTraceBuffer,
+  Error err = m_trace->OnAllCoresBinaryDataRead(
+      IntelPTDataKinds::kTraceBuffer,
       [&](const DenseMap<core_id_t, ArrayRef<uint8_t>> buffers) -> Error {
         auto it = m_continuous_executions_per_thread->find(thread.GetID());
         if (it != m_continuous_executions_per_thread->end())
-          DecodeTrace(*decoded_thread_sp, m_trace, buffers, it->second);
+          DecodeTrace(*decoded_thread_sp, *m_trace, buffers, it->second);
 
         return Error::success();
       });
@@ -60,14 +63,23 @@
   llvm::DenseMap<lldb::tid_t, std::vector<IntelPTThreadContinousExecution>>
       continuous_executions_per_thread;
 
-  for (core_id_t core_id : m_cores) {
+  Optional<LinuxPerfZeroTscConversion> conv_opt =
+      m_trace->GetPerfZeroTscConversion();
+  if (!conv_opt)
+    return createStringError(
+        inconvertibleErrorCode(),
+        "TSC to nanoseconds conversion values were not found");
+
+  LinuxPerfZeroTscConversion tsc_conversion = *conv_opt;
+
+  for (core_id_t core_id : m_trace->GetTracedCores()) {
     std::vector<IntelPTThreadSubtrace> intel_pt_executions;
 
-    Error err = m_trace.OnCoreBinaryDataRead(
+    Error err = m_trace->OnCoreBinaryDataRead(
         core_id, IntelPTDataKinds::kTraceBuffer,
         [&](ArrayRef<uint8_t> data) -> Error {
           Expected<std::vector<IntelPTThreadSubtrace>> split_trace =
-              SplitTraceInContinuousExecutions(m_trace, data);
+              SplitTraceInContinuousExecutions(*m_trace, data);
           if (!split_trace)
             return split_trace.takeError();
 
@@ -96,11 +108,11 @@
           continuous_executions_per_thread[thread_execution.tid].push_back(
               execution);
         };
-    err = m_trace.OnCoreBinaryDataRead(
+    err = m_trace->OnCoreBinaryDataRead(
         core_id, IntelPTDataKinds::kPerfContextSwitchTrace,
         [&](ArrayRef<uint8_t> data) -> Error {
           Expected<std::vector<ThreadContinuousExecution>> executions =
-              DecodePerfContextSwitchTrace(data, core_id, m_tsc_conversion);
+              DecodePerfContextSwitchTrace(data, core_id, tsc_conversion);
           if (!executions)
             return executions.takeError();
           for (const ThreadContinuousExecution &exec : *executions)
@@ -125,7 +137,7 @@
   if (m_continuous_executions_per_thread)
     return Error::success();
 
-  Error err = m_trace.GetTimer().ForGlobal().TimeTask<Error>(
+  Error err = m_trace->GetTimer().ForGlobal().TimeTask<Error>(
       "Context switch and Intel PT traces correlation", [&]() -> Error {
         if (auto correlation = CorrelateContextSwitchesAndIntelPtTraces()) {
           m_continuous_executions_per_thread.emplace(std::move(*correlation));
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
@@ -30,12 +30,12 @@
 };
 
 struct JSONThread {
-  int64_t tid;
+  uint64_t tid;
   llvm::Optional<std::string> trace_buffer;
 };
 
 struct JSONProcess {
-  int64_t pid;
+  uint64_t pid;
   llvm::Optional<std::string> triple;
   std::vector<JSONThread> threads;
   std::vector<JSONModule> modules;
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,15 +163,6 @@
 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
@@ -185,13 +176,12 @@
   /// \param[in] trace_threads
   ///     The threads traced in the live session. They must belong to the
   ///     processes mentioned above.
-  TraceIntelPT(JSONTraceSession &session, const FileSpec &session_file_dir,
+  TraceIntelPT(JSONTraceSession &session,
                llvm::ArrayRef<lldb::ProcessSP> traced_processes,
                llvm::ArrayRef<lldb::ThreadPostMortemTraceSP> traced_threads);
 
   /// Constructor for live processes
-  TraceIntelPT(Process &live_process)
-      : Trace(live_process), m_thread_decoders(){};
+  TraceIntelPT(Process &live_process) : Trace(live_process){};
 
   /// Decode the trace of the given thread that, i.e. recontruct the traced
   /// instructions.
@@ -205,20 +195,29 @@
   ///     errors are embedded in the instruction list.
   DecodedThreadSP Decode(Thread &thread);
 
+  /// We package all the data that can change upon process stops to make sure
+  /// this contract is very visible.
+  /// This variable should only be accessed directly by constructores or live
+  /// process data refreshers.
+  struct Storage {
+    llvm::Optional<TraceIntelPTMultiCoreDecoder> multicore_decoder;
+    /// These decoders are used for the non-per-core case
+    std::map<lldb::tid_t, std::unique_ptr<ThreadDecoder>> thread_decoders;
+    /// Helper variable used to track long running operations for telemetry.
+    TaskTimer task_timer;
+    /// It is provided by either a session file or a live process to convert TSC
+    /// counters to and from nanos. It might not be available on all hosts.
+    llvm::Optional<LinuxPerfZeroTscConversion> tsc_conversion;
+  } m_storage;
+
   /// It is provided by either a session file or a live process' "cpuInfo"
-  /// binary data.
+  /// binary data. We don't put it in the Storage because this variable doesn't
+  /// change.
   llvm::Optional<pt_cpu> m_cpu_info;
-  llvm::Optional<TraceIntelPTMultiCoreDecoder> m_multicore_decoder;
-  /// These decoders are used for the non-per-core case
-  std::map<lldb::tid_t, std::unique_ptr<ThreadDecoder>> m_thread_decoders;
-  /// Helper variable used to track long running operations for telemetry.
-  TaskTimer m_task_timer;
-  /// It is provided by either a session file or a live process to convert TSC
-  /// counters to and from nanos. It might not be available on all hosts.
-  llvm::Optional<LinuxPerfZeroTscConversion> m_tsc_conversion;
-};
 
-using TraceIntelPTSP = std::shared_ptr<TraceIntelPT>;
+  /// Get the storage after refreshing the data in the case of a live process.
+  Storage &GetUpdatedStorage();
+};
 
 } // 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
@@ -75,37 +75,22 @@
 }
 
 TraceIntelPT::TraceIntelPT(JSONTraceSession &session,
-                           const FileSpec &session_file_dir,
                            ArrayRef<ProcessSP> traced_processes,
                            ArrayRef<ThreadPostMortemTraceSP> traced_threads)
     : Trace(traced_processes, session.GetCoreIds()),
-      m_cpu_info(session.cpu_info),
-      m_tsc_conversion(session.tsc_perf_zero_conversion) {
-  for (const ThreadPostMortemTraceSP &thread : traced_threads) {
-    m_thread_decoders.emplace(thread->GetID(),
-                              std::make_unique<ThreadDecoder>(thread, *this));
-    if (const Optional<FileSpec> &trace_file = thread->GetTraceFile()) {
-      SetPostMortemThreadDataFile(thread->GetID(),
-                                  IntelPTDataKinds::kTraceBuffer, *trace_file);
-    }
-  }
+      m_cpu_info(session.cpu_info) {
+  m_storage.tsc_conversion = session.tsc_perf_zero_conversion;
+
   if (session.cores) {
     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,
-                                trace_buffer);
+                                FileSpec(core.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,
-                                context_switch);
+                                FileSpec(core.context_switch_trace));
       cores.push_back(core.core_id);
     }
 
@@ -114,8 +99,16 @@
       for (const JSONThread &thread : process.threads)
         tids.push_back(thread.tid);
 
-    m_multicore_decoder.emplace(*this, cores, tids,
-                                *session.tsc_perf_zero_conversion);
+    m_storage.multicore_decoder.emplace(*this);
+  } else {
+    for (const ThreadPostMortemTraceSP &thread : traced_threads) {
+      m_storage.thread_decoders.emplace(
+          thread->GetID(), std::make_unique<ThreadDecoder>(thread, *this));
+      if (const Optional<FileSpec> &trace_file = thread->GetTraceFile()) {
+        SetPostMortemThreadDataFile(
+            thread->GetID(), IntelPTDataKinds::kTraceBuffer, *trace_file);
+      }
+    }
   }
 }
 
@@ -125,11 +118,12 @@
         thread.shared_from_this(),
         createStringError(inconvertibleErrorCode(), error));
 
-  if (m_multicore_decoder)
-    return m_multicore_decoder->Decode(thread);
+  Storage &storage = GetUpdatedStorage();
+  if (storage.multicore_decoder)
+    return storage.multicore_decoder->Decode(thread);
 
-  auto it = m_thread_decoders.find(thread.GetID());
-  if (it == m_thread_decoders.end())
+  auto it = storage.thread_decoders.find(thread.GetID());
+  if (it == storage.thread_decoders.end())
     return std::make_shared<DecodedThread>(
         thread.shared_from_this(),
         createStringError(inconvertibleErrorCode(), "thread not traced"));
@@ -141,6 +135,8 @@
 }
 
 void TraceIntelPT::DumpTraceInfo(Thread &thread, Stream &s, bool verbose) {
+  Storage &storage = GetUpdatedStorage();
+
   lldb::tid_t tid = thread.GetID();
   s.Format("\nthread #{0}: tid = {1}", thread.GetIndexID(), thread.GetID());
   if (!IsTraced(tid)) {
@@ -209,12 +205,13 @@
   }
 
   // Multicode decoding stats
-  if (m_multicore_decoder) {
+  if (storage.multicore_decoder) {
     s << "\n  Multi-core decoding:\n";
     s.Format("    Total number of continuous executions found: {0}\n",
-             m_multicore_decoder->GetTotalContinuousExecutionsCount());
-    s.Format("    Number of continuous executions for this thread: {0}\n",
-             m_multicore_decoder->GetNumContinuousExecutionsForThread(tid));
+             storage.multicore_decoder->GetTotalContinuousExecutionsCount());
+    s.Format(
+        "    Number of continuous executions for this thread: {0}\n",
+        storage.multicore_decoder->GetNumContinuousExecutionsForThread(tid));
   }
 
   // Errors
@@ -234,7 +231,7 @@
 
 llvm::Expected<Optional<uint64_t>>
 TraceIntelPT::GetRawTraceSize(Thread &thread) {
-  if (m_multicore_decoder)
+  if (GetUpdatedStorage().multicore_decoder)
     return None; // TODO: calculate the amount of intel pt raw trace associated
                  // with the given thread.
   if (GetLiveProcess())
@@ -316,15 +313,17 @@
 
 llvm::Optional<LinuxPerfZeroTscConversion>
 TraceIntelPT::GetPerfZeroTscConversion() {
+  return GetUpdatedStorage().tsc_conversion;
+}
+
+TraceIntelPT::Storage &TraceIntelPT::GetUpdatedStorage() {
   RefreshLiveProcessState();
-  return m_tsc_conversion;
+  return m_storage;
 }
 
 Error TraceIntelPT::DoRefreshLiveProcessState(TraceGetStateResponse state,
                                               StringRef json_response) {
-  m_thread_decoders.clear();
-  m_tsc_conversion.reset();
-  m_multicore_decoder.reset();
+  m_storage = {};
 
   Expected<TraceIntelPTGetStateResponse> intelpt_state =
       json::parse<TraceIntelPTGetStateResponse>(json_response,
@@ -332,11 +331,13 @@
   if (!intelpt_state)
     return intelpt_state.takeError();
 
+  m_storage.tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
+
   if (!intelpt_state->cores) {
     for (const TraceThreadState &thread_state : state.traced_threads) {
       ThreadSP thread_sp =
           GetLiveProcess()->GetThreadList().FindThreadByID(thread_state.tid);
-      m_thread_decoders.emplace(
+      m_storage.thread_decoders.emplace(
           thread_state.tid, std::make_unique<ThreadDecoder>(thread_sp, *this));
     }
   } else {
@@ -351,12 +352,10 @@
     if (!intelpt_state->tsc_perf_zero_conversion)
       return createStringError(inconvertibleErrorCode(),
                                "Missing perf time_zero conversion values");
-    m_multicore_decoder.emplace(*this, cores, tids,
-                                *intelpt_state->tsc_perf_zero_conversion);
+    m_storage.multicore_decoder.emplace(*this);
   }
 
-  m_tsc_conversion = intelpt_state->tsc_perf_zero_conversion;
-  if (m_tsc_conversion) {
+  if (m_storage.tsc_conversion) {
     Log *log = GetLog(LLDBLog::Target);
     LLDB_LOG(log, "TraceIntelPT found TSC conversion information");
   }
@@ -364,10 +363,10 @@
 }
 
 bool TraceIntelPT::IsTraced(lldb::tid_t tid) {
-  RefreshLiveProcessState();
-  if (m_multicore_decoder)
-    return m_multicore_decoder->TracesThread(tid);
-  return m_thread_decoders.count(tid);
+  Storage &storage = GetUpdatedStorage();
+  if (storage.multicore_decoder)
+    return storage.multicore_decoder->TracesThread(tid);
+  return storage.thread_decoders.count(tid);
 }
 
 // The information here should match the description of the intel-pt section
@@ -481,46 +480,4 @@
   return OnThreadBinaryDataRead(tid, IntelPTDataKinds::kTraceBuffer, callback);
 }
 
-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();
-}
+TaskTimer &TraceIntelPT::GetTimer() { return GetUpdatedStorage().task_timer; }
Index: lldb/source/Plugins/Process/Linux/Perf.h
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.h
+++ lldb/source/Plugins/Process/Linux/Perf.h
@@ -80,11 +80,6 @@
 /// Handles the management of the event's file descriptor and mmap'ed
 /// regions.
 class PerfEvent {
-  enum class CollectionState {
-    Enabled,
-    Disabled,
-  };
-
 public:
   /// Create a new performance monitoring event via the perf_event_open syscall.
   ///
@@ -116,7 +111,7 @@
   static llvm::Expected<PerfEvent> Init(perf_event_attr &attr,
                                         llvm::Optional<lldb::pid_t> pid,
                                         llvm::Optional<lldb::core_id_t> cpu,
-                                        llvm::Optional<int> group_fd,
+                                        llvm::Optional<long> group_fd,
                                         unsigned long flags);
 
   /// Create a new performance monitoring event via the perf_event_open syscall
@@ -266,17 +261,21 @@
   ///   data.
   size_t GetEffectiveDataBufferSize() const;
 
+  /// \return
+  ///   \b true if and only the perf event is enabled and collecting.
+  bool IsEnabled() const;
+
 private:
   /// Create new \a PerfEvent.
   ///
   /// \param[in] fd
   ///   File descriptor of the perf event.
   ///
-  /// \param[in] initial_state
+  /// \param[in] enabled
   ///   Initial collection state configured for this perf_event.
-  PerfEvent(long fd, CollectionState initial_state)
+  PerfEvent(long fd, bool enabled)
       : m_fd(new long(fd), resource_handle::FileDescriptorDeleter()),
-        m_collection_state(initial_state) {}
+        m_enabled(enabled) {}
 
   /// Wrapper for \a mmap to provide custom error messages.
   ///
@@ -319,9 +318,21 @@
   /// such as IntelPT.
   resource_handle::MmapUP m_aux_base;
   /// The state of the underlying perf_event.
-  CollectionState m_collection_state;
+  bool m_enabled;
 };
 
+/// Create a perf event that tracks context switches on a cpu.
+///
+/// \param[in] core_id
+///   The core to trace.
+///
+/// \param[in] parent_perf_event
+///   An optional perf event that will be grouped with the
+///   new perf event.
+llvm::Expected<PerfEvent>
+CreateContextSwitchTracePerfEvent(lldb::core_id_t core_id,
+                                  const PerfEvent *parent_perf_event = nullptr);
+
 /// Load \a PerfTscConversionParameters from \a perf_event_mmap_page, if
 /// available.
 llvm::Expected<LinuxPerfZeroTscConversion> LoadPerfTscConversionParameters();
Index: lldb/source/Plugins/Process/Linux/Perf.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/Perf.cpp
+++ lldb/source/Plugins/Process/Linux/Perf.cpp
@@ -74,7 +74,7 @@
 llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
                                           Optional<lldb::pid_t> pid,
                                           Optional<lldb::core_id_t> cpu,
-                                          Optional<int> group_fd,
+                                          Optional<long> group_fd,
                                           unsigned long flags) {
   errno = 0;
   long fd = syscall(SYS_perf_event_open, &attr, pid.getValueOr(-1),
@@ -84,8 +84,7 @@
         llvm::formatv("perf event syscall failed: {0}", std::strerror(errno));
     return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
   }
-  return PerfEvent(fd, attr.disabled ? CollectionState::Disabled
-                                     : CollectionState::Enabled);
+  return PerfEvent(fd, !attr.disabled);
 }
 
 llvm::Expected<PerfEvent> PerfEvent::Init(perf_event_attr &attr,
@@ -181,7 +180,12 @@
 
 Expected<std::vector<uint8_t>>
 PerfEvent::ReadFlushedOutDataCyclicBuffer(size_t offset, size_t size) {
-  CollectionState previous_state = m_collection_state;
+  // The following code assumes that the protection level of the DATA page
+  // is PROT_READ. If PROT_WRITE is used, then reading would require that
+  // this piece of code updates some pointers. See more about data_tail
+  // in https://man7.org/linux/man-pages/man2/perf_event_open.2.html.
+
+  bool was_enabled = m_enabled;
   if (Error err = DisableWithIoctl())
     return std::move(err);
 
@@ -220,7 +224,7 @@
       output.push_back(data[i]);
   }
 
-  if (previous_state == CollectionState::Enabled) {
+  if (was_enabled) {
     if (Error err = EnableWithIoctl())
       return std::move(err);
   }
@@ -236,7 +240,12 @@
 
 Expected<std::vector<uint8_t>>
 PerfEvent::ReadFlushedOutAuxCyclicBuffer(size_t offset, size_t size) {
-  CollectionState previous_state = m_collection_state;
+  // The following code assumes that the protection level of the AUX page
+  // is PROT_READ. If PROT_WRITE is used, then reading would require that
+  // this piece of code updates some pointers. See more about aux_tail
+  // in https://man7.org/linux/man-pages/man2/perf_event_open.2.html.
+
+  bool was_enabled = m_enabled;
   if (Error err = DisableWithIoctl())
     return std::move(err);
 
@@ -271,7 +280,7 @@
   for (uint64_t i = left_part_start; i < aux_head && output.size() < size; i++)
     output.push_back(data[i]);
 
-  if (previous_state == CollectionState::Enabled) {
+  if (was_enabled) {
     if (Error err = EnableWithIoctl())
       return std::move(err);
   }
@@ -286,7 +295,7 @@
 }
 
 Error PerfEvent::DisableWithIoctl() {
-  if (m_collection_state == CollectionState::Disabled)
+  if (!m_enabled)
     return Error::success();
 
   if (ioctl(*m_fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) < 0)
@@ -294,12 +303,14 @@
                              "Can't disable perf event. %s",
                              std::strerror(errno));
 
-  m_collection_state = CollectionState::Disabled;
+  m_enabled = false;
   return Error::success();
 }
 
+bool PerfEvent::IsEnabled() const { return m_enabled; }
+
 Error PerfEvent::EnableWithIoctl() {
-  if (m_collection_state == CollectionState::Enabled)
+  if (m_enabled)
     return Error::success();
 
   if (ioctl(*m_fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) < 0)
@@ -307,7 +318,7 @@
                              "Can't enable perf event. %s",
                              std::strerror(errno));
 
-  m_collection_state = CollectionState::Enabled;
+  m_enabled = true;
   return Error::success();
 }
 
@@ -318,3 +329,53 @@
   else
     return mmap_metadata.data_size; // The buffer has wrapped.
 }
+
+Expected<PerfEvent>
+lldb_private::process_linux::CreateContextSwitchTracePerfEvent(
+    lldb::core_id_t core_id, const PerfEvent *parent_perf_event) {
+  Log *log = GetLog(POSIXLog::Trace);
+#ifndef PERF_ATTR_SIZE_VER5
+  return createStringError(inconvertibleErrorCode(),
+                           "Intel PT Linux perf event not supported");
+#else
+  perf_event_attr attr;
+  memset(&attr, 0, sizeof(attr));
+  attr.size = sizeof(attr);
+  attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME;
+  attr.type = PERF_TYPE_SOFTWARE;
+  attr.context_switch = 1;
+  attr.exclude_kernel = 1;
+  attr.sample_id_all = 1;
+  attr.exclude_hv = 1;
+  attr.disabled = parent_perf_event ? !parent_perf_event->IsEnabled() : false;
+
+  // The given perf configuration will produce context switch records of 32
+  // bytes each. Assuming that every context switch will be emitted twice (one
+  // for context switch ins and another one for context switch outs), and that a
+  // context switch will happen at least every half a millisecond per core, we
+  // need 500 * 32 bytes (~16 KB) for a trace of one second, which is much more
+  // than what a regular intel pt trace can get. Pessimistically we pick as
+  // 32KiB for the size of our context switch trace.
+
+  uint64_t data_buffer_size = 32768;
+  uint64_t data_buffer_numpages = data_buffer_size / getpagesize();
+
+  LLDB_LOG(log, "Will create context switch trace buffer of size {0}",
+           data_buffer_size);
+
+  Optional<long> group_fd;
+  if (parent_perf_event)
+    group_fd = parent_perf_event->GetFd();
+
+  if (Expected<PerfEvent> perf_event =
+          PerfEvent::Init(attr, /*pid=*/None, core_id, group_fd, /*flags=*/0)) {
+    if (Error mmap_err = perf_event->MmapMetadataAndBuffers(
+            data_buffer_numpages, 0, /*data_buffer_write=*/false)) {
+      return std::move(mmap_err);
+    }
+    return perf_event;
+  } else {
+    return perf_event.takeError();
+  }
+#endif
+}
Index: lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
+++ lldb/source/Plugins/Process/Linux/IntelPTSingleBufferTrace.h
@@ -40,7 +40,9 @@
   ///     The CPU core id where to trace. If \b None, then this traces all CPUs.
   ///
   /// \param[in] disabled
-  ///     Whether to start the tracing paused.
+  ///     If \b true, then no data is collected until \a Resume is invoked.
+  ///     Similarly, if \b false, data is collected right away until \a Pause is
+  ///     invoked.
   ///
   /// \return
   ///   A \a IntelPTSingleBufferTrace instance if tracing was successful, or
Index: lldb/source/Plugins/Process/Linux/IntelPTProcessTrace.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTProcessTrace.h
+++ lldb/source/Plugins/Process/Linux/IntelPTProcessTrace.h
@@ -16,7 +16,8 @@
 namespace lldb_private {
 namespace process_linux {
 
-// Abstract class to be inherited by all the process tracing strategies.
+/// Interface to be implemented by each 'process trace' strategy (per core, per
+/// thread, etc).
 class IntelPTProcessTrace {
 public:
   virtual ~IntelPTProcessTrace() = default;
Index: lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.h
+++ lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.h
@@ -32,7 +32,7 @@
   /// \return
   ///   An \a IntelPTMultiCoreTrace instance if tracing was successful, or
   ///   an \a llvm::Error otherwise.
-  static llvm::Expected<IntelPTProcessTraceUP>
+  static llvm::Expected<std::unique_ptr<IntelPTPerThreadProcessTrace>>
   Start(const TraceIntelPTStartRequest &request,
         llvm::ArrayRef<lldb::tid_t> current_tids);
 
Index: lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTPerThreadProcessTrace.cpp
@@ -52,10 +52,11 @@
   return m_thread_traces.TryGetBinaryData(request);
 }
 
-Expected<IntelPTProcessTraceUP>
+Expected<std::unique_ptr<IntelPTPerThreadProcessTrace>>
 IntelPTPerThreadProcessTrace::Start(const TraceIntelPTStartRequest &request,
                                     ArrayRef<lldb::tid_t> current_tids) {
-  IntelPTProcessTraceUP trace(new IntelPTPerThreadProcessTrace(request));
+  std::unique_ptr<IntelPTPerThreadProcessTrace> trace(
+      new IntelPTPerThreadProcessTrace(request));
 
   Error error = Error::success();
   for (lldb::tid_t tid : current_tids)
Index: lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
+++ lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.h
@@ -38,7 +38,7 @@
   /// \return
   ///   An \a IntelPTMultiCoreTrace instance if tracing was successful, or
   ///   an \a llvm::Error otherwise.
-  static llvm::Expected<IntelPTProcessTraceUP>
+  static llvm::Expected<std::unique_ptr<IntelPTMultiCoreTrace>>
   StartOnAllCores(const TraceIntelPTStartRequest &request,
                   NativeProcessProtocol &process);
 
@@ -65,7 +65,7 @@
   ///   The perf event collecting context switches for the given core.
   void ForEachCore(std::function<void(lldb::core_id_t core_id,
                                       IntelPTSingleBufferTrace &intelpt_trace,
-                                      PerfEvent &context_switch_trace)>
+                                      ContextSwitchTrace &context_switch_trace)>
                        callback);
 
   void ProcessDidStop() override;
Index: lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTMultiCoreTrace.cpp
@@ -33,55 +33,7 @@
       toString(std::move(error)).c_str());
 }
 
-static Expected<PerfEvent> CreateContextSwitchTracePerfEvent(
-    bool disabled, lldb::core_id_t core_id,
-    IntelPTSingleBufferTrace &intelpt_core_trace) {
-  Log *log = GetLog(POSIXLog::Trace);
-#ifndef PERF_ATTR_SIZE_VER5
-  return createStringError(inconvertibleErrorCode(),
-                           "Intel PT Linux perf event not supported");
-#else
-  perf_event_attr attr;
-  memset(&attr, 0, sizeof(attr));
-  attr.size = sizeof(attr);
-  attr.sample_period = 0;
-  attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME;
-  attr.type = PERF_TYPE_SOFTWARE;
-  attr.context_switch = 1;
-  attr.exclude_kernel = 1;
-  attr.sample_id_all = 1;
-  attr.exclude_hv = 1;
-  attr.disabled = disabled;
-
-  // The given perf configuration will product context switch records of 32
-  // bytes each. Assuming that every context switch will be emitted twice (one
-  // for context switch ins and another one for context switch outs), and that a
-  // context switch will happen at least every half a millisecond per core, we
-  // need 500 * 32 bytes (~16 KB) for a trace of one second, which is much more
-  // than what a regular intel pt trace can get. Pessimistically we pick as
-  // 32KiB for the size of our context switch trace.
-
-  uint64_t data_buffer_size = 32768;
-  uint64_t data_buffer_numpages = data_buffer_size / getpagesize();
-
-  LLDB_LOG(log, "Will create context switch trace buffer of size {0}",
-           data_buffer_size);
-
-  if (Expected<PerfEvent> perf_event = PerfEvent::Init(
-          attr, /*pid=*/None, core_id,
-          intelpt_core_trace.GetPerfEvent().GetFd(), /*flags=*/0)) {
-    if (Error mmap_err = perf_event->MmapMetadataAndBuffers(
-            data_buffer_numpages, 0, /*data_buffer_write=*/false)) {
-      return std::move(mmap_err);
-    }
-    return perf_event;
-  } else {
-    return perf_event.takeError();
-  }
-#endif
-}
-
-Expected<IntelPTProcessTraceUP>
+Expected<std::unique_ptr<IntelPTMultiCoreTrace>>
 IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request,
                                        NativeProcessProtocol &process) {
   Expected<ArrayRef<core_id_t>> core_ids = GetAvailableLogicalCoreIDs();
@@ -105,8 +57,8 @@
       return IncludePerfEventParanoidMessageInError(core_trace.takeError());
 
     if (Expected<PerfEvent> context_switch_trace =
-            CreateContextSwitchTracePerfEvent(/*disabled=*/true, core_id,
-                                              core_trace.get())) {
+            CreateContextSwitchTracePerfEvent(core_id,
+                                              &core_trace->GetPerfEvent())) {
       traces.try_emplace(core_id,
                          std::make_pair(std::move(*core_trace),
                                         std::move(*context_switch_trace)));
@@ -115,7 +67,7 @@
     }
   }
 
-  return IntelPTProcessTraceUP(
+  return std::unique_ptr<IntelPTMultiCoreTrace>(
       new IntelPTMultiCoreTrace(std::move(traces), process));
 }
 
@@ -129,7 +81,7 @@
 void IntelPTMultiCoreTrace::ForEachCore(
     std::function<void(core_id_t core_id,
                        IntelPTSingleBufferTrace &intelpt_trace,
-                       PerfEvent &context_switch_trace)>
+                       ContextSwitchTrace &context_switch_trace)>
         callback) {
   for (auto &it : m_traces_per_core)
     callback(it.first, it.second.first, it.second.second);
@@ -163,7 +115,7 @@
   state.cores.emplace();
   ForEachCore([&](lldb::core_id_t core_id,
                   const IntelPTSingleBufferTrace &core_trace,
-                  const PerfEvent &context_switch_trace) {
+                  const ContextSwitchTrace &context_switch_trace) {
     state.cores->push_back(
         {core_id,
          {{IntelPTDataKinds::kTraceBuffer, core_trace.GetTraceBufferSize()},
@@ -180,8 +132,12 @@
 }
 
 llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) {
-  // This instance is already tracing all threads automatically.
-  return llvm::Error::success();
+  // All the process' threads are being traced automatically.
+  if (!TracesThread(tid))
+    return createStringError(
+        inconvertibleErrorCode(),
+        "Thread %" PRIu64 " is not part of the target process", tid);
+  return Error::success();
 }
 
 Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) {
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.h
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.h
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.h
@@ -74,8 +74,7 @@
                          const TraceIntelPTStartRequest &request);
 
   /// \return
-  ///   The conversion object between TSC and wall time. It caches the result
-  ///   upon success.
+  ///   The conversion object between TSC and wall time.
   llvm::Expected<LinuxPerfZeroTscConversion &>
   FetchPerfTscConversionParameters();
 
@@ -87,9 +86,6 @@
   /// Only one instance of "process trace" can be active at a given time.
   /// It might be \b nullptr.
   IntelPTProcessTraceUP m_process_trace_up;
-
-  /// Cached TSC to and from wall time conversion.
-  llvm::Optional<LinuxPerfZeroTscConversion> m_cached_tsc_conversion;
 };
 
 } // namespace process_linux
Index: lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
===================================================================
--- lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
+++ lldb/source/Plugins/Process/Linux/IntelPTCollector.cpp
@@ -37,16 +37,13 @@
 
 llvm::Expected<LinuxPerfZeroTscConversion &>
 IntelPTCollector::FetchPerfTscConversionParameters() {
-  if (!m_cached_tsc_conversion) {
-    if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
-            LoadPerfTscConversionParameters())
-      m_cached_tsc_conversion = std::move(*tsc_conversion);
-    else
-      return createStringError(inconvertibleErrorCode(),
-                               "Unable to load TSC to wall time conversion: %s",
-                               toString(tsc_conversion.takeError()).c_str());
-  }
-  return *m_cached_tsc_conversion;
+  if (Expected<LinuxPerfZeroTscConversion> tsc_conversion =
+          LoadPerfTscConversionParameters())
+    return *tsc_conversion;
+  else
+    return createStringError(inconvertibleErrorCode(),
+                             "Unable to load TSC to wall time conversion: %s",
+                             toString(tsc_conversion.takeError()).c_str());
 }
 
 Error IntelPTCollector::TraceStop(lldb::tid_t tid) {
Index: lldb/include/lldb/Target/Trace.h
===================================================================
--- lldb/include/lldb/Target/Trace.h
+++ lldb/include/lldb/Target/Trace.h
@@ -296,10 +296,9 @@
                                    OnBinaryDataReadCallback callback);
 
   /// Similar to \a OnCoreBinaryDataRead but this is able to fetch the same data
-  /// from multiple cores at once.
-  llvm::Error OnCoresBinaryDataRead(const std::set<lldb::core_id_t> core_ids,
-                                    llvm::StringRef kind,
-                                    OnCoresBinaryDataReadCallback callback);
+  /// from all cores at once.
+  llvm::Error OnAllCoresBinaryDataRead(llvm::StringRef kind,
+                                       OnCoresBinaryDataReadCallback callback);
 
   /// \return
   ///     All the currently traced processes.
@@ -310,6 +309,11 @@
   ///     plugin.
   llvm::ArrayRef<lldb::core_id_t> GetTracedCores();
 
+  /// Helper method for reading a data file and passing its data to the given
+  /// callback.
+  static llvm::Error OnDataFileRead(FileSpec file,
+                                    OnBinaryDataReadCallback callback);
+
 protected:
   /// Get the currently traced live process.
   ///
@@ -342,10 +346,6 @@
                                              llvm::StringRef kind,
                                              OnBinaryDataReadCallback callback);
 
-  /// Helper method for reading a data file and passing its data to the given
-  /// callback.
-  llvm::Error OnDataFileRead(FileSpec file, OnBinaryDataReadCallback callback);
-
   /// Get the file path containing data of a postmortem thread given a data
   /// identifier.
   ///
@@ -498,7 +498,7 @@
 
   /// Return the list of processes traced by this instance. None of the returned
   /// pointers are invalid.
-  std::vector<Process *> GetTracedProcesses() const;
+  std::vector<Process *> GetTracedProcesses();
 
   /// Method to be invoked by the plug-in to refresh the live process state. It
   /// will invoked DoRefreshLiveProcessState at some point, which should be
@@ -513,52 +513,63 @@
 
 private:
   uint32_t m_stop_id = LLDB_INVALID_STOP_ID;
+
   /// Process traced by this object if doing live tracing. Otherwise it's null.
   Process *m_live_process = nullptr;
 
-  /// Portmortem processes traced by this object if doing non-live tracing.
-  /// Otherwise it's empty.
-  std::vector<Process *> m_postmortem_processes;
-
-  /// These data kinds are returned by lldb-server when fetching the state of
-  /// the tracing session. The size in bytes can be used later for fetching the
-  /// data in batches.
-  /// \{
-
-  /// tid -> data kind -> size
-  llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, uint64_t>>
-      m_live_thread_data;
-
-  /// core id -> data kind -> size
-  llvm::DenseMap<lldb::core_id_t, std::unordered_map<std::string, uint64_t>>
-      m_live_core_data_sizes;
-  /// core id -> data kind -> bytes
-  llvm::DenseMap<lldb::core_id_t,
-                 std::unordered_map<std::string, std::vector<uint8_t>>>
-      m_live_core_data;
-
-  /// data kind -> size
-  std::unordered_map<std::string, uint64_t> m_live_process_data;
-  /// \}
-
-  /// The list of cores being traced. Might be \b None depending on the plug-in.
-  llvm::Optional<std::vector<lldb::core_id_t>> m_cores;
-
-  /// Postmortem traces can specific additional data files, which are
-  /// represented in this variable using a data kind identifier for each file.
-  /// \{
-
-  /// tid -> data kind -> file
-  llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, FileSpec>>
-      m_postmortem_thread_data;
-
-  /// core id -> data kind -> file
-  llvm::DenseMap<lldb::core_id_t, std::unordered_map<std::string, FileSpec>>
-      m_postmortem_core_data;
-
-  /// \}
-
-  llvm::Optional<std::string> m_live_refresh_error;
+  /// We package all the data that can change upon process stops to make sure
+  /// this contract is very visible.
+  /// This variable should only be accessed directly by constructores or live
+  /// process data refreshers.
+  struct Storage {
+    /// Portmortem processes traced by this object if doing non-live tracing.
+    /// Otherwise it's empty.
+    std::vector<Process *> postmortem_processes;
+
+    /// These data kinds are returned by lldb-server when fetching the state of
+    /// the tracing session. The size in bytes can be used later for fetching
+    /// the data in batches.
+    /// \{
+
+    /// tid -> data kind -> size
+    llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, uint64_t>>
+        live_thread_data;
+
+    /// core id -> data kind -> size
+    llvm::DenseMap<lldb::core_id_t, std::unordered_map<std::string, uint64_t>>
+        live_core_data_sizes;
+    /// core id -> data kind -> bytes
+    llvm::DenseMap<lldb::core_id_t,
+                   std::unordered_map<std::string, std::vector<uint8_t>>>
+        live_core_data;
+
+    /// data kind -> size
+    std::unordered_map<std::string, uint64_t> live_process_data;
+    /// \}
+
+    /// The list of cores being traced. Might be \b None depending on the
+    /// plug-in.
+    llvm::Optional<std::vector<lldb::core_id_t>> cores;
+
+    /// Postmortem traces can specific additional data files, which are
+    /// represented in this variable using a data kind identifier for each file.
+    /// \{
+
+    /// tid -> data kind -> file
+    llvm::DenseMap<lldb::tid_t, std::unordered_map<std::string, FileSpec>>
+        postmortem_thread_data;
+
+    /// core id -> data kind -> file
+    llvm::DenseMap<lldb::core_id_t, std::unordered_map<std::string, FileSpec>>
+        postmortem_core_data;
+
+    /// \}
+
+    llvm::Optional<std::string> live_refresh_error;
+  } m_storage;
+
+  /// Get the storage after refreshing the data in the case of a live process.
+  Storage &GetUpdatedStorage();
 };
 
 } // namespace lldb_private
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to