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<IntelPTProcessTraceUP> 37 IntelPTMultiCoreTrace::StartOnAllCores(const TraceIntelPTStartRequest &request, 38 NativeProcessProtocol &process) { 39 Expected<ArrayRef<core_id_t>> core_ids = GetAvailableLogicalCoreIDs(); 40 if (!core_ids) 41 return core_ids.takeError(); 42 43 if (IsTotalBufferLimitReached(*core_ids, request)) 44 return createStringError( 45 inconvertibleErrorCode(), 46 "The process can't be traced because the process trace size limit " 47 "has been reached. Consider retracing with a higher limit."); 48 49 llvm::DenseMap<core_id_t, IntelPTSingleBufferTraceUP> buffers; 50 for (core_id_t core_id : *core_ids) { 51 if (Expected<IntelPTSingleBufferTraceUP> core_trace = 52 IntelPTSingleBufferTrace::Start(request, /*tid=*/None, core_id, 53 TraceCollectionState::Paused)) 54 buffers.try_emplace(core_id, std::move(*core_trace)); 55 else 56 return IncludePerfEventParanoidMessageInError(core_trace.takeError()); 57 } 58 59 return IntelPTProcessTraceUP( 60 new IntelPTMultiCoreTrace(std::move(buffers), process)); 61 } 62 63 void IntelPTMultiCoreTrace::ForEachCore( 64 std::function<void(core_id_t core_id, IntelPTSingleBufferTrace &core_trace)> 65 callback) { 66 for (auto &it : m_traces_per_core) 67 callback(it.first, *it.second); 68 } 69 70 void IntelPTMultiCoreTrace::OnProcessStateChanged(lldb::StateType state) { 71 if (m_process_state == state) 72 return; 73 switch (state) { 74 case eStateStopped: 75 case eStateExited: { 76 ForEachCore([](core_id_t core_id, IntelPTSingleBufferTrace &core_trace) { 77 if (Error err = 78 core_trace.ChangeCollectionState(TraceCollectionState::Paused)) { 79 LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err), 80 "Unable to pause the core trace for core {0}", core_id); 81 } 82 }); 83 break; 84 } 85 case eStateRunning: { 86 ForEachCore([](core_id_t core_id, IntelPTSingleBufferTrace &core_trace) { 87 if (Error err = 88 core_trace.ChangeCollectionState(TraceCollectionState::Running)) { 89 LLDB_LOG_ERROR(GetLog(POSIXLog::Trace), std::move(err), 90 "Unable to resume the core trace for core {0}", core_id); 91 } 92 }); 93 break; 94 } 95 default: 96 break; 97 } 98 } 99 100 TraceGetStateResponse IntelPTMultiCoreTrace::GetState() { 101 TraceGetStateResponse state; 102 103 for (size_t i = 0; m_process.GetThreadAtIndex(i); i++) 104 state.traced_threads.push_back( 105 TraceThreadState{m_process.GetThreadAtIndex(i)->GetID(), {}}); 106 107 state.cores.emplace(); 108 ForEachCore([&](lldb::core_id_t core_id, 109 const IntelPTSingleBufferTrace &core_trace) { 110 state.cores->push_back( 111 {core_id, 112 {{IntelPTDataKinds::kTraceBuffer, core_trace.GetTraceBufferSize()}}}); 113 }); 114 115 return state; 116 } 117 118 bool IntelPTMultiCoreTrace::TracesThread(lldb::tid_t tid) const { 119 // All the process' threads are being traced automatically. 120 return (bool)m_process.GetThreadByID(tid); 121 } 122 123 llvm::Error IntelPTMultiCoreTrace::TraceStart(lldb::tid_t tid) { 124 // This instance is already tracing all threads automatically. 125 return llvm::Error::success(); 126 } 127 128 Error IntelPTMultiCoreTrace::TraceStop(lldb::tid_t tid) { 129 return createStringError(inconvertibleErrorCode(), 130 "Can't stop tracing an individual thread when " 131 "per-core process tracing is enabled."); 132 } 133 134 Expected<std::vector<uint8_t>> 135 IntelPTMultiCoreTrace::GetBinaryData(const TraceGetBinaryDataRequest &request) { 136 return createStringError(inconvertibleErrorCode(), "Unimplemented"); 137 } 138