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