]> git.saurik.com Git - apple/libdispatch.git/blob - src/benchmark.c
libdispatch-187.9.tar.gz
[apple/libdispatch.git] / src / benchmark.c
1 /*
2 * Copyright (c) 2008-2009 Apple Inc. All rights reserved.
3 *
4 * @APPLE_APACHE_LICENSE_HEADER_START@
5 *
6 * Licensed under the Apache License, Version 2.0 (the "License");
7 * you may not use this file except in compliance with the License.
8 * You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 *
18 * @APPLE_APACHE_LICENSE_HEADER_END@
19 */
20
21 #include "internal.h"
22
23
24 struct __dispatch_benchmark_data_s {
25 #if HAVE_MACH_ABSOLUTE_TIME
26 mach_timebase_info_data_t tbi;
27 #endif
28 uint64_t loop_cost;
29 void (*func)(void *);
30 void *ctxt;
31 size_t count;
32 };
33
34 static void
35 _dispatch_benchmark_init(void *context)
36 {
37 struct __dispatch_benchmark_data_s *bdata = context;
38 // try and simulate performance of real benchmark as much as possible
39 // keep 'f', 'c' and 'cnt' in registers
40 register void (*f)(void *) = bdata->func;
41 register void *c = bdata->ctxt;
42 register size_t cnt = bdata->count;
43 size_t i = 0;
44 uint64_t start, delta;
45 #if defined(__LP64__)
46 __uint128_t lcost;
47 #else
48 long double lcost;
49 #endif
50 #if HAVE_MACH_ABSOLUTE_TIME
51 kern_return_t kr;
52
53 kr = mach_timebase_info(&bdata->tbi);
54 dispatch_assert_zero(kr);
55 #endif
56
57 start = _dispatch_absolute_time();
58 do {
59 i++;
60 f(c);
61 } while (i < cnt);
62 delta = _dispatch_absolute_time() - start;
63
64 lcost = delta;
65 #if HAVE_MACH_ABSOLUTE_TIME
66 lcost *= bdata->tbi.numer;
67 lcost /= bdata->tbi.denom;
68 #endif
69 lcost /= cnt;
70
71 bdata->loop_cost = lcost;
72 }
73
74 #ifdef __BLOCKS__
75 uint64_t
76 dispatch_benchmark(size_t count, void (^block)(void))
77 {
78 struct Block_basic *bb = (void *)block;
79 return dispatch_benchmark_f(count, block, (void *)bb->Block_invoke);
80 }
81 #endif
82
83 uint64_t
84 dispatch_benchmark_f(size_t count, register void *ctxt,
85 register void (*func)(void *))
86 {
87 static struct __dispatch_benchmark_data_s bdata = {
88 .func = (void *)dummy_function,
89 .count = 10000000ul, // ten million
90 };
91 static dispatch_once_t pred;
92 uint64_t ns, start, delta;
93 #if defined(__LP64__)
94 __uint128_t conversion, big_denom;
95 #else
96 long double conversion, big_denom;
97 #endif
98 size_t i = 0;
99
100 dispatch_once_f(&pred, &bdata, _dispatch_benchmark_init);
101
102 if (slowpath(count == 0)) {
103 return 0;
104 }
105
106 start = _dispatch_absolute_time();
107 do {
108 i++;
109 func(ctxt);
110 } while (i < count);
111 delta = _dispatch_absolute_time() - start;
112
113 conversion = delta;
114 #if HAVE_MACH_ABSOLUTE_TIME
115 conversion *= bdata.tbi.numer;
116 big_denom = bdata.tbi.denom;
117 #else
118 big_denom = delta;
119 #endif
120 big_denom *= count;
121 conversion /= big_denom;
122 ns = conversion;
123
124 return ns - bdata.loop_cost;
125 }