#include "internal.h"
struct __dispatch_benchmark_data_s {
#if HAVE_MACH_ABSOLUTE_TIME
mach_timebase_info_data_t tbi;
#endif
uint64_t loop_cost;
void (*func)(void *);
void *ctxt;
size_t count;
};
static void
_dispatch_benchmark_init(void *context)
{
struct __dispatch_benchmark_data_s *bdata = context;
register void (*f)(void *) = bdata->func;
register void *c = bdata->ctxt;
register size_t cnt = bdata->count;
size_t i = 0;
uint64_t start, delta;
#if defined(__LP64__)
__uint128_t lcost;
#else
long double lcost;
#endif
#if HAVE_MACH_ABSOLUTE_TIME
kern_return_t kr;
kr = mach_timebase_info(&bdata->tbi);
dispatch_assert_zero(kr);
#endif
start = _dispatch_uptime();
do {
i++;
f(c);
} while (i < cnt);
delta = _dispatch_uptime() - start;
lcost = delta;
#if HAVE_MACH_ABSOLUTE_TIME
lcost *= bdata->tbi.numer;
lcost /= bdata->tbi.denom;
#endif
lcost /= cnt;
bdata->loop_cost = lcost > UINT64_MAX ? UINT64_MAX : (uint64_t)lcost;
}
#ifdef __BLOCKS__
uint64_t
dispatch_benchmark(size_t count, void (^block)(void))
{
return dispatch_benchmark_f(count, block, _dispatch_Block_invoke(block));
}
#endif
static void
_dispatch_benchmark_dummy_function(void *ctxt DISPATCH_UNUSED)
{
}
uint64_t
dispatch_benchmark_f(size_t count, register void *ctxt,
register void (*func)(void *))
{
static struct __dispatch_benchmark_data_s bdata = {
.func = _dispatch_benchmark_dummy_function,
.count = 10000000ul, };
static dispatch_once_t pred;
uint64_t ns, start, delta;
#if defined(__LP64__)
__uint128_t conversion, big_denom;
#else
long double conversion, big_denom;
#endif
size_t i = 0;
dispatch_once_f(&pred, &bdata, _dispatch_benchmark_init);
if (unlikely(count == 0)) {
return 0;
}
start = _dispatch_uptime();
do {
i++;
func(ctxt);
} while (i < count);
delta = _dispatch_uptime() - start;
conversion = delta;
#if HAVE_MACH_ABSOLUTE_TIME
conversion *= bdata.tbi.numer;
big_denom = bdata.tbi.denom;
#else
big_denom = delta;
#endif
big_denom *= count;
conversion /= big_denom;
ns = conversion > UINT64_MAX ? UINT64_MAX : (uint64_t)conversion;
return ns - bdata.loop_cost;
}