// SPDX-License-Identifier: GPL-2.0#ifdef HAVE_BPF_SKEL#define _GNU_SOURCE#include "timerlat.h"#include "timerlat_bpf.h"#include "timerlat.skel.h" static struct timerlat_bpf *bpf; /* BPF object and program for action program */static struct bpf_object *obj;static struct bpf_program *prog; /* * 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->common.output_divisor; bpf->rodata->entries = params->common.hist.entries; bpf->rodata->irq_threshold = params->common.stop_us; bpf->rodata->thread_threshold = params->common.stop_total_us; bpf->rodata->aa_only = params->common.aa_only; if (params->common.hist.entries != 0) { /* Pass histogram options */ bpf->rodata->bucket_size = params->common.hist.bucket_size; /* Set histogram array sizes */ bpf_map__set_max_entries(bpf->maps.hist_irq, params->common.hist.entries); bpf_map__set_max_entries(bpf->maps.hist_thread, params->common.hist.entries); bpf_map__set_max_entries(bpf->maps.hist_user, params->common.hist.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->common.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_set_action - set action on threshold executed on BPF side */static int timerlat_bpf_set_action(struct bpf_program *prog){ unsigned int key = 0, value = bpf_program__fd(prog); return bpf_map__update_elem(bpf->maps.bpf_action, &key, sizeof(key), &value, sizeof(value), BPF_ANY);} /* * 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); bpf = NULL; if (obj) bpf_object__close(obj); obj = NULL; prog = NULL;} 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;} /* * timerlat_bpf_restart_tracing - restart stopped tracing */int timerlat_bpf_restart_tracing(void){ unsigned int key = 0; unsigned long long value = 0; return bpf_map__update_elem(bpf->maps.stop_tracing, &key, sizeof(key), &value, sizeof(value), BPF_ANY);} 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 err; err = bpf_map__lookup_elem(map_irq, &key, sizeof(unsigned int), value_irq, sizeof(long long) * nr_cpus, 0); if (err) return err; err = bpf_map__lookup_elem(map_thread, &key, sizeof(unsigned int), value_thread, sizeof(long long) * nr_cpus, 0); if (err) return err; err = bpf_map__lookup_elem(map_user, &key, sizeof(unsigned int), value_user, sizeof(long long) * nr_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){ return get_value(bpf->maps.hist_irq, bpf->maps.hist_thread, bpf->maps.hist_user, key, value_irq, value_thread, value_user);} /* * 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){ return get_value(bpf->maps.summary_irq, bpf->maps.summary_thread, bpf->maps.summary_user, key, value_irq, value_thread, value_user);} /* * timerlat_load_bpf_action_program - load and register a BPF action program */int timerlat_load_bpf_action_program(const char *program_path){ int err; obj = bpf_object__open_file(program_path, NULL); if (!obj) { err_msg("Failed to open BPF action program: %s\n", program_path); goto out_err; } err = bpf_object__load(obj); if (err) { err_msg("Failed to load BPF action program: %s\n", program_path); goto out_obj_err; } prog = bpf_object__find_program_by_name(obj, "action_handler"); if (!prog) { err_msg("BPF action program must have 'action_handler' function: %s\n", program_path); goto out_obj_err; } err = timerlat_bpf_set_action(prog); if (err) { err_msg("Failed to register BPF action program: %s\n", program_path); goto out_prog_err; } return 0; out_prog_err: prog = NULL;out_obj_err: bpf_object__close(obj); obj = NULL;out_err: return 1;} #endif /* HAVE_BPF_SKEL */
// SPDX-License-Identifier: GPL-2.0
#ifdef HAVE_BPF_SKEL
#define _GNU_SOURCE
#include "timerlat.h"
#include "timerlat_bpf.h"
#include "timerlat.skel.h"
static struct timerlat_bpf *bpf;
/* BPF object and program for action program */
static struct bpf_object *obj;
static struct bpf_program *prog;
/*
* 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->common.output_divisor;
bpf->rodata->entries = params->common.hist.entries;
bpf->rodata->irq_threshold = params->common.stop_us;
bpf->rodata->thread_threshold = params->common.stop_total_us;
bpf->rodata->aa_only = params->common.aa_only;
if (params->common.hist.entries != 0) {
/* Pass histogram options */
bpf->rodata->bucket_size = params->common.hist.bucket_size;
/* Set histogram array sizes */
bpf_map__set_max_entries(bpf->maps.hist_irq, params->common.hist.entries);
bpf_map__set_max_entries(bpf->maps.hist_thread, params->common.hist.entries);
bpf_map__set_max_entries(bpf->maps.hist_user, params->common.hist.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->common.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_set_action - set action on threshold executed on BPF side
*/
static int timerlat_bpf_set_action(struct bpf_program *prog)
{
unsigned int key = 0, value = bpf_program__fd(prog);
return bpf_map__update_elem(bpf->maps.bpf_action,
&key, sizeof(key),
&value, sizeof(value),
BPF_ANY);
}
/*
* 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);
bpf = NULL;
if (obj)
bpf_object__close(obj);
obj = NULL;
prog = NULL;
}
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;
}
/*
* timerlat_bpf_restart_tracing - restart stopped tracing
*/
int timerlat_bpf_restart_tracing(void)
{
unsigned int key = 0;
unsigned long long value = 0;
return bpf_map__update_elem(bpf->maps.stop_tracing,
&key, sizeof(key),
&value, sizeof(value), BPF_ANY);
}
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 err;
err = bpf_map__lookup_elem(map_irq, &key,
sizeof(unsigned int), value_irq,
sizeof(long long) * nr_cpus, 0);
if (err)
return err;
err = bpf_map__lookup_elem(map_thread, &key,
sizeof(unsigned int), value_thread,
sizeof(long long) * nr_cpus, 0);
if (err)
return err;
err = bpf_map__lookup_elem(map_user, &key,
sizeof(unsigned int), value_user,
sizeof(long long) * nr_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)
{
return get_value(bpf->maps.hist_irq,
bpf->maps.hist_thread,
bpf->maps.hist_user,
key, value_irq, value_thread, value_user);
}
/*
* 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)
{
return get_value(bpf->maps.summary_irq,
bpf->maps.summary_thread,
bpf->maps.summary_user,
key, value_irq, value_thread, value_user);
}
/*
* timerlat_load_bpf_action_program - load and register a BPF action program
*/
int timerlat_load_bpf_action_program(const char *program_path)
{
int err;
obj = bpf_object__open_file(program_path, NULL);
if (!obj) {
err_msg("Failed to open BPF action program: %s\n", program_path);
goto out_err;
}
err = bpf_object__load(obj);
if (err) {
err_msg("Failed to load BPF action program: %s\n", program_path);
goto out_obj_err;
}
prog = bpf_object__find_program_by_name(obj, "action_handler");
if (!prog) {
err_msg("BPF action program must have 'action_handler' function: %s\n",
program_path);
goto out_obj_err;
}
err = timerlat_bpf_set_action(prog);
if (err) {
err_msg("Failed to register BPF action program: %s\n", program_path);
goto out_prog_err;
}
return 0;
out_prog_err:
prog = NULL;
out_obj_err:
bpf_object__close(obj);
obj = NULL;
out_err:
return 1;
}
#endif /* HAVE_BPF_SKEL */