diff options
Diffstat (limited to 'tools/tracing/rtla/src/timerlat_bpf.c')
-rw-r--r-- | tools/tracing/rtla/src/timerlat_bpf.c | 166 |
1 files changed, 166 insertions, 0 deletions
diff --git a/tools/tracing/rtla/src/timerlat_bpf.c b/tools/tracing/rtla/src/timerlat_bpf.c new file mode 100644 index 000000000000..5abee884037a --- /dev/null +++ b/tools/tracing/rtla/src/timerlat_bpf.c @@ -0,0 +1,166 @@ +// SPDX-License-Identifier: GPL-2.0 +#ifdef HAVE_BPF_SKEL +#include "timerlat.h" +#include "timerlat_bpf.h" +#include "timerlat.skel.h" + +static struct timerlat_bpf *bpf; + +/* + * timerlat_bpf_init - load and initialize BPF program to collect timerlat data + */ +int timerlat_bpf_init(struct timerlat_params *params) +{ + int err; + + debug_msg("Loading BPF program\n"); + + bpf = timerlat_bpf__open(); + if (!bpf) + return 1; + + /* Pass common options */ + bpf->rodata->output_divisor = params->output_divisor; + bpf->rodata->entries = params->entries; + bpf->rodata->irq_threshold = params->stop_us; + bpf->rodata->thread_threshold = params->stop_total_us; + bpf->rodata->aa_only = params->aa_only; + + if (params->entries != 0) { + /* Pass histogram options */ + bpf->rodata->bucket_size = params->bucket_size; + + /* Set histogram array sizes */ + bpf_map__set_max_entries(bpf->maps.hist_irq, params->entries); + bpf_map__set_max_entries(bpf->maps.hist_thread, params->entries); + bpf_map__set_max_entries(bpf->maps.hist_user, params->entries); + } else { + /* No entries, disable histogram */ + bpf_map__set_autocreate(bpf->maps.hist_irq, false); + bpf_map__set_autocreate(bpf->maps.hist_thread, false); + bpf_map__set_autocreate(bpf->maps.hist_user, false); + } + + if (params->aa_only) { + /* Auto-analysis only, disable summary */ + bpf_map__set_autocreate(bpf->maps.summary_irq, false); + bpf_map__set_autocreate(bpf->maps.summary_thread, false); + bpf_map__set_autocreate(bpf->maps.summary_user, false); + } + + /* Load and verify BPF program */ + err = timerlat_bpf__load(bpf); + if (err) { + timerlat_bpf__destroy(bpf); + return err; + } + + return 0; +} + +/* + * timerlat_bpf_attach - attach BPF program to collect timerlat data + */ +int timerlat_bpf_attach(void) +{ + debug_msg("Attaching BPF program\n"); + + return timerlat_bpf__attach(bpf); +} + +/* + * timerlat_bpf_detach - detach BPF program to collect timerlat data + */ +void timerlat_bpf_detach(void) +{ + timerlat_bpf__detach(bpf); +} + +/* + * timerlat_bpf_detach - destroy BPF program to collect timerlat data + */ +void timerlat_bpf_destroy(void) +{ + timerlat_bpf__destroy(bpf); +} + +static int handle_rb_event(void *ctx, void *data, size_t data_sz) +{ + return 0; +} + +/* + * timerlat_bpf_wait - wait until tracing is stopped or signal + */ +int timerlat_bpf_wait(int timeout) +{ + struct ring_buffer *rb; + int retval; + + rb = ring_buffer__new(bpf_map__fd(bpf->maps.signal_stop_tracing), + handle_rb_event, NULL, NULL); + retval = ring_buffer__poll(rb, timeout * 1000); + ring_buffer__free(rb); + + return retval; +} + +static int get_value(struct bpf_map *map_irq, + struct bpf_map *map_thread, + struct bpf_map *map_user, + int key, + long long *value_irq, + long long *value_thread, + long long *value_user, + int cpus) +{ + int err; + + err = bpf_map__lookup_elem(map_irq, &key, + sizeof(unsigned int), value_irq, + sizeof(long long) * cpus, 0); + if (err) + return err; + err = bpf_map__lookup_elem(map_thread, &key, + sizeof(unsigned int), value_thread, + sizeof(long long) * cpus, 0); + if (err) + return err; + err = bpf_map__lookup_elem(map_user, &key, + sizeof(unsigned int), value_user, + sizeof(long long) * cpus, 0); + if (err) + return err; + return 0; +} + +/* + * timerlat_bpf_get_hist_value - get value from BPF hist map + */ +int timerlat_bpf_get_hist_value(int key, + long long *value_irq, + long long *value_thread, + long long *value_user, + int cpus) +{ + return get_value(bpf->maps.hist_irq, + bpf->maps.hist_thread, + bpf->maps.hist_user, + key, value_irq, value_thread, value_user, cpus); +} + +/* + * timerlat_bpf_get_summary_value - get value from BPF summary map + */ +int timerlat_bpf_get_summary_value(enum summary_field key, + long long *value_irq, + long long *value_thread, + long long *value_user, + int cpus) +{ + return get_value(bpf->maps.summary_irq, + bpf->maps.summary_thread, + bpf->maps.summary_user, + key, value_irq, value_thread, value_user, cpus); +} +#endif /* HAVE_BPF_SKEL */ |