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 #include "Plugins/Process/POSIX/ProcessPOSIXLog.h" 14 15 using namespace lldb; 16 using namespace lldb_private; 17 using namespace process_linux; 18 using namespace llvm; 19 20 static bool IsTotalBufferLimitReached(ArrayRef<core_id_t> cores, 21 const TraceIntelPTStartRequest &request) { 22 uint64_t required = cores.size() * request.trace_buffer_size; 23 uint64_t limit = request.process_buffer_size_limit.getValueOr( 24 std::numeric_limits<uint64_t>::max()); 25 return required > limit; 26 } 27 28 static Error IncludePerfEventParanoidMessageInError(Error &&error) { 29 return createStringError( 30 inconvertibleErrorCode(), 31 "%s\nYou might need to rerun as sudo or to set " 32 "/proc/sys/kernel/perf_event_paranoid to a value of 0 or -1.", 33 toString(std::move(error)).c_str()); 34 } 35 36 Expected<IntelPTMultiCoreTraceUP> IntelPTMultiCoreTrace::StartOnAllCores( 37 const TraceIntelPTStartRequest &request) { 38 Expected<ArrayRef<core_id_t>> core_ids = GetAvailableLogicalCoreIDs(); 39 if (!core_ids) 40 return core_ids.takeError(); 41 42 if (IsTotalBufferLimitReached(*core_ids, request)) 43 return createStringError( 44 inconvertibleErrorCode(), 45 "The process can't be traced because the process trace size limit " 46 "has been reached. Consider retracing with a higher limit."); 47 48 llvm::DenseMap<core_id_t, IntelPTSingleBufferTraceUP> buffers; 49 for (core_id_t core_id : *core_ids) { 50 if (Expected<IntelPTSingleBufferTraceUP> core_trace = 51 IntelPTSingleBufferTrace::Start(request, /*tid=*/None, core_id, 52 TraceCollectionState::Paused)) 53 buffers.try_emplace(core_id, std::move(*core_trace)); 54 else 55 return IncludePerfEventParanoidMessageInError(core_trace.takeError()); 56 } 57 58 return IntelPTMultiCoreTraceUP(new IntelPTMultiCoreTrace(std::move(buffers))); 59 } 60 61 void IntelPTMultiCoreTrace::ForEachCore( 62 std::function<void(core_id_t core_id, IntelPTSingleBufferTrace &core_trace)> 63 callback) { 64 for (auto &it : m_traces_per_core) 65 callback(it.first, *it.second); 66 } 67 68 void IntelPTMultiCoreTrace::OnProcessStateChanged(lldb::StateType state) { 69 if (m_process_state == state) 70 return; 71 switch (state) { 72 case eStateStopped: 73 case eStateExited: { 74 ForEachCore([](core_id_t core_id, IntelPTSingleBufferTrace &core_trace) { 75 if (Error err = 76 core_trace.ChangeCollectionState(TraceCollectionState::Paused)) { 77 LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err), 78 "Unable to pause the core trace for core {0}", core_id); 79 } 80 }); 81 break; 82 } 83 case eStateRunning: { 84 ForEachCore([](core_id_t core_id, IntelPTSingleBufferTrace &core_trace) { 85 if (Error err = 86 core_trace.ChangeCollectionState(TraceCollectionState::Running)) { 87 LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err), 88 "Unable to resume the core trace for core {0}", core_id); 89 } 90 }); 91 break; 92 } 93 default: 94 break; 95 } 96 } 97