1 /*- 2 * Copyright (c) 2004 Sam Leffler, Errno Consulting 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer, 10 * without modification. 11 * 2. Redistributions in binary form must reproduce at minimum a disclaimer 12 * similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any 13 * redistribution must be conditioned upon including a substantially 14 * similar Disclaimer requirement for further binary redistribution. 15 * 3. Neither the names of the above-listed copyright holders nor the names 16 * of any contributors may be used to endorse or promote products derived 17 * from this software without specific prior written permission. 18 * 19 * NO WARRANTY 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 NONINFRINGEMENT, MERCHANTIBILITY 23 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL 24 * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, 25 * OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 26 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 27 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER 28 * IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 29 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF 30 * THE POSSIBILITY OF SUCH DAMAGES. 31 * 32 * $FreeBSD$ 33 */ 34 35 /* 36 * Simple tool for testing hardware/system crypto support. 37 * 38 * cryptotest [-czsbv] [-a algorithm] [count] [size ...] 39 * 40 * Run count iterations of a crypt+decrypt or mac operation on a buffer of 41 * size bytes. A random key and iv are used. Options: 42 * -c check the results 43 * -d dev pin work on device dev 44 * -z run all available algorithms on a variety of buffer sizes 45 * -v be verbose 46 * -b mark operations for batching 47 * -p profile kernel crypto operations (must be root) 48 * -t n fork n threads and run tests concurrently 49 * Known algorithms are: 50 * null null cbc 51 * des des cbc 52 * 3des 3des cbc 53 * blf blowfish cbc 54 * cast cast cbc 55 * skj skipjack cbc 56 * aes rijndael/aes 128-bit cbc 57 * aes192 rijndael/aes 192-bit cbc 58 * aes256 rijndael/aes 256-bit cbc 59 * chacha20 Chacha20 stream cipher 60 * blake2b Blake2b 61 * blake2s Blake2s 62 * md5 md5 hmac 63 * sha1 sha1 hmac 64 * sha256 256-bit sha2 hmac 65 * sha384 384-bit sha2 hmac 66 * sha512 512--bit sha2 hmac 67 * 68 * For a test of how fast a crypto card is, use something like: 69 * cryptotest -z 1024 70 * This will run a series of tests using the available crypto/cipher 71 * algorithms over a variety of buffer sizes. The 1024 says to do 1024 72 * iterations. Extra arguments can be used to specify one or more buffer 73 * sizes to use in doing tests. 74 * 75 * To fork multiple processes all doing the same work, specify -t X on the 76 * command line to get X "threads" running simultaneously. No effort is made 77 * to synchronize the threads or otherwise maximize load. 78 * 79 * If the kernel crypto code is built with CRYPTO_TIMING and you run as root, 80 * then you can specify the -p option to get a "profile" of the time spent 81 * processing crypto operations. At present this data is only meaningful for 82 * symmetric operations. To get meaningful numbers you must run on an idle 83 * machine. 84 * 85 * Expect ~400 Mb/s for a Broadcom 582x for 8K buffers on a reasonable CPU 86 * (64-bit PCI helps). Hifn 7811 parts top out at ~110 Mb/s. 87 */ 88 89 #include <sys/param.h> 90 #include <sys/cpuset.h> 91 #include <sys/ioctl.h> 92 #include <sys/mman.h> 93 #include <sys/sysctl.h> 94 #include <sys/time.h> 95 #include <sys/wait.h> 96 97 #include <err.h> 98 #include <fcntl.h> 99 #include <paths.h> 100 #include <stdio.h> 101 #include <stdlib.h> 102 #include <string.h> 103 #include <sysexits.h> 104 #include <unistd.h> 105 106 #include <crypto/cryptodev.h> 107 108 #define CHUNK 64 /* how much to display */ 109 #define streq(a,b) (strcasecmp(a,b) == 0) 110 111 void hexdump(char *, int); 112 113 int verbose = 0; 114 int opflags = 0; 115 int verify = 0; 116 int crid = CRYPTO_FLAG_HARDWARE; 117 118 struct alg { 119 const char* name; 120 int ishash; 121 int blocksize; 122 int minkeylen; 123 int maxkeylen; 124 int code; 125 } algorithms[] = { 126 #ifdef CRYPTO_NULL_CBC 127 { "null", 0, 8, 1, 256, CRYPTO_NULL_CBC }, 128 #endif 129 { "des", 0, 8, 8, 8, CRYPTO_DES_CBC }, 130 { "3des", 0, 8, 24, 24, CRYPTO_3DES_CBC }, 131 { "blf", 0, 8, 5, 56, CRYPTO_BLF_CBC }, 132 { "cast", 0, 8, 5, 16, CRYPTO_CAST_CBC }, 133 { "skj", 0, 8, 10, 10, CRYPTO_SKIPJACK_CBC }, 134 { "rij", 0, 16, 16, 16, CRYPTO_RIJNDAEL128_CBC}, 135 { "aes", 0, 16, 16, 16, CRYPTO_AES_CBC}, 136 { "aes192", 0, 16, 24, 24, CRYPTO_AES_CBC}, 137 { "aes256", 0, 16, 32, 32, CRYPTO_AES_CBC}, 138 { "chacha20", 0, 1, 32, 32, CRYPTO_CHACHA20}, 139 { "blake2b", 1, 128, 64, 64, CRYPTO_BLAKE2B }, 140 { "blake2s", 1, 64, 32, 32, CRYPTO_BLAKE2S }, 141 { "md5", 1, 8, 16, 16, CRYPTO_MD5_HMAC }, 142 { "sha1", 1, 8, 20, 20, CRYPTO_SHA1_HMAC }, 143 { "sha256", 1, 8, 32, 32, CRYPTO_SHA2_256_HMAC }, 144 { "sha384", 1, 8, 48, 48, CRYPTO_SHA2_384_HMAC }, 145 { "sha512", 1, 8, 64, 64, CRYPTO_SHA2_512_HMAC }, 146 }; 147 148 void 149 usage(const char* cmd) 150 { 151 printf("usage: %s [-czsbv] [-d dev] [-a algorithm] [count] [size ...]\n", 152 cmd); 153 printf("where algorithm is one of:\n"); 154 printf(" null des 3des (default) blowfish cast skipjack rij\n"); 155 printf(" aes aes192 aes256 chacha20 md5 sha1 sha256 sha384 sha512\n"); 156 printf(" blake2b blake2s\n"); 157 printf(" or an encryption algorithm concatented with authentication\n"); 158 printf(" algorithm with '+' in the middle, e.g., aes+sha1.\n"); 159 printf("count is the number of encrypt/decrypt ops to do\n"); 160 printf("size is the number of bytes of text to encrypt+decrypt\n"); 161 printf("\n"); 162 printf("-c check the results (slows timing)\n"); 163 printf("-d use specific device, specify 'soft' for testing software implementations\n"); 164 printf("\tNOTE: to use software you must set:\n\t sysctl kern.cryptodevallowsoft=1\n"); 165 printf("-z run all available algorithms on a variety of sizes\n"); 166 printf("-v be verbose\n"); 167 printf("-b mark operations for batching\n"); 168 printf("-p profile kernel crypto operation (must be root)\n"); 169 printf("-t n for n threads and run tests concurrently\n"); 170 exit(-1); 171 } 172 173 struct alg* 174 getalgbycode(int cipher) 175 { 176 int i; 177 178 for (i = 0; i < nitems(algorithms); i++) 179 if (cipher == algorithms[i].code) 180 return &algorithms[i]; 181 return NULL; 182 } 183 184 struct alg* 185 getalgbyname(const char* name) 186 { 187 int i; 188 189 for (i = 0; i < nitems(algorithms); i++) 190 if (streq(name, algorithms[i].name)) 191 return &algorithms[i]; 192 return NULL; 193 } 194 195 int 196 devcrypto(void) 197 { 198 int fd = -1; 199 200 if (fd < 0) { 201 fd = open(_PATH_DEV "crypto", O_RDWR, 0); 202 if (fd < 0) 203 err(1, _PATH_DEV "crypto"); 204 if (fcntl(fd, F_SETFD, 1) == -1) 205 err(1, "fcntl(F_SETFD) (devcrypto)"); 206 } 207 return fd; 208 } 209 210 int 211 crlookup(const char *devname) 212 { 213 struct crypt_find_op find; 214 215 if (strncmp(devname, "soft", 4) == 0) 216 return CRYPTO_FLAG_SOFTWARE; 217 218 find.crid = -1; 219 strlcpy(find.name, devname, sizeof(find.name)); 220 if (ioctl(devcrypto(), CIOCFINDDEV, &find) == -1) 221 err(1, "ioctl(CIOCFINDDEV)"); 222 return find.crid; 223 } 224 225 const char * 226 crfind(int crid) 227 { 228 static struct crypt_find_op find; 229 230 bzero(&find, sizeof(find)); 231 find.crid = crid; 232 if (ioctl(devcrypto(), CRIOFINDDEV, &find) == -1) 233 err(1, "ioctl(CIOCFINDDEV): crid %d", crid); 234 return find.name; 235 } 236 237 int 238 crget(void) 239 { 240 int fd; 241 242 if (ioctl(devcrypto(), CRIOGET, &fd) == -1) 243 err(1, "ioctl(CRIOGET)"); 244 if (fcntl(fd, F_SETFD, 1) == -1) 245 err(1, "fcntl(F_SETFD) (crget)"); 246 return fd; 247 } 248 249 char 250 rdigit(void) 251 { 252 const char a[] = { 253 0x10,0x54,0x11,0x48,0x45,0x12,0x4f,0x13,0x49,0x53,0x14,0x41, 254 0x15,0x16,0x4e,0x55,0x54,0x17,0x18,0x4a,0x4f,0x42,0x19,0x01 255 }; 256 return 0x20+a[random()%nitems(a)]; 257 } 258 259 void 260 runtest(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, struct timeval *tv) 261 { 262 int i, fd = crget(); 263 struct timeval start, stop, dt; 264 char *cleartext, *ciphertext, *originaltext, *key; 265 struct session2_op sop; 266 struct crypt_op cop; 267 char iv[EALG_MAX_BLOCK_LEN]; 268 char digest[512/8]; 269 270 /* Canonicalize 'ealg' to crypt alg and 'alg' to authentication alg. */ 271 if (ealg == NULL && !alg->ishash) { 272 ealg = alg; 273 alg = NULL; 274 } 275 276 bzero(&sop, sizeof(sop)); 277 if (ealg != NULL) { 278 sop.keylen = (ealg->minkeylen + ealg->maxkeylen)/2; 279 key = (char *) malloc(sop.keylen); 280 if (key == NULL) 281 err(1, "malloc (key)"); 282 for (i = 0; i < sop.keylen; i++) 283 key[i] = rdigit(); 284 sop.key = key; 285 sop.cipher = ealg->code; 286 } 287 if (alg != NULL) { 288 sop.mackeylen = (alg->minkeylen + alg->maxkeylen)/2; 289 key = (char *) malloc(sop.mackeylen); 290 if (key == NULL) 291 err(1, "malloc (mac)"); 292 for (i = 0; i < sop.mackeylen; i++) 293 key[i] = rdigit(); 294 sop.mackey = key; 295 sop.mac = alg->code; 296 } 297 298 sop.crid = crid; 299 if (ioctl(fd, cmd, &sop) < 0) { 300 if (cmd == CIOCGSESSION || cmd == CIOCGSESSION2) { 301 close(fd); 302 if (verbose) { 303 printf("cipher %s%s%s", ealg? ealg->name : "", 304 (ealg && alg) ? "+" : "", 305 alg? alg->name : ""); 306 307 if (alg->ishash) 308 printf(" mackeylen %u\n", sop.mackeylen); 309 else 310 printf(" keylen %u\n", sop.keylen); 311 perror("CIOCGSESSION"); 312 } 313 /* hardware doesn't support algorithm; skip it */ 314 return; 315 } 316 printf("cipher %s%s%s keylen %u mackeylen %u\n", 317 ealg? ealg->name : "", (ealg && alg) ? "+" : "", 318 alg? alg->name : "", sop.keylen, sop.mackeylen); 319 err(1, "CIOCGSESSION"); 320 } 321 322 originaltext = malloc(3*size); 323 if (originaltext == NULL) 324 err(1, "malloc (text)"); 325 cleartext = originaltext+size; 326 ciphertext = cleartext+size; 327 for (i = 0; i < size; i++) 328 cleartext[i] = rdigit(); 329 memcpy(originaltext, cleartext, size); 330 for (i = 0; i < nitems(iv); i++) 331 iv[i] = rdigit(); 332 333 if (verbose) { 334 printf("session = 0x%x\n", sop.ses); 335 printf("device = %s\n", crfind(sop.crid)); 336 printf("count = %d, size = %d\n", count, size); 337 if (ealg) { 338 printf("iv:"); 339 hexdump(iv, sizeof iv); 340 } 341 printf("cleartext:"); 342 hexdump(cleartext, MIN(size, CHUNK)); 343 } 344 345 gettimeofday(&start, NULL); 346 if (ealg) { 347 for (i = 0; i < count; i++) { 348 cop.ses = sop.ses; 349 cop.op = COP_ENCRYPT; 350 cop.flags = opflags | COP_F_CIPHER_FIRST; 351 cop.len = size; 352 cop.src = cleartext; 353 cop.dst = ciphertext; 354 if (alg) 355 cop.mac = digest; 356 else 357 cop.mac = 0; 358 cop.iv = iv; 359 360 if (ioctl(fd, CIOCCRYPT, &cop) < 0) 361 err(1, "ioctl(CIOCCRYPT)"); 362 363 if (verify && bcmp(ciphertext, cleartext, size) == 0) { 364 printf("cipher text unchanged:"); 365 hexdump(ciphertext, size); 366 } 367 368 memset(cleartext, 'x', MIN(size, CHUNK)); 369 cop.ses = sop.ses; 370 cop.op = COP_DECRYPT; 371 cop.flags = opflags; 372 cop.len = size; 373 cop.src = ciphertext; 374 cop.dst = cleartext; 375 if (alg) 376 cop.mac = digest; 377 else 378 cop.mac = 0; 379 cop.iv = iv; 380 381 if (ioctl(fd, CIOCCRYPT, &cop) < 0) 382 err(1, "ioctl(CIOCCRYPT)"); 383 384 if (verify && bcmp(cleartext, originaltext, size) != 0) { 385 printf("decrypt mismatch:\n"); 386 printf("original:"); 387 hexdump(originaltext, size); 388 printf("cleartext:"); 389 hexdump(cleartext, size); 390 } 391 } 392 } else { 393 for (i = 0; i < count; i++) { 394 cop.ses = sop.ses; 395 cop.op = 0; 396 cop.flags = opflags; 397 cop.len = size; 398 cop.src = cleartext; 399 cop.dst = 0; 400 cop.mac = ciphertext; 401 cop.iv = 0; 402 403 if (ioctl(fd, CIOCCRYPT, &cop) < 0) 404 err(1, "ioctl(CIOCCRYPT)"); 405 } 406 } 407 gettimeofday(&stop, NULL); 408 409 if (ioctl(fd, CIOCFSESSION, &sop.ses) < 0) 410 perror("ioctl(CIOCFSESSION)"); 411 412 if (verbose) { 413 printf("cleartext:"); 414 hexdump(cleartext, MIN(size, CHUNK)); 415 } 416 timersub(&stop, &start, tv); 417 418 free(originaltext); 419 420 close(fd); 421 } 422 423 #ifdef __FreeBSD__ 424 void 425 resetstats() 426 { 427 struct cryptostats stats; 428 size_t slen; 429 430 slen = sizeof (stats); 431 if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) { 432 perror("kern.crypto_stats"); 433 return; 434 } 435 bzero(&stats.cs_invoke, sizeof (stats.cs_invoke)); 436 bzero(&stats.cs_done, sizeof (stats.cs_done)); 437 bzero(&stats.cs_cb, sizeof (stats.cs_cb)); 438 bzero(&stats.cs_finis, sizeof (stats.cs_finis)); 439 stats.cs_invoke.min.tv_sec = 10000; 440 stats.cs_done.min.tv_sec = 10000; 441 stats.cs_cb.min.tv_sec = 10000; 442 stats.cs_finis.min.tv_sec = 10000; 443 if (sysctlbyname("kern.crypto_stats", NULL, NULL, &stats, sizeof (stats)) < 0) 444 perror("kern.cryptostats"); 445 } 446 447 void 448 printt(const char* tag, struct cryptotstat *ts) 449 { 450 uint64_t avg, min, max; 451 452 if (ts->count == 0) 453 return; 454 avg = (1000000000LL*ts->acc.tv_sec + ts->acc.tv_nsec) / ts->count; 455 min = 1000000000LL*ts->min.tv_sec + ts->min.tv_nsec; 456 max = 1000000000LL*ts->max.tv_sec + ts->max.tv_nsec; 457 printf("%16.16s: avg %6llu ns : min %6llu ns : max %7llu ns [%u samps]\n", 458 tag, avg, min, max, ts->count); 459 } 460 #endif 461 462 void 463 runtests(struct alg *ealg, struct alg *alg, int count, int size, u_long cmd, int threads, int profile) 464 { 465 int i, status; 466 double t; 467 void *region; 468 struct timeval *tvp; 469 struct timeval total; 470 int otiming; 471 472 if (size % alg->blocksize || (ealg && size % ealg->blocksize)) { 473 if (verbose) 474 printf("skipping blocksize %u 'cuz not a multiple of " 475 "%s blocksize %u (or %s blocksize %u)\n", 476 size, alg->name, alg->blocksize, 477 ealg ? ealg->name : "n/a", 478 ealg ? ealg->blocksize : 0); 479 return; 480 } 481 482 region = mmap(NULL, threads * sizeof (struct timeval), 483 PROT_READ|PROT_WRITE, MAP_ANON|MAP_SHARED, -1, 0); 484 if (region == MAP_FAILED) { 485 perror("mmap"); 486 return; 487 } 488 tvp = (struct timeval *) region; 489 #ifdef __FreeBSD__ 490 if (profile) { 491 size_t tlen = sizeof (otiming); 492 int timing = 1; 493 494 resetstats(); 495 if (sysctlbyname("debug.crypto_timing", &otiming, &tlen, 496 &timing, sizeof (timing)) < 0) 497 perror("debug.crypto_timing"); 498 } 499 #endif 500 501 if (threads > 1) { 502 for (i = 0; i < threads; i++) 503 if (fork() == 0) { 504 cpuset_t mask; 505 CPU_ZERO(&mask); 506 CPU_SET(i, &mask); 507 cpuset_setaffinity(CPU_LEVEL_WHICH, CPU_WHICH_PID, 508 -1, sizeof(mask), &mask); 509 runtest(ealg, alg, count, size, cmd, &tvp[i]); 510 exit(0); 511 } 512 while (waitpid(WAIT_MYPGRP, &status, 0) != -1) 513 ; 514 } else 515 runtest(ealg, alg, count, size, cmd, tvp); 516 517 t = 0; 518 for (i = 0; i < threads; i++) 519 t += (((double)tvp[i].tv_sec * 1000000 + tvp[i].tv_usec) / 1000000); 520 if (t) { 521 int nops = alg->ishash ? count : 2*count; 522 523 nops *= threads; 524 printf("%8.3lf sec, %7d %6s%s%6s crypts, %7d bytes, %8.0lf byte/sec, %7.1lf Mb/sec\n", 525 t, nops, alg->name, ealg? "+" : "", ealg? ealg->name : "", 526 size, (double)nops*size / t, 527 (double)nops*size / t * 8 / 1024 / 1024); 528 } 529 #ifdef __FreeBSD__ 530 if (profile) { 531 struct cryptostats stats; 532 size_t slen = sizeof (stats); 533 534 if (sysctlbyname("debug.crypto_timing", NULL, NULL, 535 &otiming, sizeof (otiming)) < 0) 536 perror("debug.crypto_timing"); 537 if (sysctlbyname("kern.crypto_stats", &stats, &slen, NULL, 0) < 0) 538 perror("kern.cryptostats"); 539 if (stats.cs_invoke.count) { 540 printt("dispatch->invoke", &stats.cs_invoke); 541 printt("invoke->done", &stats.cs_done); 542 printt("done->cb", &stats.cs_cb); 543 printt("cb->finis", &stats.cs_finis); 544 } 545 } 546 #endif 547 fflush(stdout); 548 } 549 550 int 551 main(int argc, char **argv) 552 { 553 struct alg *alg = NULL, *ealg = NULL; 554 char *tmp; 555 int count = 1; 556 int sizes[128], nsizes = 0; 557 u_long cmd = CIOCGSESSION2; 558 int testall = 0; 559 int maxthreads = 1; 560 int profile = 0; 561 int i, ch; 562 563 while ((ch = getopt(argc, argv, "cpzsva:bd:t:")) != -1) { 564 switch (ch) { 565 #ifdef CIOCGSSESSION 566 case 's': 567 cmd = CIOCGSSESSION; 568 break; 569 #endif 570 case 'v': 571 verbose++; 572 break; 573 case 'a': 574 tmp = strchr(optarg, '+'); 575 if (tmp != NULL) { 576 *tmp = '\0'; 577 ealg = getalgbyname(optarg); 578 if (ealg == NULL || ealg->ishash) 579 usage(argv[0]); 580 optarg = tmp + 1; 581 } 582 583 alg = getalgbyname(optarg); 584 if (alg == NULL) { 585 if (streq(optarg, "rijndael")) 586 alg = getalgbyname("aes"); 587 else 588 usage(argv[0]); 589 } else if (ealg != NULL && !alg->ishash) 590 usage(argv[0]); 591 break; 592 case 'd': 593 crid = crlookup(optarg); 594 break; 595 case 't': 596 maxthreads = atoi(optarg); 597 break; 598 case 'z': 599 testall = 1; 600 break; 601 case 'p': 602 profile = 1; 603 break; 604 case 'b': 605 opflags |= COP_F_BATCH; 606 break; 607 case 'c': 608 verify = 1; 609 break; 610 default: 611 usage(argv[0]); 612 } 613 } 614 argc -= optind, argv += optind; 615 if (argc > 0) 616 count = atoi(argv[0]); 617 while (argc > 1) { 618 int s = atoi(argv[1]); 619 if (nsizes < nitems(sizes)) { 620 sizes[nsizes++] = s; 621 } else { 622 printf("Too many sizes, ignoring %u\n", s); 623 } 624 argc--, argv++; 625 } 626 if (maxthreads > CPU_SETSIZE) 627 errx(EX_USAGE, "Too many threads, %d, choose fewer.", maxthreads); 628 629 if (nsizes == 0) { 630 if (alg) 631 sizes[nsizes++] = alg->blocksize; 632 else 633 sizes[nsizes++] = 8; 634 if (testall) { 635 while (sizes[nsizes-1] < 8*1024) { 636 sizes[nsizes] = sizes[nsizes-1]<<1; 637 nsizes++; 638 } 639 } 640 } 641 642 if (testall) { 643 for (i = 0; i < nitems(algorithms); i++) { 644 int j; 645 alg = &algorithms[i]; 646 for (j = 0; j < nsizes; j++) 647 runtests(ealg, alg, count, sizes[j], cmd, maxthreads, profile); 648 } 649 } else { 650 if (alg == NULL) 651 alg = getalgbycode(CRYPTO_3DES_CBC); 652 for (i = 0; i < nsizes; i++) 653 runtests(ealg, alg, count, sizes[i], cmd, maxthreads, profile); 654 } 655 656 return (0); 657 } 658 659 void 660 hexdump(char *p, int n) 661 { 662 int i, off; 663 664 for (off = 0; n > 0; off += 16, n -= 16) { 665 printf("%s%04x:", off == 0 ? "\n" : "", off); 666 i = (n >= 16 ? 16 : n); 667 do { 668 printf(" %02x", *p++ & 0xff); 669 } while (--i); 670 printf("\n"); 671 } 672 } 673