4
4
5
5
#include <stdint.h>
6
6
#include <inttypes.h>
7
+ #include <getopt.h>
7
8
#include <rte_eal.h>
8
9
#include <rte_ethdev.h>
9
10
#include <rte_cycles.h>
17
18
#define MBUF_CACHE_SIZE 250
18
19
#define BURST_SIZE 32
19
20
21
+ static const char usage [] =
22
+ "%s EAL_ARGS -- [-t]\n" ;
23
+
20
24
static const struct rte_eth_conf port_conf_default = {
21
25
.rxmode = {
22
26
.max_rx_pkt_len = RTE_ETHER_MAX_LEN ,
@@ -25,9 +29,14 @@ static const struct rte_eth_conf port_conf_default = {
25
29
26
30
static struct {
27
31
uint64_t total_cycles ;
32
+ uint64_t total_queue_cycles ;
28
33
uint64_t total_pkts ;
29
34
} latency_numbers ;
30
35
36
+ int hw_timestamping ;
37
+
38
+ #define TICKS_PER_CYCLE_SHIFT 16
39
+ static uint64_t ticks_per_cycle_mult ;
31
40
32
41
static uint16_t
33
42
add_timestamps (uint16_t port __rte_unused , uint16_t qidx __rte_unused ,
@@ -43,22 +52,42 @@ add_timestamps(uint16_t port __rte_unused, uint16_t qidx __rte_unused,
43
52
}
44
53
45
54
static uint16_t
46
- calc_latency (uint16_t port __rte_unused , uint16_t qidx __rte_unused ,
55
+ calc_latency (uint16_t port , uint16_t qidx __rte_unused ,
47
56
struct rte_mbuf * * pkts , uint16_t nb_pkts , void * _ __rte_unused )
48
57
{
49
58
uint64_t cycles = 0 ;
59
+ uint64_t queue_ticks = 0 ;
50
60
uint64_t now = rte_rdtsc ();
61
+ uint64_t ticks ;
51
62
unsigned i ;
52
63
53
- for (i = 0 ; i < nb_pkts ; i ++ )
64
+ if (hw_timestamping )
65
+ rte_eth_read_clock (port , & ticks );
66
+
67
+ for (i = 0 ; i < nb_pkts ; i ++ ) {
54
68
cycles += now - pkts [i ]-> udata64 ;
69
+ if (hw_timestamping )
70
+ queue_ticks += ticks - pkts [i ]-> timestamp ;
71
+ }
72
+
55
73
latency_numbers .total_cycles += cycles ;
74
+ if (hw_timestamping )
75
+ latency_numbers .total_queue_cycles += (queue_ticks
76
+ * ticks_per_cycle_mult ) >> TICKS_PER_CYCLE_SHIFT ;
77
+
56
78
latency_numbers .total_pkts += nb_pkts ;
57
79
58
80
if (latency_numbers .total_pkts > (100 * 1000 * 1000ULL )) {
59
81
printf ("Latency = %" PRIu64 " cycles\n" ,
60
82
latency_numbers .total_cycles / latency_numbers .total_pkts );
61
- latency_numbers .total_cycles = latency_numbers .total_pkts = 0 ;
83
+ if (hw_timestamping ) {
84
+ printf ("Latency from HW = %" PRIu64 " cycles\n" ,
85
+ latency_numbers .total_queue_cycles
86
+ / latency_numbers .total_pkts );
87
+ }
88
+ latency_numbers .total_cycles = 0 ;
89
+ latency_numbers .total_queue_cycles = 0 ;
90
+ latency_numbers .total_pkts = 0 ;
62
91
}
63
92
return nb_pkts ;
64
93
}
@@ -77,6 +106,7 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
77
106
int retval ;
78
107
uint16_t q ;
79
108
struct rte_eth_dev_info dev_info ;
109
+ struct rte_eth_rxconf rxconf ;
80
110
struct rte_eth_txconf txconf ;
81
111
82
112
if (!rte_eth_dev_is_valid_port (port ))
@@ -95,9 +125,20 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
95
125
if (retval != 0 )
96
126
return retval ;
97
127
128
+ rxconf = dev_info .default_rxconf ;
129
+
130
+ if (hw_timestamping ) {
131
+ if (!(dev_info .rx_offload_capa & DEV_RX_OFFLOAD_TIMESTAMP )) {
132
+ printf ("\nERROR: Port %u does not support hardware timestamping\n"
133
+ , port );
134
+ return -1 ;
135
+ }
136
+ rxconf .offloads |= DEV_RX_OFFLOAD_TIMESTAMP ;
137
+ }
138
+
98
139
for (q = 0 ; q < rx_rings ; q ++ ) {
99
140
retval = rte_eth_rx_queue_setup (port , q , nb_rxd ,
100
- rte_eth_dev_socket_id (port ), NULL , mbuf_pool );
141
+ rte_eth_dev_socket_id (port ), & rxconf , mbuf_pool );
101
142
if (retval < 0 )
102
143
return retval ;
103
144
}
@@ -115,6 +156,29 @@ port_init(uint16_t port, struct rte_mempool *mbuf_pool)
115
156
if (retval < 0 )
116
157
return retval ;
117
158
159
+ if (hw_timestamping && ticks_per_cycle_mult == 0 ) {
160
+ uint64_t cycles_base = rte_rdtsc ();
161
+ uint64_t ticks_base ;
162
+ retval = rte_eth_read_clock (port , & ticks_base );
163
+ if (retval != 0 )
164
+ return retval ;
165
+ rte_delay_ms (100 );
166
+ uint64_t cycles = rte_rdtsc ();
167
+ uint64_t ticks ;
168
+ rte_eth_read_clock (port , & ticks );
169
+ uint64_t c_freq = cycles - cycles_base ;
170
+ uint64_t t_freq = ticks - ticks_base ;
171
+ double freq_mult = (double )c_freq / t_freq ;
172
+ printf ("TSC Freq ~= %" PRIu64
173
+ "\nHW Freq ~= %" PRIu64
174
+ "\nRatio : %f\n" ,
175
+ c_freq * 10 , t_freq * 10 , freq_mult );
176
+ /* TSC will be faster than internal ticks so freq_mult is > 0
177
+ * We convert the multiplication to an integer shift & mult
178
+ */
179
+ ticks_per_cycle_mult = (1 << TICKS_PER_CYCLE_SHIFT ) / freq_mult ;
180
+ }
181
+
118
182
struct rte_ether_addr addr ;
119
183
120
184
rte_eth_macaddr_get (port , & addr );
@@ -177,6 +241,11 @@ main(int argc, char *argv[])
177
241
struct rte_mempool * mbuf_pool ;
178
242
uint16_t nb_ports ;
179
243
uint16_t portid ;
244
+ struct option lgopts [] = {
245
+ { NULL , 0 , 0 , 0 }
246
+ };
247
+ int opt , option_index ;
248
+
180
249
181
250
/* init EAL */
182
251
int ret = rte_eal_init (argc , argv );
@@ -186,6 +255,18 @@ main(int argc, char *argv[])
186
255
argc -= ret ;
187
256
argv += ret ;
188
257
258
+ while ((opt = getopt_long (argc , argv , "t" , lgopts , & option_index ))
259
+ != EOF )
260
+ switch (opt ) {
261
+ case 't' :
262
+ hw_timestamping = 1 ;
263
+ break ;
264
+ default :
265
+ printf (usage , argv [0 ]);
266
+ return -1 ;
267
+ }
268
+ optind = 1 ; /* reset getopt lib */
269
+
189
270
nb_ports = rte_eth_dev_count_avail ();
190
271
if (nb_ports < 2 || (nb_ports & 1 ))
191
272
rte_exit (EXIT_FAILURE , "Error: number of ports must be even\n" );
0 commit comments