perf kwork: Add IRQ trace BPF support
Implements irq trace bpf function. Test cases: Trace irq without filter: # perf kwork -k irq rep -b Starting trace, Hit <Ctrl+C> to stop and report ^C Kwork Name | Cpu | Total Runtime | Count | Max runtime | Max runtime start | Max runtime end | -------------------------------------------------------------------------------------------------------------------------------- virtio0-requests:25 | 0000 | 31.026 ms | 285 | 1.493 ms | 110326.049963 s | 110326.051456 s | eth0:10 | 0002 | 7.875 ms | 96 | 1.429 ms | 110313.916835 s | 110313.918264 s | ata_piix:14 | 0002 | 2.510 ms | 28 | 0.396 ms | 110331.367987 s | 110331.368383 s | -------------------------------------------------------------------------------------------------------------------------------- Trace irq with cpu filter: # perf kwork -k irq rep -b -C 0 Starting trace, Hit <Ctrl+C> to stop and report ^C Kwork Name | Cpu | Total Runtime | Count | Max runtime | Max runtime start | Max runtime end | -------------------------------------------------------------------------------------------------------------------------------- virtio0-requests:25 | 0000 | 34.288 ms | 282 | 2.061 ms | 110358.078968 s | 110358.081029 s | -------------------------------------------------------------------------------------------------------------------------------- Trace irq with name filter: # perf kwork -k irq rep -b -n eth0 Starting trace, Hit <Ctrl+C> to stop and report ^C Kwork Name | Cpu | Total Runtime | Count | Max runtime | Max runtime start | Max runtime end | -------------------------------------------------------------------------------------------------------------------------------- eth0:10 | 0002 | 2.184 ms | 21 | 0.572 ms | 110386.541699 s | 110386.542271 s | -------------------------------------------------------------------------------------------------------------------------------- Trace irq with summary: # perf kwork -k irq rep -b -S Starting trace, Hit <Ctrl+C> to stop and report ^C Kwork Name | Cpu | Total Runtime | Count | Max runtime | Max runtime start | Max runtime end | -------------------------------------------------------------------------------------------------------------------------------- virtio0-requests:25 | 0000 | 42.923 ms | 285 | 1.181 ms | 110418.128867 s | 110418.130049 s | eth0:10 | 0002 | 2.085 ms | 20 | 0.668 ms | 110416.002935 s | 110416.003603 s | ata_piix:14 | 0002 | 0.970 ms | 4 | 0.656 ms | 110424.034482 s | 110424.035138 s | -------------------------------------------------------------------------------------------------------------------------------- Total count : 309 Total runtime (msec) : 45.977 (0.003% load average) Total time span (msec) : 17017.655 -------------------------------------------------------------------------------------------------------------------------------- Committer testing: # perf kwork -k irq rep -b Starting trace, Hit <Ctrl+C> to stop and report ^C Kwork Name | Cpu | Total Runtime | Count | Max runtime | Max runtime start | Max runtime end | -------------------------------------------------------------------------------------------------------------------------------- nvme0q20:145 | 0019 | 0.570 ms | 28 | 0.064 ms | 26966.635102 s | 26966.635167 s | amdgpu:162 | 0002 | 0.568 ms | 29 | 0.068 ms | 26966.644346 s | 26966.644414 s | nvme0q4:129 | 0003 | 0.565 ms | 31 | 0.037 ms | 26966.614830 s | 26966.614866 s | nvme0q16:141 | 0015 | 0.205 ms | 66 | 0.012 ms | 26967.145161 s | 26967.145174 s | nvme0q29:154 | 0028 | 0.154 ms | 44 | 0.014 ms | 26967.078970 s | 26967.078984 s | nvme0q10:135 | 0009 | 0.134 ms | 43 | 0.011 ms | 26967.132093 s | 26967.132104 s | nvme0q2:127 | 0001 | 0.132 ms | 26 | 0.011 ms | 26966.883584 s | 26966.883595 s | nvme0q25:150 | 0024 | 0.127 ms | 32 | 0.014 ms | 26966.631419 s | 26966.631433 s | nvme0q14:139 | 0013 | 0.110 ms | 21 | 0.017 ms | 26966.760843 s | 26966.760861 s | nvme0q30:155 | 0029 | 0.102 ms | 30 | 0.022 ms | 26966.677171 s | 26966.677193 s | nvme0q13:138 | 0012 | 0.088 ms | 20 | 0.015 ms | 26966.738733 s | 26966.738748 s | nvme0q6:131 | 0005 | 0.087 ms | 13 | 0.020 ms | 26966.648445 s | 26966.648465 s | nvme0q28:153 | 0027 | 0.066 ms | 12 | 0.015 ms | 26966.771431 s | 26966.771447 s | nvme0q26:151 | 0025 | 0.060 ms | 13 | 0.012 ms | 26966.704266 s | 26966.704278 s | nvme0q21:146 | 0020 | 0.054 ms | 20 | 0.011 ms | 26967.322082 s | 26967.322094 s | nvme0q1:126 | 0000 | 0.046 ms | 11 | 0.013 ms | 26966.859754 s | 26966.859767 s | nvme0q17:142 | 0016 | 0.046 ms | 10 | 0.011 ms | 26967.114513 s | 26967.114524 s | xhci_hcd:74 | 0015 | 0.041 ms | 3 | 0.016 ms | 26967.086004 s | 26967.086020 s | nvme0q8:133 | 0007 | 0.039 ms | 12 | 0.008 ms | 26966.712056 s | 26966.712063 s | nvme0q32:157 | 0031 | 0.036 ms | 10 | 0.014 ms | 26966.627054 s | 26966.627068 s | nvme0q9:134 | 0008 | 0.036 ms | 11 | 0.011 ms | 26967.258452 s | 26967.258462 s | nvme0q7:132 | 0006 | 0.024 ms | 3 | 0.014 ms | 26966.767404 s | 26966.767418 s | nvme0q11:136 | 0010 | 0.023 ms | 5 | 0.006 ms | 26966.935455 s | 26966.935461 s | nvme0q31:156 | 0030 | 0.018 ms | 5 | 0.006 ms | 26966.627517 s | 26966.627524 s | nvme0q12:137 | 0011 | 0.015 ms | 2 | 0.014 ms | 26966.799588 s | 26966.799602 s | enp5s0-rx-0:164 | 0006 | 0.009 ms | 2 | 0.005 ms | 26966.742024 s | 26966.742028 s | enp5s0-rx-1:165 | 0007 | 0.006 ms | 2 | 0.004 ms | 26966.939486 s | 26966.939490 s | enp5s0-tx-0:166 | 0008 | 0.005 ms | 1 | 0.005 ms | 26966.939484 s | 26966.939489 s | enp5s0-tx-1:167 | 0009 | 0.005 ms | 1 | 0.005 ms | 26966.939484 s | 26966.939489 s | -------------------------------------------------------------------------------------------------------------------------------- #t Signed-off-by: Yang Jihong <yangjihong1@huawei.com> Tested-by: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Alexander Shishkin <alexander.shishkin@linux.intel.com> Cc: Ingo Molnar <mingo@redhat.com> Cc: Jiri Olsa <jolsa@kernel.org> Cc: Mark Rutland <mark.rutland@arm.com> Cc: Namhyung Kim <namhyung@kernel.org> Cc: Paul Clarke <pc@us.ibm.com> Cc: Peter Zijlstra <peterz@infradead.org> Link: https://lore.kernel.org/r/20220709015033.38326-16-yangjihong1@huawei.com Signed-off-by: Arnaldo Carvalho de Melo <acme@redhat.com>
This commit is contained in:
Родитель
daf07d2207
Коммит
420298aefe
|
@ -62,9 +62,45 @@ void perf_kwork__trace_finish(void)
|
|||
skel->bss->enabled = 0;
|
||||
}
|
||||
|
||||
static int get_work_name_from_map(struct work_key *key, char **ret_name)
|
||||
{
|
||||
char name[MAX_KWORKNAME] = { 0 };
|
||||
int fd = bpf_map__fd(skel->maps.perf_kwork_names);
|
||||
|
||||
*ret_name = NULL;
|
||||
|
||||
if (fd < 0) {
|
||||
pr_debug("Invalid names map fd\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((bpf_map_lookup_elem(fd, key, name) == 0) && (strlen(name) != 0)) {
|
||||
*ret_name = strdup(name);
|
||||
if (*ret_name == NULL) {
|
||||
pr_err("Failed to copy work name\n");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void irq_load_prepare(struct perf_kwork *kwork)
|
||||
{
|
||||
if (kwork->report == KWORK_REPORT_RUNTIME) {
|
||||
bpf_program__set_autoload(skel->progs.report_irq_handler_entry, true);
|
||||
bpf_program__set_autoload(skel->progs.report_irq_handler_exit, true);
|
||||
}
|
||||
}
|
||||
|
||||
static struct kwork_class_bpf kwork_irq_bpf = {
|
||||
.load_prepare = irq_load_prepare,
|
||||
.get_work_name = get_work_name_from_map,
|
||||
};
|
||||
|
||||
static struct kwork_class_bpf *
|
||||
kwork_class_bpf_supported_list[KWORK_CLASS_MAX] = {
|
||||
[KWORK_CLASS_IRQ] = NULL,
|
||||
[KWORK_CLASS_IRQ] = &kwork_irq_bpf,
|
||||
[KWORK_CLASS_SOFTIRQ] = NULL,
|
||||
[KWORK_CLASS_WORKQUEUE] = NULL,
|
||||
};
|
||||
|
|
|
@ -71,4 +71,154 @@ int enabled = 0;
|
|||
int has_cpu_filter = 0;
|
||||
int has_name_filter = 0;
|
||||
|
||||
static __always_inline int local_strncmp(const char *s1,
|
||||
unsigned int sz, const char *s2)
|
||||
{
|
||||
int ret = 0;
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < sz; i++) {
|
||||
ret = (unsigned char)s1[i] - (unsigned char)s2[i];
|
||||
if (ret || !s1[i] || !s2[i])
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static __always_inline int trace_event_match(struct work_key *key, char *name)
|
||||
{
|
||||
__u8 *cpu_val;
|
||||
char *name_val;
|
||||
__u32 zero = 0;
|
||||
__u32 cpu = bpf_get_smp_processor_id();
|
||||
|
||||
if (!enabled)
|
||||
return 0;
|
||||
|
||||
if (has_cpu_filter) {
|
||||
cpu_val = bpf_map_lookup_elem(&perf_kwork_cpu_filter, &cpu);
|
||||
if (!cpu_val)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (has_name_filter && (name != NULL)) {
|
||||
name_val = bpf_map_lookup_elem(&perf_kwork_name_filter, &zero);
|
||||
if (name_val &&
|
||||
(local_strncmp(name_val, MAX_KWORKNAME, name) != 0)) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static __always_inline void do_update_time(void *map, struct work_key *key,
|
||||
__u64 time_start, __u64 time_end)
|
||||
{
|
||||
struct report_data zero, *data;
|
||||
__s64 delta = time_end - time_start;
|
||||
|
||||
if (delta < 0)
|
||||
return;
|
||||
|
||||
data = bpf_map_lookup_elem(map, key);
|
||||
if (!data) {
|
||||
__builtin_memset(&zero, 0, sizeof(zero));
|
||||
bpf_map_update_elem(map, key, &zero, BPF_NOEXIST);
|
||||
data = bpf_map_lookup_elem(map, key);
|
||||
if (!data)
|
||||
return;
|
||||
}
|
||||
|
||||
if ((delta > data->max_time) ||
|
||||
(data->max_time == 0)) {
|
||||
data->max_time = delta;
|
||||
data->max_time_start = time_start;
|
||||
data->max_time_end = time_end;
|
||||
}
|
||||
|
||||
data->total_time += delta;
|
||||
data->nr++;
|
||||
}
|
||||
|
||||
static __always_inline void do_update_timestart(void *map, struct work_key *key)
|
||||
{
|
||||
__u64 ts = bpf_ktime_get_ns();
|
||||
|
||||
bpf_map_update_elem(map, key, &ts, BPF_ANY);
|
||||
}
|
||||
|
||||
static __always_inline void do_update_timeend(void *report_map, void *time_map,
|
||||
struct work_key *key)
|
||||
{
|
||||
__u64 *time = bpf_map_lookup_elem(time_map, key);
|
||||
|
||||
if (time) {
|
||||
bpf_map_delete_elem(time_map, key);
|
||||
do_update_time(report_map, key, *time, bpf_ktime_get_ns());
|
||||
}
|
||||
}
|
||||
|
||||
static __always_inline void do_update_name(void *map,
|
||||
struct work_key *key, char *name)
|
||||
{
|
||||
if (!bpf_map_lookup_elem(map, key))
|
||||
bpf_map_update_elem(map, key, name, BPF_ANY);
|
||||
}
|
||||
|
||||
static __always_inline int update_timestart_and_name(void *time_map,
|
||||
void *names_map,
|
||||
struct work_key *key,
|
||||
char *name)
|
||||
{
|
||||
if (!trace_event_match(key, name))
|
||||
return 0;
|
||||
|
||||
do_update_timestart(time_map, key);
|
||||
do_update_name(names_map, key, name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static __always_inline int update_timeend(void *report_map,
|
||||
void *time_map, struct work_key *key)
|
||||
{
|
||||
if (!trace_event_match(key, NULL))
|
||||
return 0;
|
||||
|
||||
do_update_timeend(report_map, time_map, key);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
SEC("tracepoint/irq/irq_handler_entry")
|
||||
int report_irq_handler_entry(struct trace_event_raw_irq_handler_entry *ctx)
|
||||
{
|
||||
char name[MAX_KWORKNAME];
|
||||
struct work_key key = {
|
||||
.type = KWORK_CLASS_IRQ,
|
||||
.cpu = bpf_get_smp_processor_id(),
|
||||
.id = (__u64)ctx->irq,
|
||||
};
|
||||
void *name_addr = (void *)ctx + (ctx->__data_loc_name & 0xffff);
|
||||
|
||||
bpf_probe_read_kernel_str(name, sizeof(name), name_addr);
|
||||
|
||||
return update_timestart_and_name(&perf_kwork_time,
|
||||
&perf_kwork_names, &key, name);
|
||||
}
|
||||
|
||||
SEC("tracepoint/irq/irq_handler_exit")
|
||||
int report_irq_handler_exit(struct trace_event_raw_irq_handler_exit *ctx)
|
||||
{
|
||||
struct work_key key = {
|
||||
.type = KWORK_CLASS_IRQ,
|
||||
.cpu = bpf_get_smp_processor_id(),
|
||||
.id = (__u64)ctx->irq,
|
||||
};
|
||||
|
||||
return update_timeend(&perf_kwork_report, &perf_kwork_time, &key);
|
||||
}
|
||||
|
||||
char LICENSE[] SEC("license") = "Dual BSD/GPL";
|
||||
|
|
Загрузка…
Ссылка в новой задаче