1 //===-- IntelPTMultiCoreTrace.cpp -----------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "IntelPTMultiCoreTrace.h"
10 
11 #include "Procfs.h"
12 
13 using namespace lldb;
14 using namespace lldb_private;
15 using namespace process_linux;
16 using namespace llvm;
17 
18 static bool IsTotalBufferLimitReached(ArrayRef<core_id_t> cores,
19                                       const TraceIntelPTStartRequest &request) {
20   uint64_t required = cores.size() * request.trace_buffer_size;
21   uint64_t limit = request.process_buffer_size_limit.getValueOr(
22       std::numeric_limits<uint64_t>::max());
23   return required > limit;
24 }
25 
26 static Error IncludePerfEventParanoidMessageInError(Error &&error) {
27   return createStringError(
28       inconvertibleErrorCode(),
29       "%s\nYou might need to rerun as sudo or to set "
30       "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1.",
31       toString(std::move(error)).c_str());
32 }
33 
34 Expected<IntelPTMultiCoreTraceUP> IntelPTMultiCoreTrace::StartOnAllCores(
35     const TraceIntelPTStartRequest &request) {
36   Expected<ArrayRef<core_id_t>> core_ids = GetAvailableLogicalCoreIDs();
37   if (!core_ids)
38     return core_ids.takeError();
39 
40   if (IsTotalBufferLimitReached(*core_ids, request))
41     return createStringError(
42         inconvertibleErrorCode(),
43         "The process can't be traced because the process trace size limit "
44         "has been reached. Consider retracing with a higher limit.");
45 
46   llvm::DenseMap<core_id_t, IntelPTSingleBufferTraceUP> buffers;
47   for (core_id_t core_id : *core_ids) {
48     if (Expected<IntelPTSingleBufferTraceUP> core_trace =
49             IntelPTSingleBufferTrace::Start(request, /*tid=*/None, core_id))
50       buffers.try_emplace(core_id, std::move(*core_trace));
51     else
52       return IncludePerfEventParanoidMessageInError(core_trace.takeError());
53   }
54 
55   return IntelPTMultiCoreTraceUP(new IntelPTMultiCoreTrace(std::move(buffers)));
56 }
57 
58 void IntelPTMultiCoreTrace::ForEachCore(
59     std::function<void(core_id_t core_id,
60                        const IntelPTSingleBufferTrace &core_trace)>
61         callback) {
62   for (auto &it : m_traces_per_core)
63     callback(it.first, *it.second);
64 }
65