diff --git a/libbpf-tools/.gitignore b/libbpf-tools/.gitignore index 9da5a5553322..1ab61f5a98ea 100644 --- a/libbpf-tools/.gitignore +++ b/libbpf-tools/.gitignore @@ -43,6 +43,7 @@ /offcputime /oomkill /opensnoop +/pidpersec /profile /readahead /runqlat diff --git a/libbpf-tools/Makefile b/libbpf-tools/Makefile index 0ae0d8611d8d..390287f5d09f 100644 --- a/libbpf-tools/Makefile +++ b/libbpf-tools/Makefile @@ -70,6 +70,7 @@ APPS = \ numamove \ offcputime \ oomkill \ + pidpersec \ profile \ readahead \ runqlat \ diff --git a/libbpf-tools/pidpersec.bpf.c b/libbpf-tools/pidpersec.bpf.c new file mode 100644 index 000000000000..511df209358a --- /dev/null +++ b/libbpf-tools/pidpersec.bpf.c @@ -0,0 +1,16 @@ +// SPDX-License-Identifier: GPL-2.0 +// Copyright (c) 2024 Tiago Ilieve +#include "vmlinux.h" +#include +#include "pidpersec.h" + +__u64 stats[S_MAXSTAT] = {}; + +SEC("tracepoint/sched/sched_process_fork") +int tracepoint__sched__sched_process_fork(void *ctx) +{ + __atomic_add_fetch(&stats[S_COUNT], 1, __ATOMIC_RELAXED); + return 0; +} + +char LICENSE[] SEC("license") = "GPL"; diff --git a/libbpf-tools/pidpersec.c b/libbpf-tools/pidpersec.c new file mode 100644 index 000000000000..0cef2837a279 --- /dev/null +++ b/libbpf-tools/pidpersec.c @@ -0,0 +1,121 @@ +// SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) +// Copyright (c) 2024 Tiago Ilieve +// +// Based on pidpersec(8) from BCC by Brendan Gregg. +// 12-Apr-2024 Tiago Ilieve Created this. +#include +#include +#include +#include +#include +#include +#include "pidpersec.h" +#include "pidpersec.skel.h" + +static volatile sig_atomic_t exiting = 0; + +struct env { + bool verbose; +} env = {}; + +const char *argp_program_version = "pidpersec 0.1"; +const char *argp_program_bug_address = + "https://github.com/iovisor/bcc/tree/master/libbpf-tools"; +const char argp_program_doc[] = +"Count new processes (via fork).\n" +"\n" +"USAGE: pidpersec [--help]\n" +"\n" +"EXAMPLES:\n" +" pidpersec # count new processes\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); +} + +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 pidpersec_bpf *obj; + int err; + + err = argp_parse(&argp, argc, argv, 0, NULL, NULL); + if (err) + return err; + + libbpf_set_print(libbpf_print_fn); + + obj = pidpersec_bpf__open_and_load(); + if (!obj) { + fprintf(stderr, "failed to open and load BPF object\n"); + return 1; + } + + err = pidpersec_bpf__attach(obj); + if (err) { + fprintf(stderr, "failed to attach BPF object\n"); + return 1; + } + + 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("Tracing... Ctrl-C to end.\n"); + + while (!exiting) { + struct tm *tm; + char ts[16]; + __u64 val; + time_t t; + + sleep(1); + + time(&t); + tm = localtime(&t); + strftime(ts, sizeof(ts), "%H:%M:%S", tm); + val = __atomic_exchange_n(&obj->bss->stats[S_COUNT], 0, __ATOMIC_RELAXED); + printf("%s: PIDs/sec: %llu\n", ts, val); + } + +cleanup: + pidpersec_bpf__destroy(obj); + + return err != 0; +} diff --git a/libbpf-tools/pidpersec.h b/libbpf-tools/pidpersec.h new file mode 100644 index 000000000000..a3eaa03939f1 --- /dev/null +++ b/libbpf-tools/pidpersec.h @@ -0,0 +1,10 @@ +/* SPDX-License-Identifier: (LGPL-2.1 OR BSD-2-Clause) */ +#ifndef __PIDPERSEC_H +#define __PIDPERSEC_H + +enum stat_types { + S_COUNT = 1, + S_MAXSTAT +}; + +#endif /* __PIDPERSEC_H */ diff --git a/man/man8/pidpersec.8 b/man/man8/pidpersec.8 index 2164ffafdb99..5448a9c41d0b 100644 --- a/man/man8/pidpersec.8 +++ b/man/man8/pidpersec.8 @@ -36,6 +36,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 top(1)