11
11
#include <linux/if_xdp.h>
12
12
#include <linux/if_ether.h>
13
13
#include <linux/ip.h>
14
+ #include <linux/limits.h>
14
15
#include <linux/udp.h>
15
16
#include <arpa/inet.h>
16
17
#include <locale.h>
@@ -80,6 +81,9 @@ static u32 opt_pkt_fill_pattern = 0x12345678;
80
81
static bool opt_extra_stats ;
81
82
static bool opt_quiet ;
82
83
static bool opt_app_stats ;
84
+ static const char * opt_irq_str = "" ;
85
+ static u32 irq_no ;
86
+ static int irqs_at_init = -1 ;
83
87
static int opt_poll ;
84
88
static int opt_interval = 1 ;
85
89
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP ;
@@ -111,6 +115,11 @@ struct xsk_ring_stats {
111
115
unsigned long prev_tx_empty_npkts ;
112
116
};
113
117
118
+ struct xsk_driver_stats {
119
+ unsigned long intrs ;
120
+ unsigned long prev_intrs ;
121
+ };
122
+
114
123
struct xsk_app_stats {
115
124
unsigned long rx_empty_polls ;
116
125
unsigned long fill_fail_polls ;
@@ -138,6 +147,7 @@ struct xsk_socket_info {
138
147
struct xsk_socket * xsk ;
139
148
struct xsk_ring_stats ring_stats ;
140
149
struct xsk_app_stats app_stats ;
150
+ struct xsk_driver_stats drv_stats ;
141
151
u32 outstanding_tx ;
142
152
};
143
153
@@ -243,6 +253,100 @@ static void dump_app_stats(long dt)
243
253
}
244
254
}
245
255
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
+
246
350
static void dump_stats (void )
247
351
{
248
352
unsigned long now = get_nsecs ();
@@ -327,6 +431,8 @@ static void dump_stats(void)
327
431
328
432
if (opt_app_stats )
329
433
dump_app_stats (dt );
434
+ if (irq_no )
435
+ dump_driver_stats (dt );
330
436
}
331
437
332
438
static bool is_benchmark_done (void )
@@ -804,6 +910,7 @@ static struct option long_options[] = {
804
910
{"extra-stats" , no_argument , 0 , 'x' },
805
911
{"quiet" , no_argument , 0 , 'Q' },
806
912
{"app-stats" , no_argument , 0 , 'a' },
913
+ {"irq-string" , no_argument , 0 , 'I' },
807
914
{0 , 0 , 0 , 0 }
808
915
};
809
916
@@ -841,6 +948,7 @@ static void usage(const char *prog)
841
948
" -x, --extra-stats Display extra statistics.\n"
842
949
" -Q, --quiet Do not display any stats.\n"
843
950
" -a, --app-stats Display application (syscall) statistics.\n"
951
+ " -I, --irq-string Display driver interrupt statistics for interface associated with irq-string.\n"
844
952
"\n" ;
845
953
fprintf (stderr , str , prog , XSK_UMEM__DEFAULT_FRAME_SIZE ,
846
954
opt_batch_size , MIN_PKT_SIZE , MIN_PKT_SIZE ,
@@ -856,7 +964,7 @@ static void parse_command_line(int argc, char **argv)
856
964
opterr = 0 ;
857
965
858
966
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: " ,
860
968
long_options , & option_index );
861
969
if (c == -1 )
862
970
break ;
@@ -945,6 +1053,16 @@ static void parse_command_line(int argc, char **argv)
945
1053
break ;
946
1054
case 'a' :
947
1055
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
+
948
1066
break ;
949
1067
default :
950
1068
usage (basename (argv [0 ]));
0 commit comments