app/crypto-perf: fix invalid latency for QAT
[dpdk.git] / app / test-crypto-perf / cperf_test_latency.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016-2017 Intel Corporation. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of Intel Corporation nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <rte_malloc.h>
34 #include <rte_cycles.h>
35 #include <rte_crypto.h>
36 #include <rte_cryptodev.h>
37
38 #include "cperf_test_latency.h"
39 #include "cperf_ops.h"
40
41
42 struct cperf_latency_results {
43
44         uint64_t ops_failed;
45
46         uint64_t enqd_tot;
47         uint64_t enqd_max;
48         uint64_t enqd_min;
49
50         uint64_t deqd_tot;
51         uint64_t deqd_max;
52         uint64_t deqd_min;
53
54         uint64_t cycles_tot;
55         uint64_t cycles_max;
56         uint64_t cycles_min;
57
58         uint64_t burst_num;
59         uint64_t num;
60 };
61
62 struct cperf_op_result {
63         uint64_t tsc_start;
64         uint64_t tsc_end;
65         enum rte_crypto_op_status status;
66 };
67
68 struct cperf_latency_ctx {
69         uint8_t dev_id;
70         uint16_t qp_id;
71         uint8_t lcore_id;
72
73         struct rte_mempool *pkt_mbuf_pool_in;
74         struct rte_mempool *pkt_mbuf_pool_out;
75         struct rte_mbuf **mbufs_in;
76         struct rte_mbuf **mbufs_out;
77
78         struct rte_mempool *crypto_op_pool;
79
80         struct rte_cryptodev_sym_session *sess;
81
82         cperf_populate_ops_t populate_ops;
83         cperf_verify_crypto_op_t verify_op_output;
84
85         const struct cperf_options *options;
86         const struct cperf_test_vector *test_vector;
87         struct cperf_op_result *res;
88         struct cperf_latency_results results;
89 };
90
91 #define max(a, b) (a > b ? (uint64_t)a : (uint64_t)b)
92 #define min(a, b) (a < b ? (uint64_t)a : (uint64_t)b)
93
94 static void
95 cperf_latency_test_free(struct cperf_latency_ctx *ctx, uint32_t mbuf_nb)
96 {
97         uint32_t i;
98
99         if (ctx) {
100                 if (ctx->sess)
101                         rte_cryptodev_sym_session_free(ctx->dev_id, ctx->sess);
102
103                 if (ctx->mbufs_in) {
104                         for (i = 0; i < mbuf_nb; i++)
105                                 rte_pktmbuf_free(ctx->mbufs_in[i]);
106
107                         rte_free(ctx->mbufs_in);
108                 }
109
110                 if (ctx->mbufs_out) {
111                         for (i = 0; i < mbuf_nb; i++) {
112                                 if (ctx->mbufs_out[i] != NULL)
113                                         rte_pktmbuf_free(ctx->mbufs_out[i]);
114                         }
115
116                         rte_free(ctx->mbufs_out);
117                 }
118
119                 if (ctx->pkt_mbuf_pool_in)
120                         rte_mempool_free(ctx->pkt_mbuf_pool_in);
121
122                 if (ctx->pkt_mbuf_pool_out)
123                         rte_mempool_free(ctx->pkt_mbuf_pool_out);
124
125                 if (ctx->crypto_op_pool)
126                         rte_mempool_free(ctx->crypto_op_pool);
127
128                 rte_free(ctx->res);
129                 rte_free(ctx);
130         }
131 }
132
133 static struct rte_mbuf *
134 cperf_mbuf_create(struct rte_mempool *mempool,
135                 uint32_t segments_nb,
136                 const struct cperf_options *options,
137                 const struct cperf_test_vector *test_vector)
138 {
139         struct rte_mbuf *mbuf;
140         uint32_t segment_sz = options->buffer_sz / segments_nb;
141         uint32_t last_sz = options->buffer_sz % segments_nb;
142         uint8_t *mbuf_data;
143         uint8_t *test_data =
144                         (options->cipher_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT) ?
145                                         test_vector->plaintext.data :
146                                         test_vector->ciphertext.data;
147
148         mbuf = rte_pktmbuf_alloc(mempool);
149         if (mbuf == NULL)
150                 goto error;
151
152         mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
153         if (mbuf_data == NULL)
154                 goto error;
155
156         memcpy(mbuf_data, test_data, segment_sz);
157         test_data += segment_sz;
158         segments_nb--;
159
160         while (segments_nb) {
161                 struct rte_mbuf *m;
162
163                 m = rte_pktmbuf_alloc(mempool);
164                 if (m == NULL)
165                         goto error;
166
167                 rte_pktmbuf_chain(mbuf, m);
168
169                 mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, segment_sz);
170                 if (mbuf_data == NULL)
171                         goto error;
172
173                 memcpy(mbuf_data, test_data, segment_sz);
174                 test_data += segment_sz;
175                 segments_nb--;
176         }
177
178         if (last_sz) {
179                 mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf, last_sz);
180                 if (mbuf_data == NULL)
181                         goto error;
182
183                 memcpy(mbuf_data, test_data, last_sz);
184         }
185
186         mbuf_data = (uint8_t *)rte_pktmbuf_append(mbuf,
187                         options->auth_digest_sz);
188         if (mbuf_data == NULL)
189                 goto error;
190
191         if (options->op_type == CPERF_AEAD) {
192                 uint8_t *aead = (uint8_t *)rte_pktmbuf_prepend(mbuf,
193                         RTE_ALIGN_CEIL(options->auth_aad_sz, 16));
194
195                 if (aead == NULL)
196                         goto error;
197
198                 memcpy(aead, test_vector->aad.data, test_vector->aad.length);
199         }
200
201         return mbuf;
202 error:
203         if (mbuf != NULL)
204                 rte_pktmbuf_free(mbuf);
205
206         return NULL;
207 }
208
209 void *
210 cperf_latency_test_constructor(uint8_t dev_id, uint16_t qp_id,
211                 const struct cperf_options *options,
212                 const struct cperf_test_vector *test_vector,
213                 const struct cperf_op_fns *op_fns)
214 {
215         struct cperf_latency_ctx *ctx = NULL;
216         unsigned int mbuf_idx = 0;
217         char pool_name[32] = "";
218
219         ctx = rte_malloc(NULL, sizeof(struct cperf_latency_ctx), 0);
220         if (ctx == NULL)
221                 goto err;
222
223         ctx->dev_id = dev_id;
224         ctx->qp_id = qp_id;
225
226         ctx->populate_ops = op_fns->populate_ops;
227         ctx->options = options;
228         ctx->test_vector = test_vector;
229
230         ctx->sess = op_fns->sess_create(dev_id, options, test_vector);
231         if (ctx->sess == NULL)
232                 goto err;
233
234         snprintf(pool_name, sizeof(pool_name), "cperf_pool_in_cdev_%d",
235                                 dev_id);
236
237         ctx->pkt_mbuf_pool_in = rte_pktmbuf_pool_create(pool_name,
238                         options->pool_sz * options->segments_nb, 0, 0,
239                         RTE_PKTMBUF_HEADROOM +
240                         RTE_CACHE_LINE_ROUNDUP(
241                                 (options->buffer_sz / options->segments_nb) +
242                                 (options->buffer_sz % options->segments_nb) +
243                                         options->auth_digest_sz),
244                         rte_socket_id());
245
246         if (ctx->pkt_mbuf_pool_in == NULL)
247                 goto err;
248
249         /* Generate mbufs_in with plaintext populated for test */
250         if (ctx->options->pool_sz % ctx->options->burst_sz)
251                 goto err;
252
253         ctx->mbufs_in = rte_malloc(NULL,
254                         (sizeof(struct rte_mbuf *) *
255                         ctx->options->pool_sz), 0);
256
257         for (mbuf_idx = 0; mbuf_idx < options->pool_sz; mbuf_idx++) {
258                 ctx->mbufs_in[mbuf_idx] = cperf_mbuf_create(
259                                 ctx->pkt_mbuf_pool_in, options->segments_nb,
260                                 options, test_vector);
261                 if (ctx->mbufs_in[mbuf_idx] == NULL)
262                         goto err;
263         }
264
265         if (options->out_of_place == 1) {
266
267                 snprintf(pool_name, sizeof(pool_name),
268                                 "cperf_pool_out_cdev_%d",
269                                 dev_id);
270
271                 ctx->pkt_mbuf_pool_out = rte_pktmbuf_pool_create(
272                                 pool_name, options->pool_sz, 0, 0,
273                                 RTE_PKTMBUF_HEADROOM +
274                                 RTE_CACHE_LINE_ROUNDUP(
275                                         options->buffer_sz +
276                                         options->auth_digest_sz),
277                                 rte_socket_id());
278
279                 if (ctx->pkt_mbuf_pool_out == NULL)
280                         goto err;
281         }
282
283         ctx->mbufs_out = rte_malloc(NULL,
284                         (sizeof(struct rte_mbuf *) *
285                         ctx->options->pool_sz), 0);
286
287         for (mbuf_idx = 0; mbuf_idx < options->pool_sz; mbuf_idx++) {
288                 if (options->out_of_place == 1) {
289                         ctx->mbufs_out[mbuf_idx] = cperf_mbuf_create(
290                                         ctx->pkt_mbuf_pool_out, 1,
291                                         options, test_vector);
292                         if (ctx->mbufs_out[mbuf_idx] == NULL)
293                                 goto err;
294                 } else {
295                         ctx->mbufs_out[mbuf_idx] = NULL;
296                 }
297         }
298
299         snprintf(pool_name, sizeof(pool_name), "cperf_op_pool_cdev_%d",
300                         dev_id);
301
302         ctx->crypto_op_pool = rte_crypto_op_pool_create(pool_name,
303                         RTE_CRYPTO_OP_TYPE_SYMMETRIC, options->pool_sz, 0, 0,
304                         rte_socket_id());
305         if (ctx->crypto_op_pool == NULL)
306                 goto err;
307
308         ctx->res = rte_malloc(NULL, sizeof(struct cperf_op_result) *
309                         ctx->options->total_ops, 0);
310
311         if (ctx->res == NULL)
312                 goto err;
313
314         return ctx;
315 err:
316         cperf_latency_test_free(ctx, mbuf_idx);
317
318         return NULL;
319 }
320
321 static int
322 cperf_latency_test_verifier(struct rte_mbuf *mbuf,
323                 const struct cperf_options *options,
324                 const struct cperf_test_vector *vector)
325 {
326         const struct rte_mbuf *m;
327         uint32_t len;
328         uint16_t nb_segs;
329         uint8_t *data;
330         uint32_t cipher_offset, auth_offset;
331         uint8_t cipher, auth;
332         int res = 0;
333
334         m = mbuf;
335         nb_segs = m->nb_segs;
336         len = 0;
337         while (m && nb_segs != 0) {
338                 len += m->data_len;
339                 m = m->next;
340                 nb_segs--;
341         }
342
343         data = rte_malloc(NULL, len, 0);
344         if (data == NULL)
345                 return 1;
346
347         m = mbuf;
348         nb_segs = m->nb_segs;
349         len = 0;
350         while (m && nb_segs != 0) {
351                 memcpy(data + len, rte_pktmbuf_mtod(m, uint8_t *),
352                                 m->data_len);
353                 len += m->data_len;
354                 m = m->next;
355                 nb_segs--;
356         }
357
358         switch (options->op_type) {
359         case CPERF_CIPHER_ONLY:
360                 cipher = 1;
361                 cipher_offset = 0;
362                 auth = 0;
363                 auth_offset = 0;
364                 break;
365         case CPERF_CIPHER_THEN_AUTH:
366                 cipher = 1;
367                 cipher_offset = 0;
368                 auth = 1;
369                 auth_offset = vector->plaintext.length;
370                 break;
371         case CPERF_AUTH_ONLY:
372                 cipher = 0;
373                 cipher_offset = 0;
374                 auth = 1;
375                 auth_offset = vector->plaintext.length;
376                 break;
377         case CPERF_AUTH_THEN_CIPHER:
378                 cipher = 1;
379                 cipher_offset = 0;
380                 auth = 1;
381                 auth_offset = vector->plaintext.length;
382                 break;
383         case CPERF_AEAD:
384                 cipher = 1;
385                 cipher_offset = vector->aad.length;
386                 auth = 1;
387                 auth_offset = vector->aad.length + vector->plaintext.length;
388                 break;
389         }
390
391         if (cipher == 1) {
392                 if (options->cipher_op == RTE_CRYPTO_CIPHER_OP_ENCRYPT)
393                         res += memcmp(data + cipher_offset,
394                                         vector->ciphertext.data,
395                                         vector->ciphertext.length);
396                 else
397                         res += memcmp(data + cipher_offset,
398                                         vector->plaintext.data,
399                                         vector->plaintext.length);
400         }
401
402         if (auth == 1) {
403                 if (options->auth_op == RTE_CRYPTO_AUTH_OP_GENERATE)
404                         res += memcmp(data + auth_offset,
405                                         vector->digest.data,
406                                         vector->digest.length);
407         }
408
409         if (res != 0)
410                 res = 1;
411
412         return res;
413 }
414
415 int
416 cperf_latency_test_runner(void *arg)
417 {
418         struct cperf_latency_ctx *ctx = arg;
419         struct cperf_op_result *pres;
420
421         if (ctx == NULL)
422                 return 0;
423
424         struct rte_crypto_op *ops[ctx->options->burst_sz];
425         struct rte_crypto_op *ops_processed[ctx->options->burst_sz];
426         uint64_t ops_enqd = 0, ops_deqd = 0;
427         uint64_t m_idx = 0, b_idx = 0, i;
428
429         uint64_t tsc_val, tsc_end, tsc_start;
430         uint64_t tsc_max = 0, tsc_min = ~0UL, tsc_tot = 0, tsc_idx = 0;
431         uint64_t enqd_max = 0, enqd_min = ~0UL, enqd_tot = 0;
432         uint64_t deqd_max = 0, deqd_min = ~0UL, deqd_tot = 0;
433
434         uint32_t lcore = rte_lcore_id();
435
436 #ifdef CPERF_LINEARIZATION_ENABLE
437         struct rte_cryptodev_info dev_info;
438         int linearize = 0;
439
440         /* Check if source mbufs require coalescing */
441         if (ctx->options->segments_nb > 1) {
442                 rte_cryptodev_info_get(ctx->dev_id, &dev_info);
443                 if ((dev_info.feature_flags &
444                                 RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER) == 0)
445                         linearize = 1;
446         }
447 #endif /* CPERF_LINEARIZATION_ENABLE */
448
449         ctx->lcore_id = lcore;
450
451         /* Warm up the host CPU before starting the test */
452         for (i = 0; i < ctx->options->total_ops; i++)
453                 rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0);
454
455         while (enqd_tot < ctx->options->total_ops) {
456
457                 uint16_t burst_size = ((enqd_tot + ctx->options->burst_sz)
458                                 <= ctx->options->total_ops) ?
459                                                 ctx->options->burst_sz :
460                                                 ctx->options->total_ops -
461                                                 enqd_tot;
462
463                 /* Allocate crypto ops from pool */
464                 if (burst_size != rte_crypto_op_bulk_alloc(
465                                 ctx->crypto_op_pool,
466                                 RTE_CRYPTO_OP_TYPE_SYMMETRIC,
467                                 ops, burst_size))
468                         return -1;
469
470                 /* Setup crypto op, attach mbuf etc */
471                 (ctx->populate_ops)(ops, &ctx->mbufs_in[m_idx],
472                                 &ctx->mbufs_out[m_idx],
473                                 burst_size, ctx->sess, ctx->options,
474                                 ctx->test_vector);
475
476                 tsc_start = rte_rdtsc_precise();
477
478 #ifdef CPERF_LINEARIZATION_ENABLE
479                 if (linearize) {
480                         /* PMD doesn't support scatter-gather and source buffer
481                          * is segmented.
482                          * We need to linearize it before enqueuing.
483                          */
484                         for (i = 0; i < burst_size; i++)
485                                 rte_pktmbuf_linearize(ops[i]->sym->m_src);
486                 }
487 #endif /* CPERF_LINEARIZATION_ENABLE */
488
489                 /* Enqueue burst of ops on crypto device */
490                 ops_enqd = rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id,
491                                 ops, burst_size);
492
493                 /* Dequeue processed burst of ops from crypto device */
494                 ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
495                                 ops_processed, ctx->options->burst_sz);
496
497                 tsc_end = rte_rdtsc_precise();
498
499                 for (i = 0; i < ops_enqd; i++) {
500                         ctx->res[tsc_idx].tsc_start = tsc_start;
501                         ops[i]->opaque_data = (void *)&ctx->res[tsc_idx];
502                         tsc_idx++;
503                 }
504
505                 /* Free memory for not enqueued operations */
506                 for (i = ops_enqd; i < burst_size; i++)
507                         rte_crypto_op_free(ops[i]);
508
509                 if (likely(ops_deqd))  {
510                         /*
511                          * free crypto ops so they can be reused. We don't free
512                          * the mbufs here as we don't want to reuse them as
513                          * the crypto operation will change the data and cause
514                          * failures.
515                          */
516                         for (i = 0; i < ops_deqd; i++) {
517                                 pres = (struct cperf_op_result *)
518                                                 (ops_processed[i]->opaque_data);
519                                 pres->status = ops_processed[i]->status;
520                                 pres->tsc_end = tsc_end;
521
522                                 rte_crypto_op_free(ops_processed[i]);
523                         }
524
525                         deqd_tot += ops_deqd;
526                         deqd_max = max(ops_deqd, deqd_max);
527                         deqd_min = min(ops_deqd, deqd_min);
528                 }
529
530                 enqd_tot += ops_enqd;
531                 enqd_max = max(ops_enqd, enqd_max);
532                 enqd_min = min(ops_enqd, enqd_min);
533
534                 m_idx += ops_enqd;
535                 m_idx = m_idx + ctx->options->burst_sz > ctx->options->pool_sz ?
536                                 0 : m_idx;
537                 b_idx++;
538         }
539
540         /* Dequeue any operations still in the crypto device */
541         while (deqd_tot < ctx->options->total_ops) {
542                 /* Sending 0 length burst to flush sw crypto device */
543                 rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0);
544
545                 /* dequeue burst */
546                 ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id,
547                                 ops_processed, ctx->options->burst_sz);
548
549                 tsc_end = rte_rdtsc_precise();
550
551                 if (ops_deqd != 0) {
552                         for (i = 0; i < ops_deqd; i++) {
553                                 pres = (struct cperf_op_result *)
554                                                 (ops_processed[i]->opaque_data);
555                                 pres->status = ops_processed[i]->status;
556                                 pres->tsc_end = tsc_end;
557
558                                 rte_crypto_op_free(ops_processed[i]);
559                         }
560
561                         deqd_tot += ops_deqd;
562                         deqd_max = max(ops_deqd, deqd_max);
563                         deqd_min = min(ops_deqd, deqd_min);
564                 }
565         }
566
567         for (i = 0; i < tsc_idx; i++) {
568                 tsc_val = ctx->res[i].tsc_end - ctx->res[i].tsc_start;
569                 tsc_max = max(tsc_val, tsc_max);
570                 tsc_min = min(tsc_val, tsc_min);
571                 tsc_tot += tsc_val;
572         }
573
574         if (ctx->options->verify) {
575                 struct rte_mbuf **mbufs;
576
577                 if (ctx->options->out_of_place == 1)
578                         mbufs = ctx->mbufs_out;
579                 else
580                         mbufs = ctx->mbufs_in;
581
582                 for (i = 0; i < ctx->options->total_ops; i++) {
583
584                         if (ctx->res[i].status != RTE_CRYPTO_OP_STATUS_SUCCESS
585                                         || cperf_latency_test_verifier(mbufs[i],
586                                                         ctx->options,
587                                                         ctx->test_vector)) {
588
589                                 ctx->results.ops_failed++;
590                         }
591                 }
592         }
593
594         ctx->results.enqd_tot = enqd_tot;
595         ctx->results.enqd_max = enqd_max;
596         ctx->results.enqd_min = enqd_min;
597
598         ctx->results.deqd_tot = deqd_tot;
599         ctx->results.deqd_max = deqd_max;
600         ctx->results.deqd_min = deqd_min;
601
602         ctx->results.cycles_tot = tsc_tot;
603         ctx->results.cycles_max = tsc_max;
604         ctx->results.cycles_min = tsc_min;
605
606         ctx->results.burst_num = b_idx;
607         ctx->results.num = tsc_idx;
608
609         return 0;
610 }
611
612 void
613 cperf_latency_test_destructor(void *arg)
614 {
615         struct cperf_latency_ctx *ctx = arg;
616         uint64_t i;
617         if (ctx == NULL)
618                 return;
619         static int only_once;
620         uint64_t etot, eavg, emax, emin;
621         uint64_t dtot, davg, dmax, dmin;
622         uint64_t ctot, cavg, cmax, cmin;
623         double ttot, tavg, tmax, tmin;
624
625         const uint64_t tunit = 1000000; /* us */
626         const uint64_t tsc_hz = rte_get_tsc_hz();
627
628         etot = ctx->results.enqd_tot;
629         eavg = ctx->results.enqd_tot / ctx->results.burst_num;
630         emax = ctx->results.enqd_max;
631         emin = ctx->results.enqd_min;
632
633         dtot = ctx->results.deqd_tot;
634         davg = ctx->results.deqd_tot / ctx->results.burst_num;
635         dmax = ctx->results.deqd_max;
636         dmin = ctx->results.deqd_min;
637
638         ctot = ctx->results.cycles_tot;
639         cavg = ctx->results.cycles_tot / ctx->results.num;
640         cmax = ctx->results.cycles_max;
641         cmin = ctx->results.cycles_min;
642
643         ttot = tunit*(double)(ctot) / tsc_hz;
644         tavg = tunit*(double)(cavg) / tsc_hz;
645         tmax = tunit*(double)(cmax) / tsc_hz;
646         tmin = tunit*(double)(cmin) / tsc_hz;
647
648         if (ctx->options->csv) {
649                 if (!only_once)
650                         printf("\n# lcore, Pakt Seq #, Packet Size, cycles,"
651                                         " time (us)");
652
653                 for (i = 0; i < ctx->options->total_ops; i++) {
654
655                         printf("\n%u;%"PRIu64";%"PRIu64";%.3f",
656                                 ctx->lcore_id, i + 1,
657                                 ctx->res[i].tsc_end - ctx->res[i].tsc_start,
658                                 tunit * (double) (ctx->res[i].tsc_end
659                                                 - ctx->res[i].tsc_start)
660                                         / tsc_hz);
661
662                 }
663                 only_once = 1;
664         } else {
665                 printf("\n# Device %d on lcore %u\n", ctx->dev_id,
666                         ctx->lcore_id);
667                 printf("\n# total operations: %u", ctx->options->total_ops);
668                 printf("\n#  verified failed: %"PRIu64,
669                                 ctx->results.ops_failed);
670                 printf("\n#     burst number: %"PRIu64,
671                                 ctx->results.burst_num);
672                 printf("\n#");
673                 printf("\n#          \t       Total\t   Average\t   Maximum\t "
674                                 "  Minimum");
675                 printf("\n#  enqueued\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t"
676                                 "%10"PRIu64, etot, eavg, emax, emin);
677                 printf("\n#  dequeued\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t"
678                                 "%10"PRIu64, dtot, davg, dmax, dmin);
679                 printf("\n#    cycles\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t"
680                                 "%10"PRIu64, ctot, cavg, cmax, cmin);
681                 printf("\n# time [us]\t%12.0f\t%10.3f\t%10.3f\t%10.3f", ttot,
682                         tavg, tmax, tmin);
683                 printf("\n\n");
684
685         }
686         cperf_latency_test_free(ctx, ctx->options->pool_sz);
687
688 }