| /* FLAC - Free Lossless Audio Codec | |
| * Copyright (C) 2015-2022 Xiph.Org Foundation | |
| * | |
| * Redistribution and use in source and binary forms, with or without | |
| * modification, are permitted provided that the following conditions | |
| * are met: | |
| * | |
| * - Redistributions of source code must retain the above copyright | |
| * notice, this list of conditions and the following disclaimer. | |
| * | |
| * - Redistributions in binary form must reproduce the above copyright | |
| * notice, this list of conditions and the following disclaimer in the | |
| * documentation and/or other materials provided with the distribution. | |
| * | |
| * - Neither the name of the Xiph.org Foundation nor the names of its | |
| * contributors may be used to endorse or promote products derived from | |
| * this software without specific prior written permission. | |
| * | |
| * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | |
| * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | |
| * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR | |
| * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR | |
| * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | |
| * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | |
| * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | |
| * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | |
| * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | |
| * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | |
| * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | |
| */ | |
| #ifdef HAVE_CONFIG_H | |
| # include <config.h> | |
| #endif | |
| #include <stdlib.h> | |
| #include "util.h" | |
| #if defined _WIN32 | |
| #include <windows.h> | |
| static double | |
| counter_diff (const LARGE_INTEGER * start, const LARGE_INTEGER * end) | |
| { | |
| LARGE_INTEGER diff, freq; | |
| QueryPerformanceFrequency(&freq); | |
| diff.QuadPart = end->QuadPart - start->QuadPart; | |
| return (double)diff.QuadPart/(double)freq.QuadPart; | |
| } | |
| double | |
| benchmark_function (void (*testfunc) (void), unsigned count) | |
| { | |
| LARGE_INTEGER start, end; | |
| unsigned k; | |
| QueryPerformanceCounter (&start) ; | |
| for (k = 0 ; k < count ; k++) | |
| testfunc(); | |
| QueryPerformanceCounter (&end) ; | |
| return counter_diff (&start, &end) / count ; | |
| } /* benchmark_function */ | |
| #elif defined FLAC__SYS_DARWIN | |
| #include <mach/mach_time.h> | |
| static double | |
| counter_diff (const uint64_t * start, const uint64_t * end) | |
| { | |
| mach_timebase_info_data_t t_info; | |
| mach_timebase_info(&t_info); | |
| uint64_t duration = *end - *start; | |
| return duration * ((double)t_info.numer/(double)t_info.denom); | |
| } | |
| double | |
| benchmark_function (void (*testfunc) (void), unsigned count) | |
| { | |
| uint64_t start, end; | |
| unsigned k; | |
| start = mach_absolute_time(); | |
| for (k = 0 ; k < count ; k++) | |
| testfunc(); | |
| end = mach_absolute_time(); | |
| return counter_diff (&start, &end) / count ; | |
| } /* benchmark_function */ | |
| #elif defined HAVE_CLOCK_GETTIME | |
| #include <time.h> | |
| #include <sys/time.h> | |
| static double | |
| timespec_diff (const struct timespec * start, const struct timespec * end) | |
| { struct timespec diff; | |
| if (end->tv_nsec - start->tv_nsec < 0) | |
| { diff.tv_sec = end->tv_sec - start->tv_sec - 1 ; | |
| diff.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec ; | |
| } | |
| else | |
| { diff.tv_sec = end->tv_sec - start->tv_sec ; | |
| diff.tv_nsec = end->tv_nsec-start->tv_nsec ; | |
| } ; | |
| return diff.tv_sec + 1e-9 * diff.tv_nsec ; | |
| } | |
| double | |
| benchmark_function (void (*testfunc) (void), unsigned count) | |
| { struct timespec start, end; | |
| unsigned k ; | |
| clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &start) ; | |
| for (k = 0 ; k < count ; k++) | |
| testfunc () ; | |
| clock_gettime (CLOCK_PROCESS_CPUTIME_ID, &end) ; | |
| return timespec_diff (&start, &end) / count ; | |
| } /* benchmark_function */ | |
| #else | |
| #include <time.h> | |
| #include <sys/time.h> | |
| static double | |
| timeval_diff (const struct timeval * start, const struct timeval * end) | |
| { struct timeval diff; | |
| if (end->tv_usec - start->tv_usec < 0) | |
| { diff.tv_sec = end->tv_sec - start->tv_sec - 1 ; | |
| diff.tv_usec = 1000000 + end->tv_usec - start->tv_usec ; | |
| } | |
| else | |
| { diff.tv_sec = end->tv_sec - start->tv_sec ; | |
| diff.tv_usec = end->tv_usec-start->tv_usec ; | |
| } ; | |
| return diff.tv_sec + 1e-6 * diff.tv_usec ; | |
| } | |
| double | |
| benchmark_function (void (*testfunc) (void), unsigned count) | |
| { struct timeval start, end; | |
| unsigned k ; | |
| gettimeofday(&start, NULL); | |
| for (k = 0 ; k < count ; k++) | |
| testfunc () ; | |
| gettimeofday(&end, NULL); | |
| return timeval_diff (&start, &end) / count ; | |
| } /* benchmark_function */ | |
| #endif | |
| static int | |
| double_cmp (const void * a, const void * b) | |
| { const double * pa = (double *) a ; | |
| const double * pb = (double *) b ; | |
| return pa [0] < pb [0] ; | |
| } /* double_cmp */ | |
| void | |
| benchmark_stats (bench_stats * stats) | |
| { double sum, times [stats->run_count] ; | |
| unsigned k ; | |
| for (k = 0 ; k < stats->run_count ; k++) | |
| times [k] = benchmark_function (stats->testfunc, stats->loop_count) ; | |
| qsort (times, stats->run_count, sizeof (times [0]), double_cmp) ; | |
| sum = 0.0 ; | |
| stats->min_time = stats->max_time = times [0] ; | |
| for (k = 0 ; k < stats->run_count ; k++) | |
| { stats->min_time = stats->min_time < times [k] ? stats->min_time : times [k] ; | |
| stats->max_time = stats->max_time > times [k] ? stats->max_time : times [k] ; | |
| sum += times [k] ; | |
| } | |
| stats->mean_time = sum / stats->run_count ; | |
| if (stats->run_count & 1) | |
| stats->median_time = times [(stats->run_count + 1) / 2] ; | |
| else | |
| stats->median_time = 0.5 * (times [stats->run_count / 2] + times [(stats->run_count / 2) + 1]) ; | |
| return ; | |
| } /* benchmark_stats */ |