Skip to content

Commit 7483dda

Browse files
cloftuskernel-patches-bot
authored andcommitted
samples: bpf: driver interrupt statistics in xdpsock
Add an option to count the number of interrupts generated per second and total number of interrupts during the lifetime of the application for a given interface. This information is extracted from /proc/interrupts. Since there is no naming convention across drivers, the user must provide the string which is specific to their interface in the /proc/interrupts file on the command line. Usage: ./xdpsock ... -I <irq_str> eg. for queue 0 of i40e device eth0: ./xdpsock ... -I i40e-eth0-TxRx-0 Signed-off-by: Ciara Loftus <ciara.loftus@intel.com>
1 parent 54d5e28 commit 7483dda

File tree

1 file changed

+119
-1
lines changed

1 file changed

+119
-1
lines changed

samples/bpf/xdpsock_user.c

Lines changed: 119 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
#include <linux/if_xdp.h>
1212
#include <linux/if_ether.h>
1313
#include <linux/ip.h>
14+
#include <linux/limits.h>
1415
#include <linux/udp.h>
1516
#include <arpa/inet.h>
1617
#include <locale.h>
@@ -80,6 +81,9 @@ static u32 opt_pkt_fill_pattern = 0x12345678;
8081
static bool opt_extra_stats;
8182
static bool opt_quiet;
8283
static bool opt_app_stats;
84+
static const char *opt_irq_str = "";
85+
static u32 irq_no;
86+
static int irqs_at_init = -1;
8387
static int opt_poll;
8488
static int opt_interval = 1;
8589
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP;
@@ -111,6 +115,11 @@ struct xsk_ring_stats {
111115
unsigned long prev_tx_empty_npkts;
112116
};
113117

118+
struct xsk_driver_stats {
119+
unsigned long intrs;
120+
unsigned long prev_intrs;
121+
};
122+
114123
struct xsk_app_stats {
115124
unsigned long rx_empty_polls;
116125
unsigned long fill_fail_polls;
@@ -138,6 +147,7 @@ struct xsk_socket_info {
138147
struct xsk_socket *xsk;
139148
struct xsk_ring_stats ring_stats;
140149
struct xsk_app_stats app_stats;
150+
struct xsk_driver_stats drv_stats;
141151
u32 outstanding_tx;
142152
};
143153

@@ -243,6 +253,100 @@ static void dump_app_stats(long dt)
243253
}
244254
}
245255

256+
static bool get_interrupt_number(void)
257+
{
258+
FILE *f_int_proc;
259+
char line[4096];
260+
bool found = false;
261+
262+
f_int_proc = fopen("/proc/interrupts", "r");
263+
if (f_int_proc == NULL) {
264+
printf("Failed to open /proc/interrupts.\n");
265+
return found;
266+
}
267+
268+
while (!feof(f_int_proc) && !found) {
269+
/* Make sure to read a full line at a time */
270+
if (fgets(line, sizeof(line), f_int_proc) == NULL ||
271+
line[strlen(line) - 1] != '\n') {
272+
printf("Error reading from interrupts file\n");
273+
break;
274+
}
275+
276+
/* Extract interrupt number from line */
277+
if (strstr(line, opt_irq_str) != NULL) {
278+
irq_no = atoi(line);
279+
found = true;
280+
break;
281+
}
282+
}
283+
284+
fclose(f_int_proc);
285+
286+
return found;
287+
}
288+
289+
static int get_irqs(void)
290+
{
291+
char count_path[PATH_MAX];
292+
int total_intrs = -1;
293+
FILE *f_count_proc;
294+
char line[4096];
295+
296+
snprintf(count_path, sizeof(count_path),
297+
"/sys/kernel/irq/%i/per_cpu_count", irq_no);
298+
f_count_proc = fopen(count_path, "r");
299+
if (f_count_proc == NULL) {
300+
printf("Failed to open %s\n", count_path);
301+
return total_intrs;
302+
}
303+
304+
if (fgets(line, sizeof(line), f_count_proc) == NULL ||
305+
line[strlen(line) - 1] != '\n') {
306+
printf("Error reading from %s\n", count_path);
307+
} else {
308+
static const char com[2] = ",";
309+
char *token;
310+
311+
total_intrs = 0;
312+
token = strtok(line, com);
313+
while (token != NULL) {
314+
/* sum up interrupts across all cores */
315+
total_intrs += atoi(token);
316+
token = strtok(NULL, com);
317+
}
318+
}
319+
320+
fclose(f_count_proc);
321+
322+
return total_intrs;
323+
}
324+
325+
static void dump_driver_stats(long dt)
326+
{
327+
int i;
328+
329+
for (i = 0; i < num_socks && xsks[i]; i++) {
330+
char *fmt = "%-18s %'-14.0f %'-14lu\n";
331+
double intrs_ps;
332+
int n_ints = get_irqs();
333+
334+
if (n_ints < 0) {
335+
printf("error getting intr info for intr %i\n", irq_no);
336+
return;
337+
}
338+
xsks[i]->drv_stats.intrs = n_ints - irqs_at_init;
339+
340+
intrs_ps = (xsks[i]->drv_stats.intrs - xsks[i]->drv_stats.prev_intrs) *
341+
1000000000. / dt;
342+
343+
printf("\n%-18s %-14s %-14s\n", "", "intrs/s", "count");
344+
printf(fmt, "irqs", intrs_ps, xsks[i]->drv_stats.intrs);
345+
346+
xsks[i]->drv_stats.prev_intrs = xsks[i]->drv_stats.intrs;
347+
}
348+
}
349+
246350
static void dump_stats(void)
247351
{
248352
unsigned long now = get_nsecs();
@@ -327,6 +431,8 @@ static void dump_stats(void)
327431

328432
if (opt_app_stats)
329433
dump_app_stats(dt);
434+
if (irq_no)
435+
dump_driver_stats(dt);
330436
}
331437

332438
static bool is_benchmark_done(void)
@@ -804,6 +910,7 @@ static struct option long_options[] = {
804910
{"extra-stats", no_argument, 0, 'x'},
805911
{"quiet", no_argument, 0, 'Q'},
806912
{"app-stats", no_argument, 0, 'a'},
913+
{"irq-string", no_argument, 0, 'I'},
807914
{0, 0, 0, 0}
808915
};
809916

@@ -841,6 +948,7 @@ static void usage(const char *prog)
841948
" -x, --extra-stats Display extra statistics.\n"
842949
" -Q, --quiet Do not display any stats.\n"
843950
" -a, --app-stats Display application (syscall) statistics.\n"
951+
" -I, --irq-string Display driver interrupt statistics for interface associated with irq-string.\n"
844952
"\n";
845953
fprintf(stderr, str, prog, XSK_UMEM__DEFAULT_FRAME_SIZE,
846954
opt_batch_size, MIN_PKT_SIZE, MIN_PKT_SIZE,
@@ -856,7 +964,7 @@ static void parse_command_line(int argc, char **argv)
856964
opterr = 0;
857965

858966
for (;;) {
859-
c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQa",
967+
c = getopt_long(argc, argv, "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQaI:",
860968
long_options, &option_index);
861969
if (c == -1)
862970
break;
@@ -945,6 +1053,16 @@ static void parse_command_line(int argc, char **argv)
9451053
break;
9461054
case 'a':
9471055
opt_app_stats = 1;
1056+
break;
1057+
case 'I':
1058+
opt_irq_str = optarg;
1059+
if (get_interrupt_number())
1060+
irqs_at_init = get_irqs();
1061+
if (irqs_at_init < 0) {
1062+
fprintf(stderr, "ERROR: Failed to get irqs for %s\n", opt_irq_str);
1063+
usage(basename(argv[0]));
1064+
}
1065+
9481066
break;
9491067
default:
9501068
usage(basename(argv[0]));

0 commit comments

Comments
 (0)