]> git.saurik.com Git - apple/security.git/blob - SecurityTests/clxutils/secTime/secTime.cpp
Security-57031.1.35.tar.gz
[apple/security.git] / SecurityTests / clxutils / secTime / secTime.cpp
1 /*
2 * secTime.cpp - measure performance of Sec* ops
3 */
4
5 #include <Security/Security.h>
6 #include <security_cdsa_utils/cuFileIo.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <sys/param.h>
11 #include <CoreFoundation/CoreFoundation.h>
12 #include <security_utilities/devrandom.h>
13 #include <clAppUtils/certVerify.h>
14 #include <clAppUtils/clutils.h>
15 #include <utilLib/common.h>
16
17 /*
18 * Hard coded test params
19 */
20
21 /*
22 * The keychain we open and search for certs.
23 * MUST exist in ~/Library/Keychains.
24 * YOU can create it with
25 * % certtool c k=secTimeKc c p=secTimeKc Z
26 */
27 #define ST_KC_NAME "secTimeKc"
28
29 /*
30 * Certs to verify with SecTrust. We have a variety because the timing on
31 * this test is highly dependent on the position of the verifying anchor
32 * within the system anchors list. (This does not apply to Trust Settings).
33 */
34 typedef struct {
35 const char *certFileName;
36 const char *hostName;
37 } CertToVerify;
38
39 static const CertToVerify certsToVerify[] =
40 {
41 {
42 /* issuer: Secure Server Certification Authority */
43 "amazon_v3.100.cer",
44 "www.amazon.com"
45 },
46 {
47 /* issuer: Equifax Secure Certificate Authority */
48 "firstamlink.cer",
49 "www.firstamlink.com"
50 },
51 };
52
53 #define NUM_ST_CERTS (sizeof(certsToVerify) / sizeof(certsToVerify[0]))
54
55 /* explicit anchor for certsToVerify[0] */
56 #define ST_ANCHOR_NAME "SecureServer.509.cer" /* verifies ST_CERT_HOST */
57
58 /*
59 * Cert chain for cgv3*()
60 */
61 #define THAWTE_LEAF "dmitchThawte.cer"
62 #define THAWTE_CA "ThawteCA.cer"
63 #define THAWTE_ROOT "ThawteRoot.cer"
64
65 static void usage(char **argv)
66 {
67 printf("Usage: %s [option ...]\n", argv[0]);
68 printf("Options:\n");
69 printf(" t=testspec; default=all\n");
70 printf(" test specs: o keychainOpen\n");
71 printf(" s keychainSearch\n");
72 printf(" e secTrustEvaluate\n");
73 printf(" k SecKeychainCopySearchList\n");
74 printf(" v TP CertGroupVerify, system anchor\n");
75 printf(" V TP CertGroupVerify, explicit anchor\n");
76 printf(" 3 TP CertGroupVerify, 3 certs w/anchor\n");
77 printf(" l=loops (only valid if testspec is given)\n");
78 exit(1);
79 }
80
81 static void printSecErr(
82 const char *op,
83 OSStatus ortn)
84 {
85 printf("%s returned %ld\n", op, (unsigned long)ortn);
86 }
87
88 /*
89 * Struct passed around to test-specific functions.
90 */
91 typedef struct {
92 const char *testName;
93 void *testPriv;
94 } TestParams;
95
96 /*
97 * Each subtest has three functions - init, run, cleanup, called out
98 * from main().
99 *
100 * Init's job is one-time setup - open files, setup buffers, etc.
101 * PErsistent state can be saved in TestParams->testPriv.
102 */
103 typedef OSStatus (*testInitFcn)(TestParams *testParams);
104
105 /*
106 * Run's job is to perform 1 iteration with as
107 * little overhead as possible. Return the time spect actually
108 * doing the deed in *timeSpent.
109 */
110 typedef OSStatus (*testRunFcn)(TestParams *testParams,
111 unsigned loopNum,
112 CFAbsoluteTime *timeSpent);
113
114 /*
115 * CLeanu up any resources allocd in init.
116 */
117 typedef OSStatus (*testCleanupFcn)(TestParams *testParams);
118
119 /*
120 * Static declaration of a test
121 */
122 typedef struct {
123 const char *testName;
124 unsigned loops;
125 testInitFcn init;
126 testRunFcn run;
127 testCleanupFcn cleanup;
128 char testSpec; // for t=xxx cmd line opt
129 } TestDefs;
130
131 #pragma mark ---- Individual tests ----
132
133 #ifdef use_these_as_a_template
134
135 static OSStatus xxxInit(
136 TestParams *testParams)
137 {
138 return noErr;
139 }
140
141 static OSStatus xxRun(
142 TestParams *testParams,
143 unsigned loopNum,
144 CFAbsoluteTime *timeSpent)
145 {
146 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
147 /* do the op here */
148 *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
149 return noErr;
150 }
151
152 static OSStatus xxxCleanup(
153 TestParams *testParams)
154 {
155 return noErr;
156 }
157 #endif /* template */
158
159 #pragma mark -- keychain open --
160
161 static OSStatus kcOpenInit(
162 TestParams *testParams)
163 {
164 return noErr;
165 }
166
167 static OSStatus kcOpenRun(
168 TestParams *testParams,
169 unsigned loopNum,
170 CFAbsoluteTime *timeSpent)
171 {
172 SecKeychainRef kcRef;
173 SecKeychainStatus status;
174
175 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
176 OSStatus ortn = SecKeychainOpen(ST_KC_NAME, &kcRef);
177 if(ortn) {
178 printSecErr("SecKeychainOpen", ortn);
179 return ortn;
180 }
181 ortn = SecKeychainGetStatus(kcRef, &status);
182 if(ortn) {
183 printSecErr("SecKeychainGetStatus", ortn);
184 CFRelease(kcRef);
185 if(errSecNoSuchKeychain == ortn) {
186 printf("The keychain %s does not exist. Please create it"
187 " and populate it like so:\n", ST_KC_NAME);
188 printf(" certtool c k=%s c p=%s Z\n",
189 ST_KC_NAME, ST_KC_NAME);
190 }
191 return ortn;
192 }
193 CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
194 *timeSpent = endTime - startTime;
195 CFRelease(kcRef);
196 return noErr;
197 }
198
199 static OSStatus kcOpenCleanup(
200 TestParams *testParams)
201 {
202 return noErr;
203 }
204
205 #pragma mark -- keychain lookup --
206
207 /*
208 * Private *testPriv is a kcRef.
209 */
210 static OSStatus kcSearchInit(
211 TestParams *testParams)
212 {
213 SecKeychainRef kcRef;
214 OSStatus ortn = SecKeychainOpen(ST_KC_NAME, &kcRef);
215 if(ortn) {
216 printSecErr("SecKeychainOpen", ortn);
217 return ortn;
218 }
219 testParams->testPriv = (void *)kcRef;
220 return noErr;
221 }
222
223 static OSStatus kcSearchRun(
224 TestParams *testParams,
225 unsigned loopNum,
226 CFAbsoluteTime *timeSpent)
227 {
228 SecKeychainRef kcRef = (SecKeychainRef)testParams->testPriv;
229 SecKeychainSearchRef srchRef = NULL;
230 SecKeychainItemRef certRef = NULL;
231 CFAbsoluteTime endTime;
232 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
233
234 /* search for any cert */
235 OSStatus ortn = SecKeychainSearchCreateFromAttributes(kcRef,
236 kSecCertificateItemClass,
237 NULL, // no attrs
238 &srchRef);
239 if(ortn) {
240 printSecErr("SecKeychainSearchCreateFromAttributes", ortn);
241 return ortn;
242 }
243 ortn = SecKeychainSearchCopyNext(srchRef, &certRef);
244 if(ortn) {
245 printSecErr("SecKeychainSearchCopyNext", ortn);
246 goto done;
247 }
248 endTime = CFAbsoluteTimeGetCurrent();
249 *timeSpent = endTime - startTime;
250 done:
251 if(srchRef) {
252 CFRelease(srchRef);
253 }
254 if(certRef) {
255 CFRelease(certRef);
256 }
257 return ortn;
258 }
259
260
261 static OSStatus kcSearchCleanup(
262 TestParams *testParams)
263 {
264 SecKeychainRef kcRef = (SecKeychainRef)testParams->testPriv;
265 CFRelease(kcRef);
266 return noErr;
267 }
268
269 #pragma mark -- SecTrustEvaluate --
270
271 /*
272 * Priv data is an array of SecCertificateRef containing certs to evaluate.
273 * Each run evaluates one of them.
274 */
275 static OSStatus secTrustInit(
276 TestParams *testParams)
277 {
278 unsigned char *certData;
279 unsigned certLen;
280 CSSM_DATA cdata;
281
282 SecCertificateRef *certRefs;
283
284 certRefs = (SecCertificateRef *)malloc(
285 sizeof(SecCertificateRef) * NUM_ST_CERTS);
286
287 for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
288 if(readFile(certsToVerify[dex].certFileName, &certData, &certLen)) {
289 printf("***Can not find cert file %s. Aborting.\n",
290 certsToVerify[dex].certFileName);
291 return -1;
292 }
293 cdata.Data = certData;
294 cdata.Length = certLen;
295 SecCertificateRef certRef;
296 OSStatus ortn = SecCertificateCreateFromData(&cdata,
297 CSSM_CERT_X_509v3,
298 CSSM_CERT_ENCODING_DER,
299 &certRef);
300 if(ortn) {
301 printSecErr("SecCertificateCreateFromData", ortn);
302 return ortn;
303 }
304 free(certData); // mallocd by readFile()
305 certRefs[dex] = certRef;
306 }
307 testParams->testPriv = certRefs;
308 return noErr;
309 }
310
311 static OSStatus secTrustRun(
312 TestParams *testParams,
313 unsigned loopNum,
314 CFAbsoluteTime *timeSpent)
315 {
316 unsigned whichDex = loopNum % NUM_ST_CERTS;
317 SecCertificateRef *certRefs = (SecCertificateRef *)testParams->testPriv;
318 SecCertificateRef certRef = certRefs[whichDex];
319
320 /*
321 * We measure the whole enchilada, that's what SecureTransport
322 * has to do
323 */
324 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
325
326 CFMutableArrayRef certs;
327 certs = CFArrayCreateMutable(NULL, 1, &kCFTypeArrayCallBacks);
328 CFArrayInsertValueAtIndex(certs, 0, certRef);
329
330 SecPolicyRef policy = NULL;
331 SecPolicySearchRef policySearch = NULL;
332
333 OSStatus ortn = SecPolicySearchCreate(CSSM_CERT_X_509v3,
334 &CSSMOID_APPLE_TP_SSL,
335 NULL, // policy opts
336 &policySearch);
337 if(ortn) {
338 printSecErr("SecPolicySearchCreate", ortn);
339 return ortn;
340 }
341
342 ortn = SecPolicySearchCopyNext(policySearch, &policy);
343 if(ortn) {
344 printSecErr("SecPolicySearchCopyNext", ortn);
345 return ortn;
346 }
347 CFRelease(policySearch);
348
349 SecTrustRef secTrust;
350 ortn = SecTrustCreateWithCertificates(certs, policy, &secTrust);
351 if(ortn) {
352 printSecErr("SecTrustCreateWithCertificates", ortn);
353 return ortn;
354 }
355 /* no action data for now */
356
357 SecTrustResultType secTrustResult;
358 ortn = SecTrustEvaluate(secTrust, &secTrustResult);
359 if(ortn) {
360 printSecErr("SecTrustEvaluate", ortn);
361 return ortn;
362 }
363
364 CFRelease(certs);
365 CFRelease(secTrust);
366 CFRelease(policy);
367
368 CFAbsoluteTime endTime = CFAbsoluteTimeGetCurrent();
369 *timeSpent = endTime - startTime;
370
371 return noErr;
372 }
373
374 static OSStatus secTrustCleanup(
375 TestParams *testParams)
376 {
377 SecCertificateRef *certRefs = (SecCertificateRef*)testParams->testPriv;
378 for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
379 CFRelease(certRefs[dex]);
380 }
381 free(certRefs);
382 return noErr;
383 }
384
385 #pragma mark -- SecKeychainCopySearchList --
386
387 static OSStatus kcCSLInit(
388 TestParams *testParams)
389 {
390 return noErr;
391 }
392
393 static OSStatus kcCSLRun(
394 TestParams *testParams,
395 unsigned loopNum,
396 CFAbsoluteTime *timeSpent)
397 {
398 CFArrayRef sl;
399 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
400 OSStatus ortn = SecKeychainCopySearchList(&sl);
401 if(ortn) {
402 printSecErr("SecKeychainCopySearchList", ortn);
403 return ortn;
404 }
405 CFRelease(sl);
406 *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
407 return noErr;
408 }
409
410 static OSStatus kcCSLCleanup(
411 TestParams *testParams)
412 {
413 return noErr;
414 }
415
416 #pragma mark -- CSSM_TP_CertGroupVerify, system anchors --
417
418 /* private data allocated in cgvInit */
419 typedef struct {
420 CSSM_TP_HANDLE tpHand;
421 CSSM_CL_HANDLE clHand;
422 CSSM_CSP_HANDLE cspHand;
423 BlobList *certs[NUM_ST_CERTS];
424 BlobList *anchors; /* cgvAnchor* only */
425 } CgvParams;
426
427 static OSStatus cgvInit(
428 TestParams *testParams)
429 {
430 CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
431 memset(cgvParams, 0, sizeof(CgvParams));
432 cgvParams->tpHand = tpStartup();
433 cgvParams->clHand = clStartup();
434 cgvParams->cspHand = cspStartup();
435 for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
436 cgvParams->certs[dex] = new BlobList();
437 cgvParams->certs[dex]->addFile(certsToVerify[dex].certFileName);
438 }
439 cgvParams->anchors = NULL;
440 testParams->testPriv = cgvParams;
441 return noErr;
442 }
443
444 static OSStatus cgvRun(
445 TestParams *testParams,
446 unsigned loopNum,
447 CFAbsoluteTime *timeSpent)
448 {
449 CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
450 BlobList nullList;
451 unsigned whichDex = loopNum % NUM_ST_CERTS;
452 BlobList *certBlob = cgvParams->certs[whichDex];
453
454 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
455 int rtn = certVerifySimple(
456 cgvParams->tpHand,
457 cgvParams->clHand,
458 cgvParams->cspHand,
459 *certBlob, // contains one cert, the subject
460 nullList, // roots
461 CSSM_TRUE, // useSystemAnchors
462 CSSM_FALSE, // leafCertIsCa
463 CSSM_FALSE, // allow expired root
464 CVP_SSL,
465 certsToVerify[whichDex].hostName,
466 CSSM_FALSE, // sslClient
467 NULL, // senderEmail
468 0, // key use
469 NULL, // expected error str
470 0, // numCertErrors
471 NULL,
472 0, // numCertStatus
473 NULL,
474 CSSM_FALSE, // trustSettings
475 CSSM_TRUE, // quiet
476 CSSM_FALSE); // verbose
477 *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
478 if(rtn) {
479 printf("***certVerify error\n");
480 return (OSStatus)rtn;
481 }
482 return noErr;
483 }
484
485 static OSStatus cgvCleanup(
486 TestParams *testParams)
487 {
488 CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
489 CSSM_ModuleDetach(cgvParams->cspHand);
490 CSSM_ModuleDetach(cgvParams->tpHand);
491 CSSM_ModuleDetach(cgvParams->clHand);
492 for(unsigned dex=0; dex<NUM_ST_CERTS; dex++) {
493 delete cgvParams->certs[dex];
494 }
495 if(cgvParams->anchors) {
496 delete(cgvParams->anchors);
497 }
498 free(cgvParams);
499 return noErr;
500 }
501
502 #pragma mark -- CSSM_TP_CertGroupVerify, explicit anchors --
503
504 static OSStatus cgvAnchorInit(
505 TestParams *testParams)
506 {
507 CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
508 memset(cgvParams, 0, sizeof(CgvParams));
509 cgvParams->tpHand = tpStartup();
510 cgvParams->clHand = clStartup();
511 cgvParams->cspHand = cspStartup();
512 cgvParams->certs[0] = new BlobList();
513 cgvParams->certs[0]->addFile(certsToVerify[0].certFileName);
514 cgvParams->anchors = new BlobList();
515 cgvParams->anchors->addFile(ST_ANCHOR_NAME);
516 testParams->testPriv = cgvParams;
517 return noErr;
518 }
519
520 static OSStatus cgvAnchorRun(
521 TestParams *testParams,
522 unsigned loopNum,
523 CFAbsoluteTime *timeSpent)
524 {
525 CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
526 BlobList nullList;
527
528 CertVerifyArgs vfyArgs;
529 memset(&vfyArgs, 0, sizeof(vfyArgs));
530 vfyArgs.version = CERT_VFY_ARGS_VERS;
531
532 vfyArgs.tpHand = cgvParams->tpHand;
533 vfyArgs.clHand = cgvParams->clHand;
534 vfyArgs.cspHand = cgvParams->cspHand;
535 vfyArgs.certs = cgvParams->certs[0];
536 vfyArgs.roots = cgvParams->anchors;
537 vfyArgs.allowUnverified = CSSM_TRUE;
538 vfyArgs.vfyPolicy = CVP_SSL;
539 vfyArgs.revokePolicy = CRP_None;
540 vfyArgs.sslHost = certsToVerify[0].hostName;
541 vfyArgs.revokePolicy = CRP_None;
542 vfyArgs.quiet = CSSM_TRUE;
543
544 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
545 int rtn = certVerify(&vfyArgs);
546 *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
547 if(rtn) {
548 printf("***certVerify error\n");
549 return (OSStatus)rtn;
550 }
551 return noErr;
552 }
553
554 /* cleanup - use cgvCleanup() */
555
556 #pragma mark -- CSSM_TP_CertGroupVerify, 3 certs with anchor --
557
558 static OSStatus cgv3Init(
559 TestParams *testParams)
560 {
561 CgvParams *cgvParams = (CgvParams *)malloc(sizeof(CgvParams));
562 memset(cgvParams, 0, sizeof(CgvParams));
563 cgvParams->tpHand = tpStartup();
564 cgvParams->clHand = clStartup();
565 cgvParams->cspHand = cspStartup();
566 cgvParams->certs[0] = new BlobList();
567 cgvParams->certs[0]->addFile(THAWTE_LEAF);
568 cgvParams->certs[0]->addFile(THAWTE_CA);
569 cgvParams->certs[0]->addFile(THAWTE_ROOT);
570 cgvParams->anchors = new BlobList();
571 cgvParams->anchors->addFile(THAWTE_ROOT);
572 testParams->testPriv = cgvParams;
573 return noErr;
574 }
575
576 static OSStatus cgv3Run(
577 TestParams *testParams,
578 unsigned loopNum,
579 CFAbsoluteTime *timeSpent)
580 {
581 CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
582 BlobList nullList;
583
584 CertVerifyArgs vfyArgs;
585 memset(&vfyArgs, 0, sizeof(vfyArgs));
586 vfyArgs.version = CERT_VFY_ARGS_VERS;
587
588 vfyArgs.tpHand = cgvParams->tpHand;
589 vfyArgs.clHand = cgvParams->clHand;
590 vfyArgs.cspHand = cgvParams->cspHand;
591 vfyArgs.certs = cgvParams->certs[0]; /* that's three certs */
592 vfyArgs.roots = cgvParams->anchors;
593 vfyArgs.allowUnverified = CSSM_TRUE;
594 vfyArgs.vfyPolicy = CVP_Basic;
595 vfyArgs.revokePolicy = CRP_None;
596 vfyArgs.sslHost = certsToVerify[0].hostName;
597 vfyArgs.revokePolicy = CRP_None;
598 vfyArgs.quiet = CSSM_TRUE;
599
600 CFAbsoluteTime startTime = CFAbsoluteTimeGetCurrent();
601 int rtn = certVerify(&vfyArgs);
602 *timeSpent = CFAbsoluteTimeGetCurrent() - startTime;
603 if(rtn) {
604 printf("***certVerify error\n");
605 return (OSStatus)rtn;
606 }
607 return noErr;
608 }
609
610 static OSStatus cgv3Cleanup(
611 TestParams *testParams)
612 {
613 CgvParams *cgvParams = (CgvParams *)testParams->testPriv;
614 CSSM_ModuleDetach(cgvParams->cspHand);
615 CSSM_ModuleDetach(cgvParams->tpHand);
616 CSSM_ModuleDetach(cgvParams->clHand);
617 delete cgvParams->certs[0];
618 delete(cgvParams->anchors);
619 free(cgvParams);
620 return noErr;
621 }
622
623 #pragma mark ---- Static array of all tests ----
624
625 static TestDefs testDefs[] =
626 {
627 { "Keychain open",
628 100,
629 kcOpenInit,
630 kcOpenRun,
631 kcOpenCleanup,
632 'o',
633 },
634 { "Keychain cert search",
635 100,
636 kcSearchInit,
637 kcSearchRun,
638 kcSearchCleanup,
639 's',
640 },
641 { "SecTrustEvaluate",
642 100,
643 secTrustInit,
644 secTrustRun,
645 secTrustCleanup,
646 'e',
647 },
648 { "TP CertGroupVerify, system anchors",
649 100,
650 cgvInit,
651 cgvRun,
652 cgvCleanup,
653 'v',
654 },
655 { "TP CertGroupVerify, explicit anchor",
656 100,
657 cgvAnchorInit,
658 cgvAnchorRun,
659 cgvCleanup,
660 'V',
661 },
662 { "TP CertGroupVerify, 3 certs with anchor",
663 100,
664 cgv3Init,
665 cgv3Run,
666 cgv3Cleanup,
667 '3',
668 },
669 { "SecKeychainCopySearchList",
670 100,
671 kcCSLInit,
672 kcCSLRun,
673 kcCSLCleanup,
674 'k',
675 },
676 };
677
678 #define NUM_TESTS (sizeof(testDefs) / sizeof(testDefs[0]))
679
680 int main(int argc, char **argv)
681 {
682 TestParams testParams;
683 TestDefs *testDef;
684 OSStatus ortn;
685 int arg;
686 char *argp;
687 unsigned cmdLoops = 0; // can be specified in cmd line
688 // if not, use TestDefs.loops
689 char testSpec = '\0'; // allows specification of one test
690 // otherwise run all
691
692 for(arg=1; arg<argc; arg++) {
693 argp = argv[arg];
694 switch(argp[0]) {
695 case 't':
696 testSpec = argp[2];
697 break;
698 case 'l':
699 cmdLoops = atoi(&argp[2]);
700 break;
701 default:
702 usage(argv);
703 }
704 }
705
706 for(unsigned testNum=0; testNum<NUM_TESTS; testNum++) {
707 testDef = &testDefs[testNum];
708 unsigned loopCount;
709
710 if(testSpec && (testDef->testSpec != testSpec)) {
711 continue;
712 }
713 printf("%s:\n", testDef->testName);
714 ortn = testDef->init(&testParams);
715 if(ortn) {
716 exit(1);
717 }
718 if(cmdLoops) {
719 /* user specified */
720 loopCount = cmdLoops;
721 }
722 else {
723 /* default */
724 loopCount = testDef->loops;
725 }
726 CFAbsoluteTime totalTime = 0;
727 CFAbsoluteTime thisTime;
728 for(unsigned loop=0; loop<loopCount; loop++) {
729 ortn = testDef->run(&testParams, loop, &thisTime);
730 if(ortn) {
731 exit(1);
732 }
733 totalTime += thisTime;
734 }
735 testDef->cleanup(&testParams);
736 printf(" %3.2f ms per op\n", (totalTime / loopCount) * 1000.0);
737 }
738 return 0;
739 }