Skip to content

Commit

Permalink
libbpf-tools: add CO-RE 'syncsnoop'
Browse files Browse the repository at this point in the history
This is a CO-RE port of the Brendan Gregg's syncsnoop BCC Python tool.
The code is heavily inspired by the 'runqslower' port, with variables
naming and comments style borrowed from other CO-RE tools.
  • Loading branch information
myhro authored and chenhengqi committed Apr 11, 2024
1 parent a0ca636 commit c0e9b56
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 1 deletion.
1 change: 1 addition & 0 deletions libbpf-tools/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
/softirqs
/solisten
/statsnoop
/syncsnoop
/syscount
/tcpconnect
/tcpconnlat
Expand Down
1 change: 1 addition & 0 deletions libbpf-tools/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,7 @@ APPS = \
softirqs \
solisten \
statsnoop \
syncsnoop \
syscount \
tcptracer \
tcpconnect \
Expand Down
22 changes: 22 additions & 0 deletions libbpf-tools/syncsnoop.bpf.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: GPL-2.0
// Copyright (c) 2024 Tiago Ilieve
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include "syncsnoop.h"

struct {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__uint(key_size, sizeof(u32));
__uint(value_size, sizeof(u32));
} events SEC(".maps");

SEC("tracepoint/syscalls/sys_enter_sync")
void tracepoint__syscalls__sys_enter_sync(struct trace_event_raw_sys_enter *ctx)
{
struct event event = {};

event.ts_us = bpf_ktime_get_ns() / 1000;
bpf_perf_event_output(ctx, &events, BPF_F_CURRENT_CPU, &event, sizeof(event));
}

char LICENSE[] SEC("license") = "GPL";
146 changes: 146 additions & 0 deletions libbpf-tools/syncsnoop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause)
// Copyright (c) 2024 Tiago Ilieve
//
// Based on syncsnoop(8) from BCC by Brendan Gregg.
// 08-Feb-2024 Tiago Ilieve Created this.
#include <argp.h>
#include <signal.h>
#include <stdio.h>
#include <bpf/libbpf.h>
#include "syncsnoop.h"
#include "syncsnoop.skel.h"

#define PERF_BUFFER_PAGES 16
#define PERF_POLL_TIMEOUT_MS 100

static volatile sig_atomic_t exiting = 0;

struct env {
bool verbose;
} env = {};

const char *argp_program_version = "syncsnoop 0.1";
const char *argp_program_bug_address =
"https://github.com/iovisor/bcc/tree/master/libbpf-tools";
const char argp_program_doc[] =
"Trace sync syscalls.\n"
"\n"
"USAGE: syncsnoop [--help]\n"
"\n"
"EXAMPLES:\n"
" syncsnoop # trace sync syscalls\n";

static const struct argp_option opts[] = {
{ "verbose", 'v', NULL, 0, "Verbose debug output" },
{ NULL, 'h', NULL, OPTION_HIDDEN, "Show the full help" },
{},
};

static error_t parse_arg(int key, char *arg, struct argp_state *state)
{
switch (key) {
case 'v':
env.verbose = true;
break;
case 'h':
argp_state_help(state, stderr, ARGP_HELP_STD_HELP);
break;
default:
return ARGP_ERR_UNKNOWN;
}
return 0;
}

static int libbpf_print_fn(enum libbpf_print_level level, const char *format, va_list args)
{
if (level == LIBBPF_DEBUG && !env.verbose)
return 0;
return vfprintf(stderr, format, args);
}

void handle_event(void *ctx, int cpu, void *data, __u32 data_sz)
{
struct event e;

if (data_sz < sizeof(e)) {
printf("Error: packet too small\n");
return;
}
/* Copy data as alignment in the perf buffer isn't guaranteed. */
memcpy(&e, data, sizeof(e));

printf("%-18.9f sync()\n", (float) e.ts_us / 1000000);
}

void handle_lost_events(void *ctx, int cpu, __u64 lost_cnt)
{
printf("Lost %llu events on CPU #%d!\n", lost_cnt, cpu);
}

static void sig_int(int signo)
{
exiting = 1;
}

int main(int argc, char **argv)
{
static const struct argp argp = {
.options = opts,
.parser = parse_arg,
.doc = argp_program_doc,
};
struct perf_buffer *pb = NULL;
struct syncsnoop_bpf *obj;
int err;

err = argp_parse(&argp, argc, argv, 0, NULL, NULL);
if (err)
return err;

libbpf_set_print(libbpf_print_fn);

obj = syncsnoop_bpf__open_and_load();
if (!obj) {
fprintf(stderr, "failed to open and load BPF object\n");
return 1;
}

err = syncsnoop_bpf__attach(obj);
if (err) {
fprintf(stderr, "failed to attach BPF object\n");
return 1;
}

pb = perf_buffer__new(bpf_map__fd(obj->maps.events), PERF_BUFFER_PAGES,
handle_event, handle_lost_events, NULL, NULL);
if (!pb) {
err = -errno;
fprintf(stderr, "failed to open perf buffer: %d\n", err);
goto cleanup;
}

if (signal(SIGINT, sig_int) == SIG_ERR) {
fprintf(stderr, "can't set signal handler: %s\n", strerror(errno));
err = 1;
goto cleanup;
}

/* print header */
printf("%-18s %s\n", "TIME(s)", "CALL");

while (!exiting) {
err = perf_buffer__poll(pb, PERF_POLL_TIMEOUT_MS);
if (err < 0 && err != -EINTR) {
fprintf(stderr, "error polling perf buffer: %s\n", strerror(-err));
goto cleanup;
}
/* reset err to return 0 if exiting */
err = 0;
}

cleanup:
perf_buffer__free(pb);
syncsnoop_bpf__destroy(obj);

return err != 0;
}
9 changes: 9 additions & 0 deletions libbpf-tools/syncsnoop.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */
#ifndef __SYNCSNOOP_H
#define __SYNCSNOOP_H

struct event {
__u64 ts_us;
};

#endif /* __SYNCSNOOP_H */
3 changes: 2 additions & 1 deletion man/man8/syncsnoop.8
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@ Linux
.SH STABILITY
Unstable - in development.
.SH AUTHOR
Brendan Gregg
Brendan Gregg, original BCC Python version
Tiago Ilieve, CO-RE version
.SH SEE ALSO
iostat(1)

0 comments on commit c0e9b56

Please sign in to comment.