Files in directory pending/sandbox/perfect in any check-in
- src
- assemble_header.tcl
- Makefile
- perfect.h
- README.md
- tperfect.c
perfect
perfect is a single-header wrapper around linux kernel perf trace events. It aims to encapsulate the redundant complexity these interfaces push onto users while minimally restricting configurability and performance.
Introduction
Linux kernel perf trace events provides a low-level API for accessing many
interesting performance statistics for your software. These are used by Linux'
own perf
to do performance analysis. In order to collect these events you
must generally run an application with root or elevated privileges.
Counter events
Event counters provides sums of the total number of various kinds of events (branch misses, cache misses, etc.).
Counter API
struct Perfect_Counter
{
long long value; /* value read from counter after it is stopped. */
bool has_error; /* did any errors occur during counting? */
};
bool perfect_counter_init(
Perfect_Counter* p_counter,
struct perf_event_attr* p_attr,
pid_t pid,
int cpu,
int group_fd,
unsigned long flags);
void perfect_counter_destroy(Perfect_Counter* p_counter);
void perfect_counter_start(Perfect_Counter* p_counter);
void perfect_counter_stop(Perfect_Counter* p_counter);
bool perfect_counter_is_valid(Perfect_Counter* p_counter);
Counter example
Below is a simple example showing how to read the branch misses for a given section of code using perfect:
#define PERFECT_INCLUDE_IMPLEMENTATION
#include "perfect.h"
struct perf_event_attr pe;
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.size = sizeof(struct perf_event_attr);
pe.disabled = 1;
pe.inherit = 1;
pe.exclude_kernel = 1;
pe.exclude_guest = 1;
pe.exclude_hv = 1;
pe.type = PERF_TYPE_HARDWARE;
pe.config = PERF_COUNT_HW_BRANCH_MISSES;
Perfect_Counter branch_miss_counter;
if (perfect_counter_init(&branch_miss_counter, &pe, -1, 0, -1, 0))
{
perfect_counter_start(&branch_miss_counter);
{
// ... do something ...
}
perfect_counter_stop(&branch_miss_counter);
printf("branch misses: %lld\n", branch_miss_counter.value);
perfect_counter_destroy(&branch_miss_counter);
}
Sampling events
Sampling events provide access to specific events as they happen in real
time. They require root privileges. Events are written to an mmap
ed ring
buffer shared between the kernel and user space and can be read by iterating
over the samples in that ring buffer.
Since the structure of the data written into the ring buffer varies by attributes and specific event an iteration API is provided with the ability to read and skip arbitrary data in this buffer.
Sampling API
struct Perfect_Sampler;
struct Perfect_Sample_Iterator;
//-----------------------------------------------------------------------------
bool perfect_sampler_init(
Perfect_Sampler* p_sampler,
size_t ring_buffer_pages,
struct perf_event_attr* p_attr,
pid_t pid,
int cpu,
int group_fd,
unsigned long flags);
void perfect_sampler_destroy(Perfect_Sampler* p_sampler);
void perfect_sampler_start(Perfect_Sampler* p_sampler);
void perfect_sampler_stop(Perfect_Sampler* p_sampler);
bool perfect_sampler_has_samples(Perfect_Sampler* p_sampler);
//-----------------------------------------------------------------------------
Perfect_Sample_Iterator perfect_sample_iterator(Perfect_Sampler* p_sampler);
bool perfect_sample_iterator_is_valid(Perfect_Sample_Iterator* p_iter);
void perfect_sample_iterator_next(Perfect_Sample_Iterator* p_iter);
void perfect_sample_iterator_read(Perfect_Sample_Iterator* p_iter, void* p_dest, size_t size);
void perfect_sample_iterator_skip(Perfect_Sample_Iterator* p_iter, size_t offset);
Sampling example
Below is a simple example showing how you might read sampling events from a thread:
#define PERFECT_INCLUDE_IMPLEMENTATION
#include "perfect.h"
struct perf_event_attr pe;
//.. configure perf event ...
Perfect_Sampler sampler;
if (perfect_sampler_init(&sampler, 64, &pe, -1, 0, -1, PERF_FLAG_FD_CLOEXEC))
{
perfect_sampler_start(&sampler);
Perfect_Sample_Iterator iter = perfect_sample_iterator(&sampler);
while (perfect_sample_iterator_is_valid(&iter))
{
perfect_sample_iterator_skip(&iter, sizeof(uint64_t)); // skip time
uint64_t count;
perfect_sample_iterator_read(&iter, &count, sizeof(uint64_t));
// ... read more from sample ...
// ... persist sample ...
perfect_sample_iterator_next(&iter);
}
perfect_sampler_stop(&sampler);
perfect_sampler_destroy(&sampler);
}