diff mbox series

[RFC,1/1] sample: bpf: introduce irqlat

Message ID 1649927255-19036-1-git-send-email-chensong_2000@189.cn (mailing list archive)
State RFC
Delegated to: BPF
Headers show
Series [RFC,1/1] sample: bpf: introduce irqlat | expand

Checks

Context Check Description
bpf/vmtest-bpf-next-PR fail PR summary
bpf/vmtest-bpf-next-VM_Test-1 fail Logs for Kernel LATEST on ubuntu-latest + selftests
bpf/vmtest-bpf-next-VM_Test-2 fail Logs for Kernel LATEST on z15 + selftests
netdev/tree_selection success Not a local patch, async

Commit Message

Song Chen April 14, 2022, 9:07 a.m. UTC
irqlat presents max, min and avg value of time consumed in
irq handling for each cpu, from irq_handler_entry to
irq_handler_exit.

engineers can run it to evaluate the performance of irq handling,
especially for RT system.

Signed-off-by: Song Chen <chensong_2000@189.cn>
---
 samples/bpf/.gitignore    |   1 +
 samples/bpf/Makefile      |   5 ++
 samples/bpf/irqlat_kern.c |  81 ++++++++++++++++++++++++++++++
 samples/bpf/irqlat_user.c | 100 ++++++++++++++++++++++++++++++++++++++
 4 files changed, 187 insertions(+)
 create mode 100644 samples/bpf/irqlat_kern.c
 create mode 100644 samples/bpf/irqlat_user.c
diff mbox series

Patch

diff --git a/samples/bpf/.gitignore b/samples/bpf/.gitignore
index 0e7bfdbff80a..2d727f041f51 100644
--- a/samples/bpf/.gitignore
+++ b/samples/bpf/.gitignore
@@ -61,3 +61,4 @@  iperf.*
 /vmlinux.h
 /bpftool/
 /libbpf/
+irqlat
diff --git a/samples/bpf/Makefile b/samples/bpf/Makefile
index 38638845db9d..df2daab128f0 100644
--- a/samples/bpf/Makefile
+++ b/samples/bpf/Makefile
@@ -60,6 +60,8 @@  tprogs-y += xdp_redirect_map
 tprogs-y += xdp_redirect
 tprogs-y += xdp_monitor
 
+tprogs-y += irqlat
+
 # Libbpf dependencies
 LIBBPF_SRC = $(TOOLS_PATH)/lib/bpf
 LIBBPF_OUTPUT = $(abspath $(BPF_SAMPLES_PATH))/libbpf
@@ -125,6 +127,8 @@  xdp_redirect_map-objs := xdp_redirect_map_user.o $(XDP_SAMPLE)
 xdp_redirect-objs := xdp_redirect_user.o $(XDP_SAMPLE)
 xdp_monitor-objs := xdp_monitor_user.o $(XDP_SAMPLE)
 
+irqlat-objs := irqlat_user.o
+
 # Tell kbuild to always build the programs
 always-y := $(tprogs-y)
 always-y += sockex1_kern.o
@@ -181,6 +185,7 @@  always-y += ibumad_kern.o
 always-y += hbm_out_kern.o
 always-y += hbm_edt_kern.o
 always-y += xdpsock_kern.o
+always-y += irqlat_kern.o
 
 ifeq ($(ARCH), arm)
 # Strip all except -D__LINUX_ARM_ARCH__ option needed to handle linux
diff --git a/samples/bpf/irqlat_kern.c b/samples/bpf/irqlat_kern.c
new file mode 100644
index 000000000000..0037dcda67cf
--- /dev/null
+++ b/samples/bpf/irqlat_kern.c
@@ -0,0 +1,81 @@ 
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2022 Kylin
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of version 2 of the GNU General Public
+ * License as published by the Free Software Foundation.
+ */
+#include <linux/version.h>
+#include <linux/ptrace.h>
+#include <uapi/linux/bpf.h>
+#include <bpf/bpf_helpers.h>
+
+#define MAX_CPUS		128
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, int);
+	__type(value, u64);
+	__uint(max_entries, MAX_CPUS);
+} irq_ts SEC(".maps");
+
+SEC("tracepoint/irq/irq_handler_entry")
+int on_irq_entry(struct pt_regs *ctx)
+{
+	int cpu = bpf_get_smp_processor_id();
+	u64 *ts = bpf_map_lookup_elem(&irq_ts, &cpu);
+
+	if (ts)
+		*ts = bpf_ktime_get_ns();
+
+	return 0;
+}
+
+struct datares {
+	u64 entries;
+	u64 total;
+	u64 max;
+	u64 min;
+};
+
+struct {
+	__uint(type, BPF_MAP_TYPE_ARRAY);
+	__type(key, int);
+	__type(value, struct datares);
+	__uint(max_entries, MAX_CPUS);
+} irq_lat SEC(".maps");
+
+SEC("tracepoint/irq/irq_handler_exit")
+int on_irq_exit(struct pt_regs *ctx)
+{
+	u64 *ts, cur_ts, delta, *val;
+	int cpu;
+	struct datares *res;
+
+	cpu = bpf_get_smp_processor_id();
+	ts = bpf_map_lookup_elem(&irq_ts, &cpu);
+	if (!ts)
+		return 0;
+
+	cur_ts = bpf_ktime_get_ns();
+	delta = cur_ts - *ts;
+
+	res = bpf_map_lookup_elem(&irq_lat, &cpu);
+	if (!res)
+		return 0;
+
+	res->entries++;
+	res->total += delta;
+	if (res->max < delta)
+		res->max = delta;
+	if (res->min == 0 || res->min > delta)
+		res->min = delta;
+
+	if (res->total >= U64_MAX)
+		__builtin_memset(res, 0, sizeof(struct datares));
+
+	return 0;
+}
+
+char _license[] SEC("license") = "GPL";
diff --git a/samples/bpf/irqlat_user.c b/samples/bpf/irqlat_user.c
new file mode 100644
index 000000000000..3a5a43b9fce9
--- /dev/null
+++ b/samples/bpf/irqlat_user.c
@@ -0,0 +1,100 @@ 
+// SPDX-License-Identifier: GPL-2.0-only
+/*
+ * Copyright (c) 2022 Kylin
+ */
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <linux/perf_event.h>
+#include <linux/bpf.h>
+#include <bpf/libbpf.h>
+#include <bpf/bpf.h>
+#include "trace_helpers.h"
+
+#define MAX_CPUS 128
+static int map_fd[2];
+
+struct datares {
+	__u64 entries;
+	__u64 total;
+	__u64 max;
+	__u64 min;
+};
+
+static void get_data(int fd)
+{
+	int i;
+	struct datares res;
+	__u64 avg;
+
+	/* Clear screen */
+	printf("\033[2J");
+
+	/* Header */
+	printf("\nirq Latency statistics: (ns)\n");
+	for (i = 0; i < MAX_CPUS; i++) {
+		bpf_map_lookup_elem(fd, &i, &res);
+
+		if (res.entries == 0)
+			continue;
+
+		avg = res.total / res.entries;
+		printf("cpu:%d, max:%llu, min:%llu, avg:%llu\n",
+					i, res.max, res.min, avg);
+	}
+}
+
+int main(int argc, char **argv)
+{
+	char filename[256];
+	struct bpf_object *obj = NULL;
+	struct bpf_link *links[2];
+	struct bpf_program *prog;
+	int delay = 1, i = 0;
+
+	snprintf(filename, sizeof(filename), "%s_kern.o", argv[0]);
+
+	obj = bpf_object__open_file(filename, NULL);
+	if (libbpf_get_error(obj)) {
+		fprintf(stderr, "ERROR: opening BPF object file failed\n");
+		obj = NULL;
+		goto cleanup;
+	}
+
+	/* load BPF program */
+	if (bpf_object__load(obj)) {
+		fprintf(stderr, "ERROR: loading BPF object file failed\n");
+		goto cleanup;
+	}
+
+	map_fd[0] = bpf_object__find_map_fd_by_name(obj, "irq_ts");
+	map_fd[1] = bpf_object__find_map_fd_by_name(obj, "irq_lat");
+	if (map_fd[0] < 0 || map_fd[1] < 0) {
+		fprintf(stderr, "ERROR: finding a map in obj file failed\n");
+		goto cleanup;
+	}
+
+	bpf_object__for_each_program(prog, obj) {
+		links[i] = bpf_program__attach(prog);
+		if (libbpf_get_error(links[i])) {
+			fprintf(stderr, "ERROR: bpf_program__attach failed\n");
+			links[i] = NULL;
+			goto cleanup;
+		}
+		i++;
+	}
+
+	while (1) {
+		sleep(delay);
+		get_data(map_fd[1]);
+	}
+
+cleanup:
+	for (i--; i >= 0; i--)
+		bpf_link__destroy(links[i]);
+
+	bpf_object__close(obj);
+	return 0;
+}