1*a0483764SConrad Meyer /* 2*a0483764SConrad Meyer * Copyright (c) 2016-present, Yann Collet, Facebook, Inc. 3*a0483764SConrad Meyer * All rights reserved. 4*a0483764SConrad Meyer * 5*a0483764SConrad Meyer * This source code is licensed under both the BSD-style license (found in the 6*a0483764SConrad Meyer * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7*a0483764SConrad Meyer * in the COPYING file in the root directory of this source tree). 8*a0483764SConrad Meyer * You may select, at your option, one of the above-listed licenses. 9*a0483764SConrad Meyer */ 10*a0483764SConrad Meyer 11*a0483764SConrad Meyer 12*a0483764SConrad Meyer /* benchfn : 13*a0483764SConrad Meyer * benchmark any function on a set of input 14*a0483764SConrad Meyer * providing result in nanoSecPerRun 15*a0483764SConrad Meyer * or detecting and returning an error 16*a0483764SConrad Meyer */ 17*a0483764SConrad Meyer 18*a0483764SConrad Meyer #if defined (__cplusplus) 19*a0483764SConrad Meyer extern "C" { 20*a0483764SConrad Meyer #endif 21*a0483764SConrad Meyer 22*a0483764SConrad Meyer #ifndef BENCH_FN_H_23876 23*a0483764SConrad Meyer #define BENCH_FN_H_23876 24*a0483764SConrad Meyer 25*a0483764SConrad Meyer /* === Dependencies === */ 26*a0483764SConrad Meyer #include <stddef.h> /* size_t */ 27*a0483764SConrad Meyer 28*a0483764SConrad Meyer 29*a0483764SConrad Meyer /* ==== Benchmark any function, iterated on a set of blocks ==== */ 30*a0483764SConrad Meyer 31*a0483764SConrad Meyer /* BMK_runTime_t: valid result return type */ 32*a0483764SConrad Meyer 33*a0483764SConrad Meyer typedef struct { 34*a0483764SConrad Meyer unsigned long long nanoSecPerRun; /* time per iteration (over all blocks) */ 35*a0483764SConrad Meyer size_t sumOfReturn; /* sum of return values */ 36*a0483764SConrad Meyer } BMK_runTime_t; 37*a0483764SConrad Meyer 38*a0483764SConrad Meyer 39*a0483764SConrad Meyer /* BMK_runOutcome_t: 40*a0483764SConrad Meyer * type expressing the outcome of a benchmark run by BMK_benchFunction(), 41*a0483764SConrad Meyer * which can be either valid or invalid. 42*a0483764SConrad Meyer * benchmark outcome can be invalid if errorFn is provided. 43*a0483764SConrad Meyer * BMK_runOutcome_t must be considered "opaque" : never access its members directly. 44*a0483764SConrad Meyer * Instead, use its assigned methods : 45*a0483764SConrad Meyer * BMK_isSuccessful_runOutcome, BMK_extract_runTime, BMK_extract_errorResult. 46*a0483764SConrad Meyer * The structure is only described here to allow its allocation on stack. */ 47*a0483764SConrad Meyer 48*a0483764SConrad Meyer typedef struct { 49*a0483764SConrad Meyer BMK_runTime_t internal_never_ever_use_directly; 50*a0483764SConrad Meyer size_t error_result_never_ever_use_directly; 51*a0483764SConrad Meyer int error_tag_never_ever_use_directly; 52*a0483764SConrad Meyer } BMK_runOutcome_t; 53*a0483764SConrad Meyer 54*a0483764SConrad Meyer 55*a0483764SConrad Meyer /* prototypes for benchmarked functions */ 56*a0483764SConrad Meyer typedef size_t (*BMK_benchFn_t)(const void* src, size_t srcSize, void* dst, size_t dstCapacity, void* customPayload); 57*a0483764SConrad Meyer typedef size_t (*BMK_initFn_t)(void* initPayload); 58*a0483764SConrad Meyer typedef unsigned (*BMK_errorFn_t)(size_t); 59*a0483764SConrad Meyer 60*a0483764SConrad Meyer 61*a0483764SConrad Meyer /* BMK_benchFunction() parameters are provided through following structure. 62*a0483764SConrad Meyer * This is preferable for readability, 63*a0483764SConrad Meyer * as the number of parameters required is pretty large. 64*a0483764SConrad Meyer * No initializer is provided, because it doesn't make sense to provide some "default" : 65*a0483764SConrad Meyer * all parameters should be specified by the caller */ 66*a0483764SConrad Meyer typedef struct { 67*a0483764SConrad Meyer BMK_benchFn_t benchFn; /* the function to benchmark, over the set of blocks */ 68*a0483764SConrad Meyer void* benchPayload; /* pass custom parameters to benchFn : 69*a0483764SConrad Meyer * (*benchFn)(srcBuffers[i], srcSizes[i], dstBuffers[i], dstCapacities[i], benchPayload) */ 70*a0483764SConrad Meyer BMK_initFn_t initFn; /* (*initFn)(initPayload) is run once per run, at the beginning. */ 71*a0483764SConrad Meyer void* initPayload; /* Both arguments can be NULL, in which case nothing is run. */ 72*a0483764SConrad Meyer BMK_errorFn_t errorFn; /* errorFn will check each return value of benchFn over each block, to determine if it failed or not. 73*a0483764SConrad Meyer * errorFn can be NULL, in which case no check is performed. 74*a0483764SConrad Meyer * errorFn must return 0 when benchFn was successful, and >= 1 if it detects an error. 75*a0483764SConrad Meyer * Execution is stopped as soon as an error is detected. 76*a0483764SConrad Meyer * the triggering return value can be retrieved using BMK_extract_errorResult(). */ 77*a0483764SConrad Meyer size_t blockCount; /* number of blocks to operate benchFn on. 78*a0483764SConrad Meyer * It's also the size of all array parameters : 79*a0483764SConrad Meyer * srcBuffers, srcSizes, dstBuffers, dstCapacities, blockResults */ 80*a0483764SConrad Meyer const void *const * srcBuffers; /* array of buffers to be operated on by benchFn */ 81*a0483764SConrad Meyer const size_t* srcSizes; /* array of the sizes of srcBuffers buffers */ 82*a0483764SConrad Meyer void *const * dstBuffers;/* array of buffers to be written into by benchFn */ 83*a0483764SConrad Meyer const size_t* dstCapacities; /* array of the capacities of dstBuffers buffers */ 84*a0483764SConrad Meyer size_t* blockResults; /* Optional: store the return value of benchFn for each block. Use NULL if this result is not requested. */ 85*a0483764SConrad Meyer } BMK_benchParams_t; 86*a0483764SConrad Meyer 87*a0483764SConrad Meyer 88*a0483764SConrad Meyer /* BMK_benchFunction() : 89*a0483764SConrad Meyer * This function benchmarks benchFn and initFn, providing a result. 90*a0483764SConrad Meyer * 91*a0483764SConrad Meyer * params : see description of BMK_benchParams_t above. 92*a0483764SConrad Meyer * nbLoops: defines number of times benchFn is run over the full set of blocks. 93*a0483764SConrad Meyer * Minimum value is 1. A 0 is interpreted as a 1. 94*a0483764SConrad Meyer * 95*a0483764SConrad Meyer * @return: can express either an error or a successful result. 96*a0483764SConrad Meyer * Use BMK_isSuccessful_runOutcome() to check if benchmark was successful. 97*a0483764SConrad Meyer * If yes, extract the result with BMK_extract_runTime(), 98*a0483764SConrad Meyer * it will contain : 99*a0483764SConrad Meyer * .sumOfReturn : the sum of all return values of benchFn through all of blocks 100*a0483764SConrad Meyer * .nanoSecPerRun : time per run of benchFn + (time for initFn / nbLoops) 101*a0483764SConrad Meyer * .sumOfReturn is generally intended for functions which return a # of bytes written into dstBuffer, 102*a0483764SConrad Meyer * in which case, this value will be the total amount of bytes written into dstBuffer. 103*a0483764SConrad Meyer * 104*a0483764SConrad Meyer * blockResults : when provided (!= NULL), and when benchmark is successful, 105*a0483764SConrad Meyer * params.blockResults contains all return values of `benchFn` over all blocks. 106*a0483764SConrad Meyer * when provided (!= NULL), and when benchmark failed, 107*a0483764SConrad Meyer * params.blockResults contains return values of `benchFn` over all blocks preceding and including the failed block. 108*a0483764SConrad Meyer */ 109*a0483764SConrad Meyer BMK_runOutcome_t BMK_benchFunction(BMK_benchParams_t params, unsigned nbLoops); 110*a0483764SConrad Meyer 111*a0483764SConrad Meyer 112*a0483764SConrad Meyer 113*a0483764SConrad Meyer /* check first if the benchmark was successful or not */ 114*a0483764SConrad Meyer int BMK_isSuccessful_runOutcome(BMK_runOutcome_t outcome); 115*a0483764SConrad Meyer 116*a0483764SConrad Meyer /* If the benchmark was successful, extract the result. 117*a0483764SConrad Meyer * note : this function will abort() program execution if benchmark failed ! 118*a0483764SConrad Meyer * always check if benchmark was successful first ! 119*a0483764SConrad Meyer */ 120*a0483764SConrad Meyer BMK_runTime_t BMK_extract_runTime(BMK_runOutcome_t outcome); 121*a0483764SConrad Meyer 122*a0483764SConrad Meyer /* when benchmark failed, it means one invocation of `benchFn` failed. 123*a0483764SConrad Meyer * The failure was detected by `errorFn`, operating on return values of `benchFn`. 124*a0483764SConrad Meyer * Returns the faulty return value. 125*a0483764SConrad Meyer * note : this function will abort() program execution if benchmark did not failed. 126*a0483764SConrad Meyer * always check if benchmark failed first ! 127*a0483764SConrad Meyer */ 128*a0483764SConrad Meyer size_t BMK_extract_errorResult(BMK_runOutcome_t outcome); 129*a0483764SConrad Meyer 130*a0483764SConrad Meyer 131*a0483764SConrad Meyer 132*a0483764SConrad Meyer /* ==== Benchmark any function, returning intermediate results ==== */ 133*a0483764SConrad Meyer 134*a0483764SConrad Meyer /* state information tracking benchmark session */ 135*a0483764SConrad Meyer typedef struct BMK_timedFnState_s BMK_timedFnState_t; 136*a0483764SConrad Meyer 137*a0483764SConrad Meyer /* BMK_benchTimedFn() : 138*a0483764SConrad Meyer * Similar to BMK_benchFunction(), most arguments being identical. 139*a0483764SConrad Meyer * Automatically determines `nbLoops` so that each result is regularly produced at interval of about run_ms. 140*a0483764SConrad Meyer * Note : minimum `nbLoops` is 1, therefore a run may last more than run_ms, and possibly even more than total_ms. 141*a0483764SConrad Meyer * Usage - initialize timedFnState, select benchmark duration (total_ms) and each measurement duration (run_ms) 142*a0483764SConrad Meyer * call BMK_benchTimedFn() repetitively, each measurement is supposed to last about run_ms 143*a0483764SConrad Meyer * Check if total time budget is spent or exceeded, using BMK_isCompleted_TimedFn() 144*a0483764SConrad Meyer */ 145*a0483764SConrad Meyer BMK_runOutcome_t BMK_benchTimedFn(BMK_timedFnState_t* timedFnState, 146*a0483764SConrad Meyer BMK_benchParams_t params); 147*a0483764SConrad Meyer 148*a0483764SConrad Meyer /* Tells if duration of all benchmark runs has exceeded total_ms 149*a0483764SConrad Meyer */ 150*a0483764SConrad Meyer int BMK_isCompleted_TimedFn(const BMK_timedFnState_t* timedFnState); 151*a0483764SConrad Meyer 152*a0483764SConrad Meyer /* BMK_createTimedFnState() and BMK_resetTimedFnState() : 153*a0483764SConrad Meyer * Create/Set BMK_timedFnState_t for next benchmark session, 154*a0483764SConrad Meyer * which shall last a minimum of total_ms milliseconds, 155*a0483764SConrad Meyer * producing intermediate results, paced at interval of (approximately) run_ms. 156*a0483764SConrad Meyer */ 157*a0483764SConrad Meyer BMK_timedFnState_t* BMK_createTimedFnState(unsigned total_ms, unsigned run_ms); 158*a0483764SConrad Meyer void BMK_resetTimedFnState(BMK_timedFnState_t* timedFnState, unsigned total_ms, unsigned run_ms); 159*a0483764SConrad Meyer void BMK_freeTimedFnState(BMK_timedFnState_t* state); 160*a0483764SConrad Meyer 161*a0483764SConrad Meyer 162*a0483764SConrad Meyer 163*a0483764SConrad Meyer #endif /* BENCH_FN_H_23876 */ 164*a0483764SConrad Meyer 165*a0483764SConrad Meyer #if defined (__cplusplus) 166*a0483764SConrad Meyer } 167*a0483764SConrad Meyer #endif 168