double measureKeyPerfGivenStack()

in unittest/lib/perf.cpp [617:694]


double measureKeyPerfGivenStack(    SIZE_T keySize,
                                    PerfKeyFn keyFn,
                                    PerfCleanFn cleanFn,
                                    int * pNRuns )
{
    PBYTE buf1 = g_perfBuffer + 0*PERF_BUFFER_SIZE + (g_rng.sizet( PERF_BUFFER_SIZE ) & ~0xf);
    PBYTE buf2 = g_perfBuffer + 2*PERF_BUFFER_SIZE + (g_rng.sizet( PERF_BUFFER_SIZE ) & ~0xf);
    PBYTE buf3 = g_perfBuffer + 4*PERF_BUFFER_SIZE + (g_rng.sizet( PERF_BUFFER_SIZE ) & ~0xf);
    //PBYTE buf4 = g_perfBuffer + 6*PERF_BUFFER_SIZE + (g_rng.sizet( PERF_BUFFER_SIZE ) & ~0xf);

    double   durations[ MEASUREMENTS_PER_RESULT ];

    int runs = *pNRuns;
    int i=0;
    ULONGLONG time0, time1, time2;

    time0 = GET_PERF_CLOCK();
    FIXED_TIME_LOOP();
    time1 = GET_PERF_CLOCK();
    double fixedBefore = (double) (time1 - time0);

    while( i < MEASUREMENTS_PER_RESULT )
    {
        time0 = GET_PERF_CLOCK();
        for( int j=0; j<runs; j++ )
        {
            (*keyFn)( buf1, buf2, buf3, keySize );
            (*cleanFn)( buf1, buf2, buf3 );
        }
        time1 = GET_PERF_CLOCK();
        FIXED_TIME_LOOP();
        time2 = GET_PERF_CLOCK();

        double fixedAfter = (double)  (time2 - time1);
        double measurementScaleFactor = ((double) FIXED_TIME_LOOP_EXPECTED_CYCLES * 2) / (fixedBefore + fixedAfter);
        double fixedRatio = fixedBefore > fixedAfter ? fixedBefore / fixedAfter : fixedAfter / fixedBefore;
        fixedBefore = fixedAfter; // now use this after measurement as the next before measurement

        if( g_perfClockScaling && fixedRatio > 1.01f )
        {
            // Something changed in timing between before and after, rerun this run
            continue;
        }

        ULONGLONG duration = time1 - time0;
        if( duration < g_minMeasurementClockTime )
        {
            //
            // The measurement was too short, restart & double the # runs we do.
            //
            i = 0;
            runs <<= 1;
            CHECK( runs <= MAX_RUNS_PER_MEASUREMENT, "Measurement too fast" );
            continue;
        }

        durations[i] = (double) duration;
        if( g_perfClockScaling )
        {
            durations[i] *= measurementScaleFactor;
        }
        ++i;
    }
    qsort( durations, MEASUREMENTS_PER_RESULT, sizeof( durations[0] ), compareDouble );

    //
    // We return the one-third percentile point to compensate for expected slow-downs.
    //
    double res = (double) durations[MEASUREMENTS_PER_RESULT/3];
    res -= g_perfMeasurementOverhead;
    res /= runs;
    res *= g_perfScaleFactor;
    res -= g_perfRunOverhead;

    *pNRuns = runs;

    return res;
}