6
6
//
7
7
// ===----------------------------------------------------------------------===//
8
8
9
- #include < algorithm>
10
- #include < fstream>
11
- #include < sstream>
9
+ #include " IntelPTCollector.h"
12
10
13
- #include " llvm/ADT/StringRef.h"
14
- #include " llvm/Support/Error.h"
15
- #include " llvm/Support/MathExtras.h"
11
+ #include " Perf.h"
16
12
17
- #include " IntelPTCollector.h"
18
13
#include " Plugins/Process/POSIX/ProcessPOSIXLog.h"
19
14
#include " lldb/Host/linux/Support.h"
20
15
#include " lldb/Utility/StreamString.h"
21
16
17
+ #include " llvm/ADT/StringRef.h"
18
+ #include " llvm/Support/Error.h"
19
+ #include " llvm/Support/MathExtras.h"
20
+
21
+ #include < algorithm>
22
+ #include < cstddef>
23
+ #include < fstream>
24
+ #include < linux/perf_event.h>
25
+ #include < sstream>
22
26
#include < sys/ioctl.h>
23
27
#include < sys/syscall.h>
24
28
@@ -53,6 +57,21 @@ enum IntelPTConfigFileType {
53
57
BitOffset
54
58
};
55
59
60
+ // / Get the content of /proc/cpuinfo that can be later used to decode traces.
61
+ static Expected<ArrayRef<uint8_t >> GetCPUInfo () {
62
+ static llvm::Optional<std::vector<uint8_t >> cpu_info;
63
+ if (!cpu_info) {
64
+ auto buffer_or_error = errorOrToExpected (getProcFile (" cpuinfo" ));
65
+ if (!buffer_or_error)
66
+ return buffer_or_error.takeError ();
67
+ MemoryBuffer &buffer = **buffer_or_error;
68
+ cpu_info = std::vector<uint8_t >(
69
+ reinterpret_cast <const uint8_t *>(buffer.getBufferStart ()),
70
+ reinterpret_cast <const uint8_t *>(buffer.getBufferEnd ()));
71
+ }
72
+ return *cpu_info;
73
+ }
74
+
56
75
static Expected<uint32_t > ReadIntelPTConfigFile (const char *file,
57
76
IntelPTConfigFileType type) {
58
77
ErrorOr<std::unique_ptr<MemoryBuffer>> stream =
@@ -106,6 +125,7 @@ static Expected<uint32_t> ReadIntelPTConfigFile(const char *file,
106
125
}
107
126
return value;
108
127
}
128
+
109
129
// / Return the Linux perf event type for Intel PT.
110
130
static Expected<uint32_t > GetOSEventType () {
111
131
return ReadIntelPTConfigFile (kOSEventIntelPTTypeFile ,
@@ -148,7 +168,7 @@ size_t IntelPTThreadTrace::GetTraceBufferSize() const {
148
168
#ifndef PERF_ATTR_SIZE_VER5
149
169
llvm_unreachable (" Intel PT Linux perf event not supported" );
150
170
#else
151
- return m_mmap_meta-> aux_size ;
171
+ return m_perf_event. GetAuxBuffer (). size () ;
152
172
#endif
153
173
}
154
174
@@ -176,30 +196,9 @@ GeneratePerfEventConfigValue(bool enable_tsc, Optional<size_t> psb_period) {
176
196
return config;
177
197
}
178
198
179
- Error IntelPTThreadTrace::StartTrace (lldb::pid_t pid, lldb::tid_t tid,
180
- uint64_t buffer_size, bool enable_tsc,
181
- Optional<size_t > psb_period) {
182
- #ifndef PERF_ATTR_SIZE_VER5
183
- llvm_unreachable (" Intel PT Linux perf event not supported" );
184
- #else
185
- Log *log = GetLog (POSIXLog::Ptrace);
186
-
187
- m_tid = tid;
188
- LLDB_LOG (log, " called thread id {0}" , tid);
189
- uint64_t page_size = getpagesize ();
190
-
191
- if (__builtin_popcount (buffer_size) != 1 || buffer_size < 4096 ) {
192
- return createStringError (
193
- inconvertibleErrorCode (),
194
- " The trace buffer size must be a power of 2 greater than or equal to "
195
- " 4096 (2^12) bytes. It was %" PRIu64 " ." ,
196
- buffer_size);
197
- }
198
- uint64_t numpages = static_cast <uint64_t >(
199
- llvm::PowerOf2Floor ((buffer_size + page_size - 1 ) / page_size));
200
- numpages = std::max<uint64_t >(1 , numpages);
201
- buffer_size = page_size * numpages;
202
-
199
+ llvm::Expected<perf_event_attr>
200
+ IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration (
201
+ bool enable_tsc, Optional<size_t > psb_period) {
203
202
perf_event_attr attr;
204
203
memset (&attr, 0 , sizeof (attr));
205
204
attr.size = sizeof (attr);
@@ -213,106 +212,59 @@ Error IntelPTThreadTrace::StartTrace(lldb::pid_t pid, lldb::tid_t tid,
213
212
if (Expected<uint64_t > config_value =
214
213
GeneratePerfEventConfigValue (enable_tsc, psb_period)) {
215
214
attr.config = *config_value;
216
- LLDB_LOG (log, " intel pt config {0}" , attr.config );
217
215
} else {
218
216
return config_value.takeError ();
219
217
}
220
218
221
219
if (Expected<uint32_t > intel_pt_type = GetOSEventType ()) {
222
220
attr.type = *intel_pt_type;
223
- LLDB_LOG (log, " intel pt type {0}" , attr.type );
224
221
} else {
225
222
return intel_pt_type.takeError ();
226
223
}
227
224
228
- LLDB_LOG (log, " buffer size {0} " , buffer_size);
229
-
230
- errno = 0 ;
231
- auto fd =
232
- syscall (SYS_perf_event_open, &attr, static_cast <::tid_t >(tid), -1 , -1 , 0 );
233
- if (fd == -1 ) {
234
- LLDB_LOG (log, " syscall error {0}" , errno);
235
- return createStringError (inconvertibleErrorCode (),
236
- " perf event syscall failed" );
237
- }
238
-
239
- m_fd = std::unique_ptr<int , file_close>(new int (fd), file_close ());
240
-
241
- errno = 0 ;
242
- auto base =
243
- mmap (nullptr , (buffer_size + page_size), PROT_WRITE, MAP_SHARED, fd, 0 );
244
-
245
- if (base == MAP_FAILED) {
246
- LLDB_LOG (log, " mmap base error {0}" , errno);
247
- return createStringError (inconvertibleErrorCode (),
248
- " Meta buffer allocation failed" );
249
- }
250
-
251
- m_mmap_meta = std::unique_ptr<perf_event_mmap_page, munmap_delete>(
252
- reinterpret_cast <perf_event_mmap_page *>(base),
253
- munmap_delete (buffer_size + page_size));
254
-
255
- m_mmap_meta->aux_offset = m_mmap_meta->data_offset + m_mmap_meta->data_size ;
256
- m_mmap_meta->aux_size = buffer_size;
257
-
258
- errno = 0 ;
259
- auto mmap_aux = mmap (nullptr , buffer_size, PROT_READ, MAP_SHARED, fd,
260
- static_cast <long int >(m_mmap_meta->aux_offset ));
261
-
262
- if (mmap_aux == MAP_FAILED) {
263
- LLDB_LOG (log, " second mmap done {0}" , errno);
264
- return createStringError (inconvertibleErrorCode (),
265
- " Trace buffer allocation failed" );
266
- }
267
- m_mmap_aux = std::unique_ptr<uint8_t , munmap_delete>(
268
- reinterpret_cast <uint8_t *>(mmap_aux), munmap_delete (buffer_size));
269
- return Error::success ();
270
- #endif
225
+ return attr;
271
226
}
272
227
273
- llvm::MutableArrayRef<uint8_t > IntelPTThreadTrace::GetDataBuffer () const {
228
+ llvm::Expected<IntelPTThreadTraceUP>
229
+ IntelPTThreadTrace::Create (lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size,
230
+ bool enable_tsc, Optional<size_t > psb_period) {
274
231
#ifndef PERF_ATTR_SIZE_VER5
275
232
llvm_unreachable (" Intel PT Linux perf event not supported" );
276
233
#else
277
- return MutableArrayRef<uint8_t >(
278
- (reinterpret_cast <uint8_t *>(m_mmap_meta.get ()) +
279
- m_mmap_meta->data_offset ),
280
- m_mmap_meta->data_size );
281
- #endif
282
- }
234
+ Log *log = GetLog (POSIXLog::Ptrace);
283
235
284
- llvm::MutableArrayRef<uint8_t > IntelPTThreadTrace::GetAuxBuffer () const {
285
- #ifndef PERF_ATTR_SIZE_VER5
286
- llvm_unreachable (" Intel PT Linux perf event not supported" );
287
- #else
288
- return MutableArrayRef<uint8_t >(m_mmap_aux.get (), m_mmap_meta->aux_size );
289
- #endif
290
- }
236
+ LLDB_LOG (log, " called thread id {0}" , tid);
291
237
292
- Expected<ArrayRef<uint8_t >> IntelPTThreadTrace::GetCPUInfo () {
293
- static llvm::Optional<std::vector<uint8_t >> cpu_info;
294
- if (!cpu_info) {
295
- auto buffer_or_error = getProcFile (" cpuinfo" );
296
- if (!buffer_or_error)
297
- return Status (buffer_or_error.getError ()).ToError ();
298
- MemoryBuffer &buffer = **buffer_or_error;
299
- cpu_info = std::vector<uint8_t >(
300
- reinterpret_cast <const uint8_t *>(buffer.getBufferStart ()),
301
- reinterpret_cast <const uint8_t *>(buffer.getBufferEnd ()));
238
+ if (__builtin_popcount (buffer_size) != 1 || buffer_size < 4096 ) {
239
+ return createStringError (
240
+ inconvertibleErrorCode (),
241
+ " The trace buffer size must be a power of 2 greater than or equal to "
242
+ " 4096 (2^12) bytes. It was %" PRIu64 " ." ,
243
+ buffer_size);
302
244
}
303
- return *cpu_info;
304
- }
245
+ uint64_t page_size = getpagesize ();
246
+ uint64_t buffer_numpages = static_cast <uint64_t >(
247
+ llvm::PowerOf2Floor ((buffer_size + page_size - 1 ) / page_size));
305
248
306
- llvm::Expected<IntelPTThreadTraceUP>
307
- IntelPTThreadTrace::Create (lldb::pid_t pid, lldb::tid_t tid, size_t buffer_size,
308
- bool enable_tsc, Optional<size_t > psb_period) {
309
- IntelPTThreadTraceUP thread_trace_up (new IntelPTThreadTrace ());
249
+ Expected<perf_event_attr> attr =
250
+ IntelPTThreadTrace::CreateIntelPTPerfEventConfiguration (enable_tsc,
251
+ psb_period);
252
+ if (!attr)
253
+ return attr.takeError ();
310
254
311
- if (llvm::Error err = thread_trace_up->StartTrace (pid, tid, buffer_size,
312
- enable_tsc, psb_period))
313
- return std::move (err);
255
+ LLDB_LOG (log, " buffer size {0} " , buffer_size);
314
256
315
- return std::move (thread_trace_up);
257
+ if (Expected<PerfEvent> perf_event = PerfEvent::Init (*attr, tid)) {
258
+ if (Error mmap_err = perf_event->MmapMetadataAndBuffers (buffer_numpages,
259
+ buffer_numpages)) {
260
+ return std::move (mmap_err);
261
+ }
262
+ return IntelPTThreadTraceUP (
263
+ new IntelPTThreadTrace (std::move (*perf_event), tid));
264
+ } else {
265
+ return perf_event.takeError ();
266
+ }
267
+ #endif
316
268
}
317
269
318
270
Expected<std::vector<uint8_t >>
@@ -331,6 +283,8 @@ IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
331
283
#ifndef PERF_ATTR_SIZE_VER5
332
284
llvm_unreachable (" perf event not supported" );
333
285
#else
286
+ auto fd = m_perf_event.GetFd ();
287
+ perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage ();
334
288
// Disable the perf event to force a flush out of the CPU's internal buffer.
335
289
// Besides, we can guarantee that the CPU won't override any data as we are
336
290
// reading the buffer.
@@ -346,13 +300,13 @@ IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
346
300
//
347
301
// This is achieved by the PERF_EVENT_IOC_DISABLE ioctl request, as mentioned
348
302
// in the man page of perf_event_open.
349
- ioctl (*m_fd , PERF_EVENT_IOC_DISABLE);
303
+ ioctl (fd , PERF_EVENT_IOC_DISABLE);
350
304
351
305
Log *log = GetLog (POSIXLog::Ptrace);
352
306
Status error;
353
- uint64_t head = m_mmap_meta-> aux_head ;
307
+ uint64_t head = mmap_metadata. aux_head ;
354
308
355
- LLDB_LOG (log, " Aux size -{0} , Head - {1}" , m_mmap_meta-> aux_size , head);
309
+ LLDB_LOG (log, " Aux size -{0} , Head - {1}" , mmap_metadata. aux_size , head);
356
310
357
311
/* *
358
312
* When configured as ring buffer, the aux buffer keeps wrapping around
@@ -366,11 +320,12 @@ IntelPTThreadTrace::ReadPerfTraceAux(llvm::MutableArrayRef<uint8_t> &buffer,
366
320
*
367
321
* */
368
322
369
- ReadCyclicBuffer (buffer, GetAuxBuffer (), static_cast <size_t >(head), offset);
370
- LLDB_LOG (log, " ReadCyclic BUffer Done" );
323
+ ReadCyclicBuffer (buffer, m_perf_event.GetAuxBuffer (),
324
+ static_cast <size_t >(head), offset);
325
+ LLDB_LOG (log, " ReadCyclic Buffer Done" );
371
326
372
327
// Reenable tracing now we have read the buffer
373
- ioctl (*m_fd , PERF_EVENT_IOC_ENABLE);
328
+ ioctl (fd , PERF_EVENT_IOC_ENABLE);
374
329
return error;
375
330
#endif
376
331
}
@@ -385,7 +340,8 @@ IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
385
340
uint64_t bytes_remaining = buffer.size ();
386
341
Status error;
387
342
388
- uint64_t head = m_mmap_meta->data_head ;
343
+ perf_event_mmap_page &mmap_metadata = m_perf_event.GetMetadataPage ();
344
+ uint64_t head = mmap_metadata.data_head ;
389
345
390
346
/*
391
347
* The data buffer and aux buffer have different implementations
@@ -397,11 +353,11 @@ IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
397
353
398
354
LLDB_LOG (log, " bytes_remaining - {0}" , bytes_remaining);
399
355
400
- auto data_buffer = GetDataBuffer ();
356
+ auto data_buffer = m_perf_event. GetDataBuffer ();
401
357
402
358
if (head > data_buffer.size ()) {
403
359
head = head % data_buffer.size ();
404
- LLDB_LOG (log, " Data size -{0} Head - {1}" , m_mmap_meta-> data_size , head);
360
+ LLDB_LOG (log, " Data size -{0} Head - {1}" , mmap_metadata. data_size , head);
405
361
406
362
ReadCyclicBuffer (buffer, data_buffer, static_cast <size_t >(head), offset);
407
363
bytes_remaining -= buffer.size ();
@@ -424,7 +380,7 @@ IntelPTThreadTrace::ReadPerfTraceData(llvm::MutableArrayRef<uint8_t> &buffer,
424
380
}
425
381
426
382
void IntelPTThreadTrace::ReadCyclicBuffer (llvm::MutableArrayRef<uint8_t > &dst,
427
- llvm::MutableArrayRef <uint8_t > src,
383
+ llvm::ArrayRef <uint8_t > src,
428
384
size_t src_cyc_index, size_t offset) {
429
385
430
386
Log *log = GetLog (POSIXLog::Ptrace);
@@ -450,7 +406,7 @@ void IntelPTThreadTrace::ReadCyclicBuffer(llvm::MutableArrayRef<uint8_t> &dst,
450
406
return ;
451
407
}
452
408
453
- llvm::SmallVector<MutableArrayRef <uint8_t >, 2 > parts = {
409
+ llvm::SmallVector<ArrayRef <uint8_t >, 2 > parts = {
454
410
src.slice (src_cyc_index), src.take_front (src_cyc_index)};
455
411
456
412
if (offset > parts[0 ].size ()) {
@@ -624,7 +580,7 @@ Error IntelPTCollector::OnThreadDestroyed(lldb::tid_t tid) {
624
580
}
625
581
626
582
Expected<json::Value> IntelPTCollector::GetState () const {
627
- Expected<ArrayRef<uint8_t >> cpu_info = IntelPTThreadTrace:: GetCPUInfo ();
583
+ Expected<ArrayRef<uint8_t >> cpu_info = GetCPUInfo ();
628
584
if (!cpu_info)
629
585
return cpu_info.takeError ();
630
586
@@ -661,7 +617,7 @@ IntelPTCollector::GetBinaryData(const TraceGetBinaryDataRequest &request) const
661
617
else
662
618
return trace.takeError ();
663
619
} else if (request.kind == " cpuInfo" ) {
664
- return IntelPTThreadTrace:: GetCPUInfo ();
620
+ return GetCPUInfo ();
665
621
}
666
622
return createStringError (inconvertibleErrorCode (),
667
623
" Unsuported trace binary data kind: %s" ,
0 commit comments