1/* 2 * Copyright (c) 2008-2013 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 23struct __dispatch_benchmark_data_s { 24#if HAVE_MACH_ABSOLUTE_TIME 25 mach_timebase_info_data_t tbi; 26#endif 27 uint64_t loop_cost; 28 void (*func)(void *); 29 void *ctxt; 30 size_t count; 31}; 32 33static void 34_dispatch_benchmark_init(void *context) 35{ 36 struct __dispatch_benchmark_data_s *bdata = context; 37 // try and simulate performance of real benchmark as much as possible 38 // keep 'f', 'c' and 'cnt' in registers 39 register void (*f)(void *) = bdata->func; 40 register void *c = bdata->ctxt; 41 register size_t cnt = bdata->count; 42 size_t i = 0; 43 uint64_t start, delta; 44#if defined(__LP64__) 45 __uint128_t lcost; 46#else 47 long double lcost; 48#endif 49#if HAVE_MACH_ABSOLUTE_TIME 50 kern_return_t kr; 51 52 kr = mach_timebase_info(&bdata->tbi); 53 dispatch_assert_zero(kr); 54#endif 55 56 start = _dispatch_absolute_time(); 57 do { 58 i++; 59 f(c); 60 } while (i < cnt); 61 delta = _dispatch_absolute_time() - start; 62 63 lcost = delta; 64#if HAVE_MACH_ABSOLUTE_TIME 65 lcost *= bdata->tbi.numer; 66 lcost /= bdata->tbi.denom; 67#endif 68 lcost /= cnt; 69 70 bdata->loop_cost = lcost > UINT64_MAX ? UINT64_MAX : (uint64_t)lcost; 71} 72 73#ifdef __BLOCKS__ 74uint64_t 75dispatch_benchmark(size_t count, void (^block)(void)) 76{ 77 return dispatch_benchmark_f(count, block, _dispatch_Block_invoke(block)); 78} 79#endif 80 81static void 82_dispatch_benchmark_dummy_function(void *ctxt DISPATCH_UNUSED) 83{ 84} 85 86uint64_t 87dispatch_benchmark_f(size_t count, register void *ctxt, 88 register void (*func)(void *)) 89{ 90 static struct __dispatch_benchmark_data_s bdata = { 91 .func = _dispatch_benchmark_dummy_function, 92 .count = 10000000ul, // ten million 93 }; 94 static dispatch_once_t pred; 95 uint64_t ns, start, delta; 96#if defined(__LP64__) 97 __uint128_t conversion, big_denom; 98#else 99 long double conversion, big_denom; 100#endif 101 size_t i = 0; 102 103 dispatch_once_f(&pred, &bdata, _dispatch_benchmark_init); 104 105 if (slowpath(count == 0)) { 106 return 0; 107 } 108 109 start = _dispatch_absolute_time(); 110 do { 111 i++; 112 func(ctxt); 113 } while (i < count); 114 delta = _dispatch_absolute_time() - start; 115 116 conversion = delta; 117#if HAVE_MACH_ABSOLUTE_TIME 118 conversion *= bdata.tbi.numer; 119 big_denom = bdata.tbi.denom; 120#else 121 big_denom = delta; 122#endif 123 big_denom *= count; 124 conversion /= big_denom; 125 ns = conversion > UINT64_MAX ? UINT64_MAX : (uint64_t)conversion; 126 127 return ns - bdata.loop_cost; 128} 129