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"
101637545fSWalter Erquinigo #include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
11c4fb631cSWalter Erquinigo #include "Procfs.h"
12f190ce62SKazu Hirata #include <optional>
131637545fSWalter Erquinigo
141f49714dSWalter Erquinigo using namespace lldb;
151f49714dSWalter Erquinigo using namespace lldb_private;
161f49714dSWalter Erquinigo using namespace process_linux;
171f49714dSWalter Erquinigo using namespace llvm;
181f49714dSWalter Erquinigo
IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,const TraceIntelPTStartRequest & request)196a5355e8SWalter Erquinigo static bool IsTotalBufferLimitReached(ArrayRef<cpu_id_t> cores,
201f49714dSWalter Erquinigo const TraceIntelPTStartRequest &request) {
216a5355e8SWalter Erquinigo uint64_t required = cores.size() * request.ipt_trace_size;
22aa88161bSKazu Hirata uint64_t limit = request.process_buffer_size_limit.value_or(
231f49714dSWalter Erquinigo std::numeric_limits<uint64_t>::max());
241f49714dSWalter Erquinigo return required > limit;
251f49714dSWalter Erquinigo }
261f49714dSWalter Erquinigo
IncludePerfEventParanoidMessageInError(Error && error)271f49714dSWalter Erquinigo static Error IncludePerfEventParanoidMessageInError(Error &&error) {
281f49714dSWalter Erquinigo return createStringError(
291f49714dSWalter Erquinigo inconvertibleErrorCode(),
301f49714dSWalter Erquinigo "%s\nYou might need to rerun as sudo or to set "
31c4fb631cSWalter Erquinigo "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1. You can use "
32c4fb631cSWalter Erquinigo "`sudo sysctl -w kernel.perf_event_paranoid=-1` for that.",
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,std::optional<int> cgroup_fd)371f56f7fcSWalter Erquinigo IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request,
38d30fd5c3SGaurav Gaur NativeProcessProtocol &process,
39daa6305cSFangrui Song std::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 =
55343523d0SKazu Hirata IntelPTSingleBufferTrace::Start(request, /*tid=*/std::nullopt, cpu_id,
56d30fd5c3SGaurav 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>(
72d30fd5c3SGaurav 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;
110d30fd5c3SGaurav Gaur state.using_cgroup_filtering = m_using_cgroup_filtering;
1111f56f7fcSWalter Erquinigo
112e095cddbSMichał Górny for (NativeThreadProtocol &thread : m_process.Threads())
113c4fb631cSWalter Erquinigo state.traced_threads.push_back(TraceThreadState{thread.GetID(), {}});
1141f56f7fcSWalter Erquinigo
1156a5355e8SWalter Erquinigo state.cpus.emplace();
1166a5355e8SWalter Erquinigo ForEachCore([&](lldb::cpu_id_t cpu_id,
117a7582059SWalter Erquinigo const IntelPTSingleBufferTrace &core_trace,
11803cc58ffSWalter Erquinigo const ContextSwitchTrace &context_switch_trace) {
1196a5355e8SWalter Erquinigo state.cpus->push_back(
1206a5355e8SWalter Erquinigo {cpu_id,
1216a5355e8SWalter Erquinigo {{IntelPTDataKinds::kIptTrace, core_trace.GetIptTraceSize()},
122a7582059SWalter Erquinigo {IntelPTDataKinds::kPerfContextSwitchTrace,
123a7582059SWalter Erquinigo context_switch_trace.GetEffectiveDataBufferSize()}}});
1241f56f7fcSWalter Erquinigo });
1251f56f7fcSWalter Erquinigo
1261f56f7fcSWalter Erquinigo return state;
1271f56f7fcSWalter Erquinigo }
1281f56f7fcSWalter Erquinigo
TracesThread(lldb::tid_t tid) const1291f56f7fcSWalter Erquinigo bool IntelPTMultiCoreTrace::TracesThread(lldb::tid_t tid) const {
1301f56f7fcSWalter Erquinigo // All the process' threads are being traced automatically.
1311f56f7fcSWalter Erquinigo return (bool)m_process.GetThreadByID(tid);
1321f56f7fcSWalter Erquinigo }
1331f56f7fcSWalter Erquinigo
TraceStart(lldb::tid_t tid)1341f56f7fcSWalter Erquinigo llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) {
13503cc58ffSWalter Erquinigo // All the process' threads are being traced automatically.
13603cc58ffSWalter Erquinigo if (!TracesThread(tid))
13703cc58ffSWalter Erquinigo return createStringError(
13803cc58ffSWalter Erquinigo inconvertibleErrorCode(),
13903cc58ffSWalter Erquinigo "Thread %" PRIu64 " is not part of the target process", tid);
14003cc58ffSWalter Erquinigo return Error::success();
1411f56f7fcSWalter Erquinigo }
1421f56f7fcSWalter Erquinigo
TraceStop(lldb::tid_t tid)1431f56f7fcSWalter Erquinigo Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) {
1441f56f7fcSWalter Erquinigo return createStringError(inconvertibleErrorCode(),
1451f56f7fcSWalter Erquinigo "Can't stop tracing an individual thread when "
1469f45f23dSWalter Erquinigo "per-cpu process tracing is enabled.");
1471f56f7fcSWalter Erquinigo }
1481f56f7fcSWalter Erquinigo
149*2fe83274SKazu Hirata Expected<std::optional<std::vector<uint8_t>>>
TryGetBinaryData(const TraceGetBinaryDataRequest & request)150fc5ef57cSWalter Erquinigo IntelPTMultiCoreTrace::TryGetBinaryData(
151fc5ef57cSWalter Erquinigo const TraceGetBinaryDataRequest &request) {
1526a5355e8SWalter Erquinigo if (!request.cpu_id)
153343523d0SKazu Hirata return std::nullopt;
1546a5355e8SWalter Erquinigo auto it = m_traces_per_core.find(*request.cpu_id);
155fc5ef57cSWalter Erquinigo if (it == m_traces_per_core.end())
156fc5ef57cSWalter Erquinigo return createStringError(
157fc5ef57cSWalter Erquinigo inconvertibleErrorCode(),
1586a5355e8SWalter Erquinigo formatv("Core {0} is not being traced", *request.cpu_id));
159fc5ef57cSWalter Erquinigo
1606a5355e8SWalter Erquinigo if (request.kind == IntelPTDataKinds::kIptTrace)
1616a5355e8SWalter Erquinigo return it->second.first.GetIptTrace();
162fc5ef57cSWalter Erquinigo if (request.kind == IntelPTDataKinds::kPerfContextSwitchTrace)
163561a61fbSWalter Erquinigo return it->second.second.GetReadOnlyDataBuffer();
164343523d0SKazu Hirata return std::nullopt;
1651f56f7fcSWalter Erquinigo }
166