]> git.saurik.com Git - apple/libdispatch.git/blob - src/benchmark.c
libdispatch-84.5.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 mach_timebase_info_data_t tbi;
26 uint64_t loop_cost;
27 void (*func)(void *);
28 void *ctxt;
29 size_t count;
30 };
31
32 static void
33 _dispatch_benchmark_init(void *context)
34 {
35 struct __dispatch_benchmark_data_s *bdata = context;
36 // try and simulate performance of real benchmark as much as possible
37 // keep 'f', 'c' and 'cnt' in registers
38 register void (*f)(void *) = bdata->func;
39 register void *c = bdata->ctxt;
40 register size_t cnt = bdata->count;
41 uint64_t start, delta;
42 #ifdef __LP64__
43 __uint128_t lcost;
44 #else
45 long double lcost;
46 #endif
47 kern_return_t kr;
48 size_t i = 0;
49
50 kr = mach_timebase_info(&bdata->tbi);
51 dispatch_assert_zero(kr);
52
53 start = mach_absolute_time();
54 do {
55 i++;
56 f(c);
57 } while (i < cnt);
58 delta = mach_absolute_time() - start;
59
60 lcost = delta;
61 lcost *= bdata->tbi.numer;
62 lcost /= bdata->tbi.denom;
63 lcost /= cnt;
64
65 bdata->loop_cost = lcost;
66 }
67
68 #ifdef __BLOCKS__
69 uint64_t
70 dispatch_benchmark(size_t count, void (^block)(void))
71 {
72 struct Block_basic *bb = (void *)block;
73 return dispatch_benchmark_f(count, block, (void *)bb->Block_invoke);
74 }
75 #endif
76
77 uint64_t
78 dispatch_benchmark_f(size_t count, register void *ctxt, register void (*func)(void *))
79 {
80 static struct __dispatch_benchmark_data_s bdata = {
81 .func = (void *)dummy_function,
82 .count = 10000000ul, // ten million
83 };
84 static dispatch_once_t pred;
85 uint64_t ns, start, delta;
86 #ifdef __LP64__
87 __uint128_t conversion, big_denom;
88 #else
89 long double conversion, big_denom;
90 #endif
91 size_t i = 0;
92
93 dispatch_once_f(&pred, &bdata, _dispatch_benchmark_init);
94
95 if (slowpath(count == 0)) {
96 return 0;
97 }
98
99 start = mach_absolute_time();
100 do {
101 i++;
102 func(ctxt);
103 } while (i < count);
104 delta = mach_absolute_time() - start;
105
106 conversion = delta;
107 conversion *= bdata.tbi.numer;
108 big_denom = bdata.tbi.denom;
109 big_denom *= count;
110 conversion /= big_denom;
111 ns = conversion;
112
113 return ns - bdata.loop_cost;
114 }