Commit 420298ae authored by Yang Jihong's avatar Yang Jihong Committed by Arnaldo Carvalho de Melo
Browse files

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: default avatarYang Jihong <yangjihong1@huawei.com>
Tested-by: default avatarArnaldo 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: default avatarArnaldo Carvalho de Melo <acme@redhat.com>
parent daf07d22
Loading
Loading
Loading
Loading
+37 −1
Original line number Diff line number Diff line
@@ -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,
};
+150 −0
Original line number Diff line number Diff line
@@ -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";