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 uint16_t ops_unused = 0; 428 uint64_t m_idx = 0, b_idx = 0, i; 429 430 uint64_t tsc_val, tsc_end, tsc_start; 431 uint64_t tsc_max = 0, tsc_min = ~0UL, tsc_tot = 0, tsc_idx = 0; 432 uint64_t enqd_max = 0, enqd_min = ~0UL, enqd_tot = 0; 433 uint64_t deqd_max = 0, deqd_min = ~0UL, deqd_tot = 0; 434 435 uint32_t lcore = rte_lcore_id(); 436 437 #ifdef CPERF_LINEARIZATION_ENABLE 438 struct rte_cryptodev_info dev_info; 439 int linearize = 0; 440 441 /* Check if source mbufs require coalescing */ 442 if (ctx->options->segments_nb > 1) { 443 rte_cryptodev_info_get(ctx->dev_id, &dev_info); 444 if ((dev_info.feature_flags & 445 RTE_CRYPTODEV_FF_MBUF_SCATTER_GATHER) == 0) 446 linearize = 1; 447 } 448 #endif /* CPERF_LINEARIZATION_ENABLE */ 449 450 ctx->lcore_id = lcore; 451 452 /* Warm up the host CPU before starting the test */ 453 for (i = 0; i < ctx->options->total_ops; i++) 454 rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0); 455 456 while (enqd_tot < ctx->options->total_ops) { 457 458 uint16_t burst_size = ((enqd_tot + ctx->options->burst_sz) 459 <= ctx->options->total_ops) ? 460 ctx->options->burst_sz : 461 ctx->options->total_ops - 462 enqd_tot; 463 uint16_t ops_needed = burst_size - ops_unused; 464 465 /* Allocate crypto ops from pool */ 466 if (ops_needed != rte_crypto_op_bulk_alloc( 467 ctx->crypto_op_pool, 468 RTE_CRYPTO_OP_TYPE_SYMMETRIC, 469 ops, ops_needed)) 470 return -1; 471 472 /* Setup crypto op, attach mbuf etc */ 473 (ctx->populate_ops)(ops, &ctx->mbufs_in[m_idx], 474 &ctx->mbufs_out[m_idx], 475 ops_needed, ctx->sess, ctx->options, 476 ctx->test_vector); 477 478 tsc_start = rte_rdtsc_precise(); 479 480 #ifdef CPERF_LINEARIZATION_ENABLE 481 if (linearize) { 482 /* PMD doesn't support scatter-gather and source buffer 483 * is segmented. 484 * We need to linearize it before enqueuing. 485 */ 486 for (i = 0; i < burst_size; i++) 487 rte_pktmbuf_linearize(ops[i]->sym->m_src); 488 } 489 #endif /* CPERF_LINEARIZATION_ENABLE */ 490 491 /* Enqueue burst of ops on crypto device */ 492 ops_enqd = rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, 493 ops, burst_size); 494 495 /* Dequeue processed burst of ops from crypto device */ 496 ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id, 497 ops_processed, ctx->options->burst_sz); 498 499 tsc_end = rte_rdtsc_precise(); 500 501 for (i = 0; i < ops_needed; i++) { 502 ctx->res[tsc_idx].tsc_start = tsc_start; 503 ops[i]->opaque_data = (void *)&ctx->res[tsc_idx]; 504 tsc_idx++; 505 } 506 507 /* 508 * Calculate number of ops not enqueued (mainly for hw 509 * accelerators whose ingress queue can fill up). 510 */ 511 ops_unused = burst_size - ops_enqd; 512 513 if (likely(ops_deqd)) { 514 /* 515 * free crypto ops so they can be reused. We don't free 516 * the mbufs here as we don't want to reuse them as 517 * the crypto operation will change the data and cause 518 * failures. 519 */ 520 for (i = 0; i < ops_deqd; i++) { 521 pres = (struct cperf_op_result *) 522 (ops_processed[i]->opaque_data); 523 pres->status = ops_processed[i]->status; 524 pres->tsc_end = tsc_end; 525 526 rte_crypto_op_free(ops_processed[i]); 527 } 528 529 deqd_tot += ops_deqd; 530 deqd_max = max(ops_deqd, deqd_max); 531 deqd_min = min(ops_deqd, deqd_min); 532 } 533 534 enqd_tot += ops_enqd; 535 enqd_max = max(ops_enqd, enqd_max); 536 enqd_min = min(ops_enqd, enqd_min); 537 538 m_idx += ops_needed; 539 m_idx = m_idx + ctx->options->burst_sz > ctx->options->pool_sz ? 540 0 : m_idx; 541 b_idx++; 542 } 543 544 /* Dequeue any operations still in the crypto device */ 545 while (deqd_tot < ctx->options->total_ops) { 546 /* Sending 0 length burst to flush sw crypto device */ 547 rte_cryptodev_enqueue_burst(ctx->dev_id, ctx->qp_id, NULL, 0); 548 549 /* dequeue burst */ 550 ops_deqd = rte_cryptodev_dequeue_burst(ctx->dev_id, ctx->qp_id, 551 ops_processed, ctx->options->burst_sz); 552 553 tsc_end = rte_rdtsc_precise(); 554 555 if (ops_deqd != 0) { 556 for (i = 0; i < ops_deqd; i++) { 557 pres = (struct cperf_op_result *) 558 (ops_processed[i]->opaque_data); 559 pres->status = ops_processed[i]->status; 560 pres->tsc_end = tsc_end; 561 562 rte_crypto_op_free(ops_processed[i]); 563 } 564 565 deqd_tot += ops_deqd; 566 deqd_max = max(ops_deqd, deqd_max); 567 deqd_min = min(ops_deqd, deqd_min); 568 } 569 } 570 571 for (i = 0; i < tsc_idx; i++) { 572 tsc_val = ctx->res[i].tsc_end - ctx->res[i].tsc_start; 573 tsc_max = max(tsc_val, tsc_max); 574 tsc_min = min(tsc_val, tsc_min); 575 tsc_tot += tsc_val; 576 } 577 578 if (ctx->options->verify) { 579 struct rte_mbuf **mbufs; 580 581 if (ctx->options->out_of_place == 1) 582 mbufs = ctx->mbufs_out; 583 else 584 mbufs = ctx->mbufs_in; 585 586 for (i = 0; i < ctx->options->total_ops; i++) { 587 588 if (ctx->res[i].status != RTE_CRYPTO_OP_STATUS_SUCCESS 589 || cperf_latency_test_verifier(mbufs[i], 590 ctx->options, 591 ctx->test_vector)) { 592 593 ctx->results.ops_failed++; 594 } 595 } 596 } 597 598 ctx->results.enqd_tot = enqd_tot; 599 ctx->results.enqd_max = enqd_max; 600 ctx->results.enqd_min = enqd_min; 601 602 ctx->results.deqd_tot = deqd_tot; 603 ctx->results.deqd_max = deqd_max; 604 ctx->results.deqd_min = deqd_min; 605 606 ctx->results.cycles_tot = tsc_tot; 607 ctx->results.cycles_max = tsc_max; 608 ctx->results.cycles_min = tsc_min; 609 610 ctx->results.burst_num = b_idx; 611 ctx->results.num = tsc_idx; 612 613 return 0; 614 } 615 616 void 617 cperf_latency_test_destructor(void *arg) 618 { 619 struct cperf_latency_ctx *ctx = arg; 620 uint64_t i; 621 if (ctx == NULL) 622 return; 623 static int only_once; 624 uint64_t etot, eavg, emax, emin; 625 uint64_t dtot, davg, dmax, dmin; 626 uint64_t ctot, cavg, cmax, cmin; 627 double ttot, tavg, tmax, tmin; 628 629 const uint64_t tunit = 1000000; /* us */ 630 const uint64_t tsc_hz = rte_get_tsc_hz(); 631 632 etot = ctx->results.enqd_tot; 633 eavg = ctx->results.enqd_tot / ctx->results.burst_num; 634 emax = ctx->results.enqd_max; 635 emin = ctx->results.enqd_min; 636 637 dtot = ctx->results.deqd_tot; 638 davg = ctx->results.deqd_tot / ctx->results.burst_num; 639 dmax = ctx->results.deqd_max; 640 dmin = ctx->results.deqd_min; 641 642 ctot = ctx->results.cycles_tot; 643 cavg = ctx->results.cycles_tot / ctx->results.num; 644 cmax = ctx->results.cycles_max; 645 cmin = ctx->results.cycles_min; 646 647 ttot = tunit*(double)(ctot) / tsc_hz; 648 tavg = tunit*(double)(cavg) / tsc_hz; 649 tmax = tunit*(double)(cmax) / tsc_hz; 650 tmin = tunit*(double)(cmin) / tsc_hz; 651 652 if (ctx->options->csv) { 653 if (!only_once) 654 printf("\n# lcore, Pakt Seq #, Packet Size, cycles," 655 " time (us)"); 656 657 for (i = 0; i < ctx->options->total_ops; i++) { 658 659 printf("\n%u;%"PRIu64";%"PRIu64";%.3f", 660 ctx->lcore_id, i + 1, 661 ctx->res[i].tsc_end - ctx->res[i].tsc_start, 662 tunit * (double) (ctx->res[i].tsc_end 663 - ctx->res[i].tsc_start) 664 / tsc_hz); 665 666 } 667 only_once = 1; 668 } else { 669 printf("\n# Device %d on lcore %u\n", ctx->dev_id, 670 ctx->lcore_id); 671 printf("\n# total operations: %u", ctx->options->total_ops); 672 printf("\n# verified failed: %"PRIu64, 673 ctx->results.ops_failed); 674 printf("\n# burst number: %"PRIu64, 675 ctx->results.burst_num); 676 printf("\n#"); 677 printf("\n# \t Total\t Average\t Maximum\t " 678 " Minimum"); 679 printf("\n# enqueued\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t" 680 "%10"PRIu64, etot, eavg, emax, emin); 681 printf("\n# dequeued\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t" 682 "%10"PRIu64, dtot, davg, dmax, dmin); 683 printf("\n# cycles\t%12"PRIu64"\t%10"PRIu64"\t%10"PRIu64"\t" 684 "%10"PRIu64, ctot, cavg, cmax, cmin); 685 printf("\n# time [us]\t%12.0f\t%10.3f\t%10.3f\t%10.3f", ttot, 686 tavg, tmax, tmin); 687 printf("\n\n"); 688 689 } 690 cperf_latency_test_free(ctx, ctx->options->pool_sz); 691 692 } 693