From 95fc3bf314e73142a0e1e6fdb524623e27739e8a Mon Sep 17 00:00:00 2001 From: Erik de Castro Lopo Date: Tue, 1 Sep 2015 03:38:43 +1000 Subject: [PATCH] Add first micro-benchmark --- .gitignore | 1 + Makefile.am | 2 +- configure.ac | 1 + microbench/Makefile.am | 37 ++++++++ microbench/benchmark_residual.c | 151 ++++++++++++++++++++++++++++++++ microbench/util.c | 102 +++++++++++++++++++++ microbench/util.h | 43 +++++++++ 7 files changed, 336 insertions(+), 1 deletion(-) create mode 100644 microbench/Makefile.am create mode 100644 microbench/benchmark_residual.c create mode 100644 microbench/util.c create mode 100644 microbench/util.h diff --git a/.gitignore b/.gitignore index 52cd0b61..6e9ffce1 100644 --- a/.gitignore +++ b/.gitignore @@ -74,3 +74,4 @@ test/metaflac.flac test/picture.diff test/picture.log .dirstamp +microbench/benchmark_residual diff --git a/Makefile.am b/Makefile.am index 4b81e6e5..f9c09604 100644 --- a/Makefile.am +++ b/Makefile.am @@ -31,7 +31,7 @@ ACLOCAL_AMFLAGS = -I m4 -SUBDIRS = doc include m4 man src examples test build objs +SUBDIRS = doc include m4 man src examples test build objs microbench EXTRA_DIST = \ COPYING.FDL \ diff --git a/configure.ac b/configure.ac index 9bfe7f58..46cb916b 100644 --- a/configure.ac +++ b/configure.ac @@ -492,6 +492,7 @@ AC_CONFIG_FILES([ \ objs/release/Makefile \ objs/release/bin/Makefile \ objs/release/lib/Makefile \ + microbench/Makefile ]) AC_OUTPUT diff --git a/microbench/Makefile.am b/microbench/Makefile.am new file mode 100644 index 00000000..4ed70f6e --- /dev/null +++ b/microbench/Makefile.am @@ -0,0 +1,37 @@ +# FLAC - Free Lossless Audio Codec +# Copyright (C) 2015 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. + + +AM_CPPFLAGS = -I$(top_srcdir)/include -I$(top_srcdir)/src/libFLAC/include + +noinst_PROGRAMS = benchmark_residual + + +benchmark_residual_SOURCES = benchmark_residual.c util.c diff --git a/microbench/benchmark_residual.c b/microbench/benchmark_residual.c new file mode 100644 index 00000000..228e1688 --- /dev/null +++ b/microbench/benchmark_residual.c @@ -0,0 +1,151 @@ +/* libFLAC - Free Lossless Audio Codec library + * Copyright (C) 2000-2009 Josh Coalson + * Copyright (C) 2011-2014 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 +#endif + +#include +#include +#include +#include "FLAC/ordinals.h" +#include "share/compat.h" +#include "private/bitmath.h" +#include "private/fixed.h" +#include "private/macros.h" +#include "FLAC/assert.h" + +#include "util.h" + +static void FLAC__fixed_compute_residual_shift(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) +{ + const int idata_len = (int) data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - (data[i-1] << 1) + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - (((data[i-1]-data[i-2])<<1) + (data[i-1]-data[i-2])) - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - ((data[i-1]+data[i-3])<<2) + ((data[i-2]<<2) + (data[i-2]<<1)) + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +static void FLAC__fixed_compute_residual_mult(const FLAC__int32 data[], unsigned data_len, unsigned order, FLAC__int32 residual[]) +{ + const int idata_len = (int)data_len; + int i; + + switch(order) { + case 0: + FLAC__ASSERT(sizeof(residual[0]) == sizeof(data[0])); + memcpy(residual, data, sizeof(residual[0])*data_len); + break; + case 1: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - data[i-1]; + break; + case 2: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 2*data[i-1] + data[i-2]; + break; + case 3: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 3*data[i-1] + 3*data[i-2] - data[i-3]; + break; + case 4: + for(i = 0; i < idata_len; i++) + residual[i] = data[i] - 4*data[i-1] + 6*data[i-2] - 4*data[i-3] + data[i-4]; + break; + default: + FLAC__ASSERT(0); + } +} + +static FLAC__int32 data [200000] ; +static FLAC__int32 residual [200000] ; + +static unsigned bench_order = 0 ; + +static void +bench_shift (void) +{ FLAC__fixed_compute_residual_shift (data, ARRAY_LEN (data), bench_order, residual) ; +} + +static void +bench_mult (void) +{ FLAC__fixed_compute_residual_mult (data, ARRAY_LEN (data), bench_order, residual) ; +} + +int +main (void) +{ bench_stats stats ; + + puts ("") ; + + for (bench_order = 2 ; bench_order <= 4 ; bench_order ++) { + memset (&stats, 0, sizeof (stats)) ; + stats.testfunc = bench_shift ; + stats.run_count = 100 ; + stats.loop_count = 10 ; + + benchmark_stats (&stats) ; + printf ("shift order %u : %f %f %f %f\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ; + + memset (&stats, 0, sizeof (stats)) ; + stats.testfunc = bench_mult ; + stats.run_count = 100 ; + stats.loop_count = 10 ; + + benchmark_stats (&stats) ; + printf ("mult order %u : %f %f %f %f\n\n", bench_order, stats.min_time, stats.median_time, stats.mean_time, stats.max_time) ; + } + + return 0 ; +} diff --git a/microbench/util.c b/microbench/util.c new file mode 100644 index 00000000..b54305ce --- /dev/null +++ b/microbench/util.c @@ -0,0 +1,102 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2015 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. + */ + +#define _GNU_SOURCE + +#include +#include +#include + +#include "util.h" + +static double +timespec_diff (const struct timespec * start, const struct timespec * end) +{ struct timespec difftime; + + if (end->tv_nsec - start->tv_nsec < 0) + { difftime.tv_sec = end->tv_sec - start->tv_sec - 1 ; + difftime.tv_nsec = 1000000000 + end->tv_nsec - start->tv_nsec ; + } + else + { difftime.tv_sec = end->tv_sec - start->tv_sec ; + difftime.tv_nsec = end->tv_nsec-start->tv_nsec ; + } ; + + return difftime.tv_sec + 1e-9 * difftime.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 */ + +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 */ diff --git a/microbench/util.h b/microbench/util.h new file mode 100644 index 00000000..014a690e --- /dev/null +++ b/microbench/util.h @@ -0,0 +1,43 @@ +/* FLAC - Free Lossless Audio Codec + * Copyright (C) 2015 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. + */ + +#define ARRAY_LEN(x) ((sizeof (x) / sizeof (x [0]))) + +typedef struct bench_stats +{ void (*testfunc) (void) ; + unsigned run_count ; + unsigned loop_count ; + double min_time, mean_time, median_time, max_time ; +} bench_stats ; + +double benchmark_function (void (*testfunc) (void), unsigned count) ; + +void benchmark_stats (bench_stats * stats) ;