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;
8081static bool opt_extra_stats ;
8182static bool opt_quiet ;
8283static bool opt_app_stats ;
84+ static const char * opt_irq_str = "" ;
85+ static u32 irq_no ;
86+ static int irqs_at_init = -1 ;
8387static int opt_poll ;
8488static int opt_interval = 1 ;
8589static 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+
114123struct 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+
246350static 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
332438static 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