11f49714dSWalter Erquinigo //===-- IntelPTMultiCoreTrace.cpp -----------------------------------------===//
21f49714dSWalter Erquinigo //
31f49714dSWalter Erquinigo // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41f49714dSWalter Erquinigo // See https://llvm.org/LICENSE.txt for license information.
51f49714dSWalter Erquinigo // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61f49714dSWalter Erquinigo //
71f49714dSWalter Erquinigo //===----------------------------------------------------------------------===//
81f49714dSWalter Erquinigo 
91f49714dSWalter Erquinigo #include "IntelPTMultiCoreTrace.h"
101f49714dSWalter Erquinigo 
111f49714dSWalter Erquinigo #include "Procfs.h"
121f49714dSWalter Erquinigo 
131637545fSWalter Erquinigo #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
141637545fSWalter Erquinigo 
151f49714dSWalter Erquinigo using namespace lldb;
161f49714dSWalter Erquinigo using namespace lldb_private;
171f49714dSWalter Erquinigo using namespace process_linux;
181f49714dSWalter Erquinigo using namespace llvm;
191f49714dSWalter Erquinigo 
IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,const TraceIntelPTStartRequest & request)206a5355e8SWalter Erquinigo static bool IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,
211f49714dSWalter Erquinigo                                       const TraceIntelPTStartRequest &request) {
226a5355e8SWalter Erquinigo   uint64_t required = cores.size() * request.ipt_trace_size;
23aa88161bSKazu Hirata   uint64_t limit = request.process_buffer_size_limit.value_or(
241f49714dSWalter Erquinigo       std::numeric_limits<uint64_t>::max());
251f49714dSWalter Erquinigo   return required > limit;
261f49714dSWalter Erquinigo }
271f49714dSWalter Erquinigo 
IncludePerfEventParanoidMessageInError(Error && error)281f49714dSWalter Erquinigo static Error IncludePerfEventParanoidMessageInError(Error &&error) {
291f49714dSWalter Erquinigo   return createStringError(
301f49714dSWalter Erquinigo       inconvertibleErrorCode(),
311f49714dSWalter Erquinigo       "%s\nYou might need to rerun as sudo or to set "
321f49714dSWalter Erquinigo       "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1.",
331f49714dSWalter Erquinigo       toString(std::move(error)).c_str());
341f49714dSWalter Erquinigo }
351f49714dSWalter Erquinigo 
3603cc58ffSWalter Erquinigo Expected<std::unique_ptr<IntelPTMultiCoreTrace>>
StartOnAllCores(const TraceIntelPTStartRequest & request,NativeProcessProtocol & process,Optional<int> cgroup_fd)371f56f7fcSWalter Erquinigo IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request,
38*d30fd5c3SGaurav Gaur                                        NativeProcessProtocol &process,
39*d30fd5c3SGaurav Gaur                                        Optional<int> cgroup_fd) {
406a5355e8SWalter Erquinigo   Expected<ArrayRef<cpu_id_t>> cpu_ids = GetAvailableLogicalCoreIDs();
416a5355e8SWalter Erquinigo   if (!cpu_ids)
426a5355e8SWalter Erquinigo     return cpu_ids.takeError();
431f49714dSWalter Erquinigo 
446a5355e8SWalter Erquinigo   if (IsTotalBufferLimitReached(*cpu_ids, request))
451f49714dSWalter Erquinigo     return createStringError(
461f49714dSWalter Erquinigo         inconvertibleErrorCode(),
471f49714dSWalter Erquinigo         "The process can't be traced because the process trace size limit "
481f49714dSWalter Erquinigo         "has been reached. Consider retracing with a higher limit.");
491f49714dSWalter Erquinigo 
506a5355e8SWalter Erquinigo   DenseMap<cpu_id_t, std::pair<IntelPTSingleBufferTrace, ContextSwitchTrace>>
51a7582059SWalter Erquinigo       traces;
52a7582059SWalter Erquinigo 
536a5355e8SWalter Erquinigo   for (cpu_id_t cpu_id : *cpu_ids) {
54a7582059SWalter Erquinigo     Expected<IntelPTSingleBufferTrace> core_trace =
556a5355e8SWalter Erquinigo         IntelPTSingleBufferTrace::Start(request, /*tid=*/None, cpu_id,
56*d30fd5c3SGaurav Gaur                                         /*disabled=*/true, cgroup_fd);
57a7582059SWalter Erquinigo     if (!core_trace)
581f49714dSWalter Erquinigo       return IncludePerfEventParanoidMessageInError(core_trace.takeError());
59a7582059SWalter Erquinigo 
60a7582059SWalter Erquinigo     if (Expected<PerfEvent> context_switch_trace =
616a5355e8SWalter Erquinigo             CreateContextSwitchTracePerfEvent(cpu_id,
6203cc58ffSWalter Erquinigo                                               &core_trace->GetPerfEvent())) {
636a5355e8SWalter Erquinigo       traces.try_emplace(cpu_id,
64a7582059SWalter Erquinigo                          std::make_pair(std::move(*core_trace),
65a7582059SWalter Erquinigo                                         std::move(*context_switch_trace)));
66a7582059SWalter Erquinigo     } else {
67a7582059SWalter Erquinigo       return context_switch_trace.takeError();
68a7582059SWalter Erquinigo     }
691f49714dSWalter Erquinigo   }
701f49714dSWalter Erquinigo 
7103cc58ffSWalter Erquinigo   return std::unique_ptr<IntelPTMultiCoreTrace>(
72*d30fd5c3SGaurav Gaur       new IntelPTMultiCoreTrace(std::move(traces), process, (bool)cgroup_fd));
731f49714dSWalter Erquinigo }
741f49714dSWalter Erquinigo 
ForEachCore(std::function<void (cpu_id_t cpu_id,IntelPTSingleBufferTrace & core_trace)> callback)751f49714dSWalter Erquinigo void IntelPTMultiCoreTrace::ForEachCore(
766a5355e8SWalter Erquinigo     std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace)>
771f49714dSWalter Erquinigo         callback) {
781f49714dSWalter Erquinigo   for (auto &it : m_traces_per_core)
79a7582059SWalter Erquinigo     callback(it.first, it.second.first);
801f49714dSWalter Erquinigo }
811637545fSWalter Erquinigo 
ForEachCore(std::function<void (cpu_id_t cpu_id,IntelPTSingleBufferTrace & intelpt_trace,ContextSwitchTrace & context_switch_trace)> callback)82a7582059SWalter Erquinigo void IntelPTMultiCoreTrace::ForEachCore(
836a5355e8SWalter Erquinigo     std::function<void(cpu_id_t cpu_id, IntelPTSingleBufferTrace &intelpt_trace,
8403cc58ffSWalter Erquinigo                        ContextSwitchTrace &context_switch_trace)>
85a7582059SWalter Erquinigo         callback) {
86a7582059SWalter Erquinigo   for (auto &it : m_traces_per_core)
87a7582059SWalter Erquinigo     callback(it.first, it.second.first, it.second.second);
88a7582059SWalter Erquinigo }
89a7582059SWalter Erquinigo 
ProcessDidStop()90a7582059SWalter Erquinigo void IntelPTMultiCoreTrace::ProcessDidStop() {
916a5355e8SWalter Erquinigo   ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {
92a7582059SWalter Erquinigo     if (Error err = core_trace.Pause()) {
931637545fSWalter Erquinigo       LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),
946a5355e8SWalter Erquinigo                      "Unable to pause the core trace for core {0}", cpu_id);
951637545fSWalter Erquinigo     }
961637545fSWalter Erquinigo   });
971637545fSWalter Erquinigo }
98a7582059SWalter Erquinigo 
ProcessWillResume()99a7582059SWalter Erquinigo void IntelPTMultiCoreTrace::ProcessWillResume() {
1006a5355e8SWalter Erquinigo   ForEachCore([](cpu_id_t cpu_id, IntelPTSingleBufferTrace &core_trace) {
101a7582059SWalter Erquinigo     if (Error err = core_trace.Resume()) {
1021637545fSWalter Erquinigo       LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err),
1036a5355e8SWalter Erquinigo                      "Unable to resume the core trace for core {0}", cpu_id);
1041637545fSWalter Erquinigo     }
1051637545fSWalter Erquinigo   });
1061637545fSWalter Erquinigo }
1071f56f7fcSWalter Erquinigo 
GetState()1081f2d49a8SWalter Erquinigo TraceIntelPTGetStateResponse IntelPTMultiCoreTrace::GetState() {
1091f2d49a8SWalter Erquinigo   TraceIntelPTGetStateResponse state;
110*d30fd5c3SGaurav Gaur   state.using_cgroup_filtering = m_using_cgroup_filtering;
1111f56f7fcSWalter Erquinigo 
112e095cddbSMichał Górny   for (NativeThreadProtocol &thread : m_process.Threads())
1131f56f7fcSWalter Erquinigo     state.traced_threads.push_back(
114e095cddbSMichał Górny         TraceThreadState{thread.GetID(), {}});
1151f56f7fcSWalter Erquinigo 
1166a5355e8SWalter Erquinigo   state.cpus.emplace();
1176a5355e8SWalter Erquinigo   ForEachCore([&](lldb::cpu_id_t cpu_id,
118a7582059SWalter Erquinigo                   const IntelPTSingleBufferTrace &core_trace,
11903cc58ffSWalter Erquinigo                   const ContextSwitchTrace &context_switch_trace) {
1206a5355e8SWalter Erquinigo     state.cpus->push_back(
1216a5355e8SWalter Erquinigo         {cpu_id,
1226a5355e8SWalter Erquinigo          {{IntelPTDataKinds::kIptTrace, core_trace.GetIptTraceSize()},
123a7582059SWalter Erquinigo           {IntelPTDataKinds::kPerfContextSwitchTrace,
124a7582059SWalter Erquinigo            context_switch_trace.GetEffectiveDataBufferSize()}}});
1251f56f7fcSWalter Erquinigo   });
1261f56f7fcSWalter Erquinigo 
1271f56f7fcSWalter Erquinigo   return state;
1281f56f7fcSWalter Erquinigo }
1291f56f7fcSWalter Erquinigo 
TracesThread(lldb::tid_t tid) const1301f56f7fcSWalter Erquinigo bool IntelPTMultiCoreTrace::TracesThread(lldb::tid_t tid) const {
1311f56f7fcSWalter Erquinigo   // All the process' threads are being traced automatically.
1321f56f7fcSWalter Erquinigo   return (bool)m_process.GetThreadByID(tid);
1331f56f7fcSWalter Erquinigo }
1341f56f7fcSWalter Erquinigo 
TraceStart(lldb::tid_t tid)1351f56f7fcSWalter Erquinigo llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) {
13603cc58ffSWalter Erquinigo   // All the process' threads are being traced automatically.
13703cc58ffSWalter Erquinigo   if (!TracesThread(tid))
13803cc58ffSWalter Erquinigo     return createStringError(
13903cc58ffSWalter Erquinigo         inconvertibleErrorCode(),
14003cc58ffSWalter Erquinigo         "Thread %" PRIu64 " is not part of the target process", tid);
14103cc58ffSWalter Erquinigo   return Error::success();
1421f56f7fcSWalter Erquinigo }
1431f56f7fcSWalter Erquinigo 
TraceStop(lldb::tid_t tid)1441f56f7fcSWalter Erquinigo Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) {
1451f56f7fcSWalter Erquinigo   return createStringError(inconvertibleErrorCode(),
1461f56f7fcSWalter Erquinigo                            "Can't stop tracing an individual thread when "
1479f45f23dSWalter Erquinigo                            "per-cpu process tracing is enabled.");
1481f56f7fcSWalter Erquinigo }
1491f56f7fcSWalter Erquinigo 
150fc5ef57cSWalter Erquinigo Expected<Optional<std::vector<uint8_t>>>
TryGetBinaryData(const TraceGetBinaryDataRequest & request)151fc5ef57cSWalter Erquinigo IntelPTMultiCoreTrace::TryGetBinaryData(
152fc5ef57cSWalter Erquinigo     const TraceGetBinaryDataRequest &request) {
1536a5355e8SWalter Erquinigo   if (!request.cpu_id)
154fc5ef57cSWalter Erquinigo     return None;
1556a5355e8SWalter Erquinigo   auto it = m_traces_per_core.find(*request.cpu_id);
156fc5ef57cSWalter Erquinigo   if (it == m_traces_per_core.end())
157fc5ef57cSWalter Erquinigo     return createStringError(
158fc5ef57cSWalter Erquinigo         inconvertibleErrorCode(),
1596a5355e8SWalter Erquinigo         formatv("Core {0} is not being traced", *request.cpu_id));
160fc5ef57cSWalter Erquinigo 
1616a5355e8SWalter Erquinigo   if (request.kind == IntelPTDataKinds::kIptTrace)
1626a5355e8SWalter Erquinigo     return it->second.first.GetIptTrace();
163fc5ef57cSWalter Erquinigo   if (request.kind == IntelPTDataKinds::kPerfContextSwitchTrace)
164561a61fbSWalter Erquinigo     return it->second.second.GetReadOnlyDataBuffer();
165fc5ef57cSWalter Erquinigo   return None;
1661f56f7fcSWalter Erquinigo }
167