Permalink
Cannot retrieve contributors at this time
Name already in use
A tag already exists with the provided branch name. Many Git commands accept both tag and branch names, so creating this branch may cause unexpected behavior. Are you sure you want to create this branch?
bpf-ringbuf-examples/src/perfbuf-output.c
Go to fileThis commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
115 lines (97 sloc)
2.51 KB
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) | |
// Copyright (c) 2020 Andrii Nakryiko | |
#include <errno.h> | |
#include <signal.h> | |
#include <stdio.h> | |
#include <time.h> | |
#include <sys/resource.h> | |
#include <bpf/libbpf.h> | |
#include "common.h" | |
#include "perfbuf-output.skel.h" | |
int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args) | |
{ | |
/* Ignore debug-level libbpf logs */ | |
if (level > LIBBPF_INFO) | |
return 0; | |
return vfprintf(stderr, format, args); | |
} | |
void bump_memlock_rlimit(void) | |
{ | |
struct rlimit rlim_new = { | |
.rlim_cur = RLIM_INFINITY, | |
.rlim_max = RLIM_INFINITY, | |
}; | |
if (setrlimit(RLIMIT_MEMLOCK, &rlim_new)) { | |
fprintf(stderr, "Failed to increase RLIMIT_MEMLOCK limit!\n"); | |
exit(1); | |
} | |
} | |
static volatile bool exiting = false; | |
static void sig_handler(int sig) | |
{ | |
exiting = true; | |
} | |
void handle_event(void *ctx, int cpu, void *data, unsigned int data_sz) | |
{ | |
const struct event *e = data; | |
struct tm *tm; | |
char ts[32]; | |
time_t t; | |
time(&t); | |
tm = localtime(&t); | |
strftime(ts, sizeof(ts), "%H:%M:%S", tm); | |
printf("%-8s %-5s %-7d %-16s %s\n", ts, "EXEC", e->pid, e->comm, e->filename); | |
} | |
int main(int argc, char **argv) | |
{ | |
struct perf_buffer *pb = NULL; | |
struct perf_buffer_opts pb_opts = {}; | |
struct perfbuf_output_bpf *skel; | |
int err; | |
/* Set up libbpf logging callback */ | |
libbpf_set_print(libbpf_print_fn); | |
/* Bump RLIMIT_MEMLOCK to create BPF maps */ | |
bump_memlock_rlimit(); | |
/* Clean handling of Ctrl-C */ | |
signal(SIGINT, sig_handler); | |
signal(SIGTERM, sig_handler); | |
/* Load and verify BPF application */ | |
skel = perfbuf_output_bpf__open_and_load(); | |
if (!skel) { | |
fprintf(stderr, "Failed to open and load BPF skeleton\n"); | |
return 1; | |
} | |
/* Attach tracepoint */ | |
err = perfbuf_output_bpf__attach(skel); | |
if (err) { | |
fprintf(stderr, "Failed to attach BPF skeleton\n"); | |
goto cleanup; | |
} | |
/* Set up ring buffer polling */ | |
pb_opts.sample_cb = handle_event; | |
pb = perf_buffer__new(bpf_map__fd(skel->maps.pb), 8 /* 32KB per CPU */, &pb_opts); | |
if (libbpf_get_error(pb)) { | |
err = -1; | |
fprintf(stderr, "Failed to create perf buffer\n"); | |
goto cleanup; | |
} | |
/* Process events */ | |
printf("%-8s %-5s %-7s %-16s %s\n", | |
"TIME", "EVENT", "PID", "COMM", "FILENAME"); | |
while (!exiting) { | |
err = perf_buffer__poll(pb, 100 /* timeout, ms */); | |
/* Ctrl-C will cause -EINTR */ | |
if (err == -EINTR) { | |
err = 0; | |
break; | |
} | |
if (err < 0) { | |
printf("Error polling perf buffer: %d\n", err); | |
break; | |
} | |
} | |
cleanup: | |
perf_buffer__free(pb); | |
perfbuf_output_bpf__destroy(skel); | |
return err < 0 ? -err : 0; | |
} |