@@ -79,6 +79,7 @@ static u16 opt_pkt_size = MIN_PKT_SIZE;
7979static u32 opt_pkt_fill_pattern = 0x12345678 ;
8080static bool opt_extra_stats ;
8181static bool opt_quiet ;
82+ static bool opt_app_stats ;
8283static int opt_poll ;
8384static int opt_interval = 1 ;
8485static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP ;
@@ -110,6 +111,19 @@ struct xsk_ring_stats {
110111 unsigned long prev_tx_empty_npkts ;
111112};
112113
114+ struct xsk_app_stats {
115+ unsigned long rx_empty_polls ;
116+ unsigned long fill_fail_polls ;
117+ unsigned long copy_tx_sendtos ;
118+ unsigned long tx_wakeup_sendtos ;
119+ unsigned long opt_polls ;
120+ unsigned long prev_rx_empty_polls ;
121+ unsigned long prev_fill_fail_polls ;
122+ unsigned long prev_copy_tx_sendtos ;
123+ unsigned long prev_tx_wakeup_sendtos ;
124+ unsigned long prev_opt_polls ;
125+ };
126+
113127struct xsk_umem_info {
114128 struct xsk_ring_prod fq ;
115129 struct xsk_ring_cons cq ;
@@ -123,6 +137,7 @@ struct xsk_socket_info {
123137 struct xsk_umem_info * umem ;
124138 struct xsk_socket * xsk ;
125139 struct xsk_ring_stats ring_stats ;
140+ struct xsk_app_stats app_stats ;
126141 u32 outstanding_tx ;
127142};
128143
@@ -189,6 +204,45 @@ static int xsk_get_xdp_stats(int fd, struct xsk_socket_info *xsk)
189204 return - EINVAL ;
190205}
191206
207+ static void dump_app_stats (long dt )
208+ {
209+ int i ;
210+
211+ for (i = 0 ; i < num_socks && xsks [i ]; i ++ ) {
212+ char * fmt = "%-18s %'-14.0f %'-14lu\n" ;
213+ double rx_empty_polls_ps , fill_fail_polls_ps , copy_tx_sendtos_ps ,
214+ tx_wakeup_sendtos_ps , opt_polls_ps ;
215+
216+ rx_empty_polls_ps = (xsks [i ]-> app_stats .rx_empty_polls -
217+ xsks [i ]-> app_stats .prev_rx_empty_polls ) * 1000000000. / dt ;
218+ fill_fail_polls_ps = (xsks [i ]-> app_stats .fill_fail_polls -
219+ xsks [i ]-> app_stats .prev_fill_fail_polls ) * 1000000000. / dt ;
220+ copy_tx_sendtos_ps = (xsks [i ]-> app_stats .copy_tx_sendtos -
221+ xsks [i ]-> app_stats .prev_copy_tx_sendtos ) * 1000000000. / dt ;
222+ tx_wakeup_sendtos_ps = (xsks [i ]-> app_stats .tx_wakeup_sendtos -
223+ xsks [i ]-> app_stats .prev_tx_wakeup_sendtos )
224+ * 1000000000. / dt ;
225+ opt_polls_ps = (xsks [i ]-> app_stats .opt_polls -
226+ xsks [i ]-> app_stats .prev_opt_polls ) * 1000000000. / dt ;
227+
228+ printf ("\n%-18s %-14s %-14s\n" , "" , "calls/s" , "count" );
229+ printf (fmt , "rx empty polls" , rx_empty_polls_ps , xsks [i ]-> app_stats .rx_empty_polls );
230+ printf (fmt , "fill fail polls" , fill_fail_polls_ps ,
231+ xsks [i ]-> app_stats .fill_fail_polls );
232+ printf (fmt , "copy tx sendtos" , copy_tx_sendtos_ps ,
233+ xsks [i ]-> app_stats .copy_tx_sendtos );
234+ printf (fmt , "tx wakeup sendtos" , tx_wakeup_sendtos_ps ,
235+ xsks [i ]-> app_stats .tx_wakeup_sendtos );
236+ printf (fmt , "opt polls" , opt_polls_ps , xsks [i ]-> app_stats .opt_polls );
237+
238+ xsks [i ]-> app_stats .prev_rx_empty_polls = xsks [i ]-> app_stats .rx_empty_polls ;
239+ xsks [i ]-> app_stats .prev_fill_fail_polls = xsks [i ]-> app_stats .fill_fail_polls ;
240+ xsks [i ]-> app_stats .prev_copy_tx_sendtos = xsks [i ]-> app_stats .copy_tx_sendtos ;
241+ xsks [i ]-> app_stats .prev_tx_wakeup_sendtos = xsks [i ]-> app_stats .tx_wakeup_sendtos ;
242+ xsks [i ]-> app_stats .prev_opt_polls = xsks [i ]-> app_stats .opt_polls ;
243+ }
244+ }
245+
192246static void dump_stats (void )
193247{
194248 unsigned long now = get_nsecs ();
@@ -198,7 +252,7 @@ static void dump_stats(void)
198252 prev_time = now ;
199253
200254 for (i = 0 ; i < num_socks && xsks [i ]; i ++ ) {
201- char * fmt = "%-15s %'-11 .0f %'-11lu \n" ;
255+ char * fmt = "%-18s %'-14 .0f %'-14lu \n" ;
202256 double rx_pps , tx_pps , dropped_pps , rx_invalid_pps , full_pps , fill_empty_pps ,
203257 tx_invalid_pps , tx_empty_pps ;
204258
@@ -211,7 +265,7 @@ static void dump_stats(void)
211265 print_benchmark (false);
212266 printf ("\n" );
213267
214- printf ("%-15s %-11s %-11s %-11 .2f\n" , "" , "pps" , "pkts" ,
268+ printf ("%-18s %-14s %-14s %-14 .2f\n" , "" , "pps" , "pkts" ,
215269 dt / 1000000000. );
216270 printf (fmt , "rx" , rx_pps , xsks [i ]-> ring_stats .rx_npkts );
217271 printf (fmt , "tx" , tx_pps , xsks [i ]-> ring_stats .tx_npkts );
@@ -270,6 +324,9 @@ static void dump_stats(void)
270324 }
271325 }
272326 }
327+
328+ if (opt_app_stats )
329+ dump_app_stats (dt );
273330}
274331
275332static bool is_benchmark_done (void )
@@ -708,6 +765,17 @@ static struct xsk_socket_info *xsk_configure_socket(struct xsk_umem_info *umem,
708765 if (ret )
709766 exit_with_error (- ret );
710767
768+ xsk -> app_stats .rx_empty_polls = 0 ;
769+ xsk -> app_stats .fill_fail_polls = 0 ;
770+ xsk -> app_stats .copy_tx_sendtos = 0 ;
771+ xsk -> app_stats .tx_wakeup_sendtos = 0 ;
772+ xsk -> app_stats .opt_polls = 0 ;
773+ xsk -> app_stats .prev_rx_empty_polls = 0 ;
774+ xsk -> app_stats .prev_fill_fail_polls = 0 ;
775+ xsk -> app_stats .prev_copy_tx_sendtos = 0 ;
776+ xsk -> app_stats .prev_tx_wakeup_sendtos = 0 ;
777+ xsk -> app_stats .prev_opt_polls = 0 ;
778+
711779 return xsk ;
712780}
713781
@@ -735,6 +803,7 @@ static struct option long_options[] = {
735803 {"tx-pkt-pattern" , required_argument , 0 , 'P' },
736804 {"extra-stats" , no_argument , 0 , 'x' },
737805 {"quiet" , no_argument , 0 , 'Q' },
806+ {"app-stats" , no_argument , 0 , 'a' },
738807 {0 , 0 , 0 , 0 }
739808};
740809
@@ -771,6 +840,7 @@ static void usage(const char *prog)
771840 " -P, --tx-pkt-pattern=nPacket fill pattern. Default: 0x%x\n"
772841 " -x, --extra-stats Display extra statistics.\n"
773842 " -Q, --quiet Do not display any stats.\n"
843+ " -a, --app-stats Display application (syscall) statistics.\n"
774844 "\n" ;
775845 fprintf (stderr , str , prog , XSK_UMEM__DEFAULT_FRAME_SIZE ,
776846 opt_batch_size , MIN_PKT_SIZE , MIN_PKT_SIZE ,
@@ -786,7 +856,7 @@ static void parse_command_line(int argc, char **argv)
786856 opterr = 0 ;
787857
788858 for (;;) {
789- c = getopt_long (argc , argv , "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQ " ,
859+ c = getopt_long (argc , argv , "Frtli:q:pSNn:czf:muMd:b:C:s:P:xQa " ,
790860 long_options , & option_index );
791861 if (c == -1 )
792862 break ;
@@ -873,6 +943,9 @@ static void parse_command_line(int argc, char **argv)
873943 case 'Q' :
874944 opt_quiet = 1 ;
875945 break ;
946+ case 'a' :
947+ opt_app_stats = 1 ;
948+ break ;
876949 default :
877950 usage (basename (argv [0 ]));
878951 }
@@ -923,8 +996,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk,
923996 * is driven by the NAPI loop. So as an optimization, we do not have to call
924997 * sendto() all the time in zero-copy mode for l2fwd.
925998 */
926- if (opt_xdp_bind_flags & XDP_COPY )
999+ if (opt_xdp_bind_flags & XDP_COPY ) {
1000+ xsk -> app_stats .copy_tx_sendtos ++ ;
9271001 kick_tx (xsk );
1002+ }
9281003
9291004 ndescs = (xsk -> outstanding_tx > opt_batch_size ) ? opt_batch_size :
9301005 xsk -> outstanding_tx ;
@@ -939,8 +1014,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk,
9391014 while (ret != rcvd ) {
9401015 if (ret < 0 )
9411016 exit_with_error (- ret );
942- if (xsk_ring_prod__needs_wakeup (& umem -> fq ))
1017+ if (xsk_ring_prod__needs_wakeup (& umem -> fq )) {
1018+ xsk -> app_stats .fill_fail_polls ++ ;
9431019 ret = poll (fds , num_socks , opt_timeout );
1020+ }
9441021 ret = xsk_ring_prod__reserve (& umem -> fq , rcvd , & idx_fq );
9451022 }
9461023
@@ -964,8 +1041,10 @@ static inline void complete_tx_only(struct xsk_socket_info *xsk,
9641041 if (!xsk -> outstanding_tx )
9651042 return ;
9661043
967- if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup (& xsk -> tx ))
1044+ if (!opt_need_wakeup || xsk_ring_prod__needs_wakeup (& xsk -> tx )) {
1045+ xsk -> app_stats .tx_wakeup_sendtos ++ ;
9681046 kick_tx (xsk );
1047+ }
9691048
9701049 rcvd = xsk_ring_cons__peek (& xsk -> umem -> cq , batch_size , & idx );
9711050 if (rcvd > 0 ) {
@@ -983,17 +1062,21 @@ static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds)
9831062
9841063 rcvd = xsk_ring_cons__peek (& xsk -> rx , opt_batch_size , & idx_rx );
9851064 if (!rcvd ) {
986- if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq ))
1065+ if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq )) {
1066+ xsk -> app_stats .rx_empty_polls ++ ;
9871067 ret = poll (fds , num_socks , opt_timeout );
1068+ }
9881069 return ;
9891070 }
9901071
9911072 ret = xsk_ring_prod__reserve (& xsk -> umem -> fq , rcvd , & idx_fq );
9921073 while (ret != rcvd ) {
9931074 if (ret < 0 )
9941075 exit_with_error (- ret );
995- if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq ))
1076+ if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq )) {
1077+ xsk -> app_stats .fill_fail_polls ++ ;
9961078 ret = poll (fds , num_socks , opt_timeout );
1079+ }
9971080 ret = xsk_ring_prod__reserve (& xsk -> umem -> fq , rcvd , & idx_fq );
9981081 }
9991082
@@ -1026,6 +1109,8 @@ static void rx_drop_all(void)
10261109
10271110 for (;;) {
10281111 if (opt_poll ) {
1112+ for (i = 0 ; i < num_socks ; i ++ )
1113+ xsks [i ]-> app_stats .opt_polls ++ ;
10291114 ret = poll (fds , num_socks , opt_timeout );
10301115 if (ret <= 0 )
10311116 continue ;
@@ -1106,6 +1191,8 @@ static void tx_only_all(void)
11061191 int batch_size = get_batch_size (pkt_cnt );
11071192
11081193 if (opt_poll ) {
1194+ for (i = 0 ; i < num_socks ; i ++ )
1195+ xsks [i ]-> app_stats .opt_polls ++ ;
11091196 ret = poll (fds , num_socks , opt_timeout );
11101197 if (ret <= 0 )
11111198 continue ;
@@ -1137,8 +1224,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds)
11371224
11381225 rcvd = xsk_ring_cons__peek (& xsk -> rx , opt_batch_size , & idx_rx );
11391226 if (!rcvd ) {
1140- if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq ))
1227+ if (xsk_ring_prod__needs_wakeup (& xsk -> umem -> fq )) {
1228+ xsk -> app_stats .rx_empty_polls ++ ;
11411229 ret = poll (fds , num_socks , opt_timeout );
1230+ }
11421231 return ;
11431232 }
11441233
@@ -1147,8 +1236,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds)
11471236 if (ret < 0 )
11481237 exit_with_error (- ret );
11491238 complete_tx_l2fwd (xsk , fds );
1150- if (xsk_ring_prod__needs_wakeup (& xsk -> tx ))
1239+ if (xsk_ring_prod__needs_wakeup (& xsk -> tx )) {
1240+ xsk -> app_stats .tx_wakeup_sendtos ++ ;
11511241 kick_tx (xsk );
1242+ }
11521243 ret = xsk_ring_prod__reserve (& xsk -> tx , rcvd , & idx_tx );
11531244 }
11541245
@@ -1186,6 +1277,8 @@ static void l2fwd_all(void)
11861277
11871278 for (;;) {
11881279 if (opt_poll ) {
1280+ for (i = 0 ; i < num_socks ; i ++ )
1281+ xsks [i ]-> app_stats .opt_polls ++ ;
11891282 ret = poll (fds , num_socks , opt_timeout );
11901283 if (ret <= 0 )
11911284 continue ;
0 commit comments