@@ -79,6 +79,7 @@ static u16 opt_pkt_size = MIN_PKT_SIZE;
79
79
static u32 opt_pkt_fill_pattern = 0x12345678 ;
80
80
static bool opt_extra_stats ;
81
81
static bool opt_quiet ;
82
+ static bool opt_app_stats ;
82
83
static int opt_poll ;
83
84
static int opt_interval = 1 ;
84
85
static u32 opt_xdp_bind_flags = XDP_USE_NEED_WAKEUP ;
@@ -110,6 +111,19 @@ struct xsk_ring_stats {
110
111
unsigned long prev_tx_empty_npkts ;
111
112
};
112
113
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
+
113
127
struct xsk_umem_info {
114
128
struct xsk_ring_prod fq ;
115
129
struct xsk_ring_cons cq ;
@@ -123,6 +137,7 @@ struct xsk_socket_info {
123
137
struct xsk_umem_info * umem ;
124
138
struct xsk_socket * xsk ;
125
139
struct xsk_ring_stats ring_stats ;
140
+ struct xsk_app_stats app_stats ;
126
141
u32 outstanding_tx ;
127
142
};
128
143
@@ -189,6 +204,45 @@ static int xsk_get_xdp_stats(int fd, struct xsk_socket_info *xsk)
189
204
return - EINVAL ;
190
205
}
191
206
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
+
192
246
static void dump_stats (void )
193
247
{
194
248
unsigned long now = get_nsecs ();
@@ -198,7 +252,7 @@ static void dump_stats(void)
198
252
prev_time = now ;
199
253
200
254
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" ;
202
256
double rx_pps , tx_pps , dropped_pps , rx_invalid_pps , full_pps , fill_empty_pps ,
203
257
tx_invalid_pps , tx_empty_pps ;
204
258
@@ -211,7 +265,7 @@ static void dump_stats(void)
211
265
print_benchmark (false);
212
266
printf ("\n" );
213
267
214
- printf ("%-15s %-11s %-11s %-11 .2f\n" , "" , "pps" , "pkts" ,
268
+ printf ("%-18s %-14s %-14s %-14 .2f\n" , "" , "pps" , "pkts" ,
215
269
dt / 1000000000. );
216
270
printf (fmt , "rx" , rx_pps , xsks [i ]-> ring_stats .rx_npkts );
217
271
printf (fmt , "tx" , tx_pps , xsks [i ]-> ring_stats .tx_npkts );
@@ -270,6 +324,9 @@ static void dump_stats(void)
270
324
}
271
325
}
272
326
}
327
+
328
+ if (opt_app_stats )
329
+ dump_app_stats (dt );
273
330
}
274
331
275
332
static bool is_benchmark_done (void )
@@ -708,6 +765,17 @@ static struct xsk_socket_info *xsk_configure_socket(struct xsk_umem_info *umem,
708
765
if (ret )
709
766
exit_with_error (- ret );
710
767
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
+
711
779
return xsk ;
712
780
}
713
781
@@ -735,6 +803,7 @@ static struct option long_options[] = {
735
803
{"tx-pkt-pattern" , required_argument , 0 , 'P' },
736
804
{"extra-stats" , no_argument , 0 , 'x' },
737
805
{"quiet" , no_argument , 0 , 'Q' },
806
+ {"app-stats" , no_argument , 0 , 'a' },
738
807
{0 , 0 , 0 , 0 }
739
808
};
740
809
@@ -771,6 +840,7 @@ static void usage(const char *prog)
771
840
" -P, --tx-pkt-pattern=nPacket fill pattern. Default: 0x%x\n"
772
841
" -x, --extra-stats Display extra statistics.\n"
773
842
" -Q, --quiet Do not display any stats.\n"
843
+ " -a, --app-stats Display application (syscall) statistics.\n"
774
844
"\n" ;
775
845
fprintf (stderr , str , prog , XSK_UMEM__DEFAULT_FRAME_SIZE ,
776
846
opt_batch_size , MIN_PKT_SIZE , MIN_PKT_SIZE ,
@@ -786,7 +856,7 @@ static void parse_command_line(int argc, char **argv)
786
856
opterr = 0 ;
787
857
788
858
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 " ,
790
860
long_options , & option_index );
791
861
if (c == -1 )
792
862
break ;
@@ -873,6 +943,9 @@ static void parse_command_line(int argc, char **argv)
873
943
case 'Q' :
874
944
opt_quiet = 1 ;
875
945
break ;
946
+ case 'a' :
947
+ opt_app_stats = 1 ;
948
+ break ;
876
949
default :
877
950
usage (basename (argv [0 ]));
878
951
}
@@ -923,8 +996,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk,
923
996
* is driven by the NAPI loop. So as an optimization, we do not have to call
924
997
* sendto() all the time in zero-copy mode for l2fwd.
925
998
*/
926
- if (opt_xdp_bind_flags & XDP_COPY )
999
+ if (opt_xdp_bind_flags & XDP_COPY ) {
1000
+ xsk -> app_stats .copy_tx_sendtos ++ ;
927
1001
kick_tx (xsk );
1002
+ }
928
1003
929
1004
ndescs = (xsk -> outstanding_tx > opt_batch_size ) ? opt_batch_size :
930
1005
xsk -> outstanding_tx ;
@@ -939,8 +1014,10 @@ static inline void complete_tx_l2fwd(struct xsk_socket_info *xsk,
939
1014
while (ret != rcvd ) {
940
1015
if (ret < 0 )
941
1016
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 ++ ;
943
1019
ret = poll (fds , num_socks , opt_timeout );
1020
+ }
944
1021
ret = xsk_ring_prod__reserve (& umem -> fq , rcvd , & idx_fq );
945
1022
}
946
1023
@@ -964,8 +1041,10 @@ static inline void complete_tx_only(struct xsk_socket_info *xsk,
964
1041
if (!xsk -> outstanding_tx )
965
1042
return ;
966
1043
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 ++ ;
968
1046
kick_tx (xsk );
1047
+ }
969
1048
970
1049
rcvd = xsk_ring_cons__peek (& xsk -> umem -> cq , batch_size , & idx );
971
1050
if (rcvd > 0 ) {
@@ -983,17 +1062,21 @@ static void rx_drop(struct xsk_socket_info *xsk, struct pollfd *fds)
983
1062
984
1063
rcvd = xsk_ring_cons__peek (& xsk -> rx , opt_batch_size , & idx_rx );
985
1064
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 ++ ;
987
1067
ret = poll (fds , num_socks , opt_timeout );
1068
+ }
988
1069
return ;
989
1070
}
990
1071
991
1072
ret = xsk_ring_prod__reserve (& xsk -> umem -> fq , rcvd , & idx_fq );
992
1073
while (ret != rcvd ) {
993
1074
if (ret < 0 )
994
1075
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 ++ ;
996
1078
ret = poll (fds , num_socks , opt_timeout );
1079
+ }
997
1080
ret = xsk_ring_prod__reserve (& xsk -> umem -> fq , rcvd , & idx_fq );
998
1081
}
999
1082
@@ -1026,6 +1109,8 @@ static void rx_drop_all(void)
1026
1109
1027
1110
for (;;) {
1028
1111
if (opt_poll ) {
1112
+ for (i = 0 ; i < num_socks ; i ++ )
1113
+ xsks [i ]-> app_stats .opt_polls ++ ;
1029
1114
ret = poll (fds , num_socks , opt_timeout );
1030
1115
if (ret <= 0 )
1031
1116
continue ;
@@ -1106,6 +1191,8 @@ static void tx_only_all(void)
1106
1191
int batch_size = get_batch_size (pkt_cnt );
1107
1192
1108
1193
if (opt_poll ) {
1194
+ for (i = 0 ; i < num_socks ; i ++ )
1195
+ xsks [i ]-> app_stats .opt_polls ++ ;
1109
1196
ret = poll (fds , num_socks , opt_timeout );
1110
1197
if (ret <= 0 )
1111
1198
continue ;
@@ -1137,8 +1224,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds)
1137
1224
1138
1225
rcvd = xsk_ring_cons__peek (& xsk -> rx , opt_batch_size , & idx_rx );
1139
1226
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 ++ ;
1141
1229
ret = poll (fds , num_socks , opt_timeout );
1230
+ }
1142
1231
return ;
1143
1232
}
1144
1233
@@ -1147,8 +1236,10 @@ static void l2fwd(struct xsk_socket_info *xsk, struct pollfd *fds)
1147
1236
if (ret < 0 )
1148
1237
exit_with_error (- ret );
1149
1238
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 ++ ;
1151
1241
kick_tx (xsk );
1242
+ }
1152
1243
ret = xsk_ring_prod__reserve (& xsk -> tx , rcvd , & idx_tx );
1153
1244
}
1154
1245
@@ -1186,6 +1277,8 @@ static void l2fwd_all(void)
1186
1277
1187
1278
for (;;) {
1188
1279
if (opt_poll ) {
1280
+ for (i = 0 ; i < num_socks ; i ++ )
1281
+ xsks [i ]-> app_stats .opt_polls ++ ;
1189
1282
ret = poll (fds , num_socks , opt_timeout );
1190
1283
if (ret <= 0 )
1191
1284
continue ;
0 commit comments