13 #include "llvm/Support/FormatVariadic.h"
14 #include "llvm/Support/MathExtras.h"
15 #include "llvm/Support/MemoryBuffer.h"
16 #include <linux/version.h>
17 #include <sys/ioctl.h>
19 #include <sys/syscall.h>
23 using namespace process_linux;
26 Expected<LinuxPerfZeroTscConversion>
28 #if LINUX_VERSION_CODE >= KERNEL_VERSION(3, 12, 0)
31 memset(&attr, 0,
sizeof(attr));
32 attr.size =
sizeof(attr);
33 attr.type = PERF_TYPE_SOFTWARE;
34 attr.config = PERF_COUNT_SW_DUMMY;
38 return perf_event.takeError();
40 perf_event->MmapMetadataAndBuffers(0,
43 return std::move(mmap_err);
45 perf_event_mmap_page &mmap_metada = perf_event->GetMetadataPage();
46 if (mmap_metada.cap_user_time && mmap_metada.cap_user_time_zero) {
48 mmap_metada.
time_mult, mmap_metada.time_shift, {mmap_metada.time_zero}};
51 !mmap_metada.cap_user_time ?
"cap_user_time" :
"cap_user_time_zero";
53 llvm::formatv(
"Can't get TSC to real time conversion values. "
54 "perf_event capability '{0}' not supported.",
56 return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
59 std::string err_msg =
"PERF_COUNT_SW_DUMMY requires Linux 3.12";
60 return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
65 if (m_bytes && ptr !=
nullptr)
75 std::default_delete<long>()(ptr);
79 Optional<lldb::pid_t> pid,
80 Optional<lldb::cpu_id_t> cpu,
81 Optional<long> group_fd,
82 unsigned long flags) {
84 long fd = syscall(SYS_perf_event_open, &attr, pid.value_or(-1),
85 cpu.value_or(-1), group_fd.value_or(-1), flags);
88 llvm::formatv(
"perf event syscall failed: {0}", std::strerror(errno));
89 return llvm::createStringError(llvm::inconvertibleErrorCode(), err_msg);
95 Optional<lldb::pid_t> pid,
96 Optional<lldb::cpu_id_t> cpu) {
97 return Init(attr, pid, cpu, -1, 0);
100 llvm::Expected<resource_handle::MmapUP>
102 long int offset, llvm::StringRef buffer_name) {
104 auto mmap_result = ::mmap(addr, length, prot, flags, GetFd(), offset);
106 if (mmap_result == MAP_FAILED) {
108 llvm::formatv(
"perf event mmap allocation failed for {0}: {1}",
109 buffer_name, std::strerror(errno));
110 return createStringError(inconvertibleErrorCode(), err_msg);
116 bool data_buffer_write) {
117 size_t mmap_size = (num_data_pages + 1) * getpagesize();
118 if (Expected<resource_handle::MmapUP> mmap_metadata_data = DoMmap(
120 MAP_SHARED, 0,
"metadata and data buffer")) {
121 m_metadata_data_base = std::move(mmap_metadata_data.get());
122 return Error::success();
124 return mmap_metadata_data.takeError();
128 if (num_aux_pages == 0)
129 return Error::success();
131 perf_event_mmap_page &metadata_page = GetMetadataPage();
133 metadata_page.aux_offset =
134 metadata_page.data_offset + metadata_page.data_size;
135 metadata_page.aux_size = num_aux_pages * getpagesize();
137 if (Expected<resource_handle::MmapUP> mmap_aux =
138 DoMmap(
nullptr, metadata_page.aux_size,
PROT_READ, MAP_SHARED,
139 metadata_page.aux_offset,
"aux buffer")) {
140 m_aux_base = std::move(mmap_aux.get());
141 return Error::success();
143 return mmap_aux.takeError();
147 size_t num_aux_pages,
148 bool data_buffer_write) {
149 if (num_data_pages != 0 && !isPowerOf2_64(num_data_pages))
150 return llvm::createStringError(
151 llvm::inconvertibleErrorCode(),
152 llvm::formatv(
"Number of data pages must be a power of 2, got: {0}",
154 if (num_aux_pages != 0 && !isPowerOf2_64(num_aux_pages))
155 return llvm::createStringError(
156 llvm::inconvertibleErrorCode(),
157 llvm::formatv(
"Number of aux pages must be a power of 2, got: {0}",
159 if (
Error err = MmapMetadataAndDataBuffer(num_data_pages, data_buffer_write))
161 if (
Error err = MmapAuxBuffer(num_aux_pages))
163 return Error::success();
169 return *
reinterpret_cast<perf_event_mmap_page *
>(m_metadata_data_base.get());
173 perf_event_mmap_page &mmap_metadata = GetMetadataPage();
174 return {
reinterpret_cast<uint8_t *
>(m_metadata_data_base.get()) +
175 mmap_metadata.data_offset,
176 static_cast<size_t>(mmap_metadata.data_size)};
180 perf_event_mmap_page &mmap_metadata = GetMetadataPage();
181 return {
reinterpret_cast<uint8_t *
>(m_aux_base.get()),
182 static_cast<size_t>(mmap_metadata.aux_size)};
191 bool was_enabled = m_enabled;
192 if (
Error err = DisableWithIoctl())
193 return std::move(err);
202 perf_event_mmap_page &mmap_metadata = GetMetadataPage();
204 ArrayRef<uint8_t> data = GetDataBuffer();
205 uint64_t data_head = mmap_metadata.data_head;
206 uint64_t data_size = mmap_metadata.data_size;
207 std::vector<uint8_t> output;
208 output.reserve(data.size());
210 if (data_head > data_size) {
211 uint64_t actual_data_head = data_head % data_size;
213 output.insert(output.end(), data.begin() + actual_data_head, data.end());
215 output.insert(output.end(), data.begin(), data.begin() + actual_data_head);
218 output.insert(output.end(), data.begin(), data.begin() + data_head);
222 if (
Error err = EnableWithIoctl())
223 return std::move(err);
235 bool was_enabled = m_enabled;
236 if (
Error err = DisableWithIoctl())
237 return std::move(err);
239 perf_event_mmap_page &mmap_metadata = GetMetadataPage();
241 ArrayRef<uint8_t> data = GetAuxBuffer();
242 uint64_t aux_head = mmap_metadata.aux_head;
243 std::vector<uint8_t> output;
244 output.reserve(data.size());
258 output.insert(output.end(), data.begin() + aux_head, data.end());
259 output.insert(output.end(), data.begin(), data.begin() + aux_head);
262 if (
Error err = EnableWithIoctl())
263 return std::move(err);
271 return Error::success();
273 if (ioctl(*m_fd, PERF_EVENT_IOC_DISABLE, PERF_IOC_FLAG_GROUP) < 0)
274 return createStringError(inconvertibleErrorCode(),
275 "Can't disable perf event. %s",
276 std::strerror(errno));
279 return Error::success();
286 return Error::success();
288 if (ioctl(*m_fd, PERF_EVENT_IOC_ENABLE, PERF_IOC_FLAG_GROUP) < 0)
289 return createStringError(inconvertibleErrorCode(),
290 "Can't enable perf event. %s",
291 std::strerror(errno));
294 return Error::success();
298 perf_event_mmap_page &mmap_metadata = GetMetadataPage();
299 if (mmap_metadata.data_head < mmap_metadata.data_size)
300 return mmap_metadata.data_head;
302 return mmap_metadata.data_size;
309 #ifndef PERF_ATTR_SIZE_VER5
310 return createStringError(inconvertibleErrorCode(),
311 "Intel PT Linux perf event not supported");
313 perf_event_attr attr;
314 memset(&attr, 0,
sizeof(attr));
315 attr.size =
sizeof(attr);
316 attr.sample_type = PERF_SAMPLE_TID | PERF_SAMPLE_TIME;
317 attr.type = PERF_TYPE_SOFTWARE;
318 attr.context_switch = 1;
319 attr.exclude_kernel = 1;
320 attr.sample_id_all = 1;
322 attr.disabled = parent_perf_event ? !parent_perf_event->
IsEnabled() :
false;
332 uint64_t data_buffer_size = 32768;
333 uint64_t data_buffer_numpages = data_buffer_size / getpagesize();
335 LLDB_LOG(log,
"Will create context switch trace buffer of size {0}",
338 Optional<long> group_fd;
339 if (parent_perf_event)
340 group_fd = parent_perf_event->
GetFd();
342 if (Expected<PerfEvent> perf_event =
344 if (
Error mmap_err = perf_event->MmapMetadataAndBuffers(
345 data_buffer_numpages, 0,
false)) {
346 return std::move(mmap_err);
350 return perf_event.takeError();