Add first micro-benchmark
authorErik de Castro Lopo <erikd@mega-nerd.com>
Mon, 31 Aug 2015 17:38:43 +0000 (03:38 +1000)
committerErik de Castro Lopo <erikd@mega-nerd.com>
Mon, 31 Aug 2015 18:14:17 +0000 (04:14 +1000)
.gitignore
Makefile.am
configure.ac
microbench/Makefile.am [new file with mode: 0644]
microbench/benchmark_residual.c [new file with mode: 0644]
microbench/util.c [new file with mode: 0644]
microbench/util.h [new file with mode: 0644]

index 52cd0b6..6e9ffce 100644 (file)
@@ -74,3 +74,4 @@ test/metaflac.flac
 test/picture.diff
 test/picture.log
 .dirstamp
+microbench/benchmark_residual
index 4b81e6e..f9c0960 100644 (file)
@@ -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 \
index 9bfe7f5..46cb916 100644 (file)
@@ -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 (file)
index 0000000..4ed70f6
--- /dev/null
@@ -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 (file)
index 0000000..228e168
--- /dev/null
@@ -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 <config.h>
+#endif
+
+#include <stdio.h>
+#include <math.h>
+#include <string.h>
+#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 (file)
index 0000000..b54305c
--- /dev/null
@@ -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 <stdlib.h>
+#include <time.h>
+#include <sys/time.h>
+
+#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 (file)
index 0000000..014a690
--- /dev/null
@@ -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) ;