Add support for microbenchmarks.
authorSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 15 Nov 2017 19:30:58 +0000 (20:30 +0100)
committerSteinar H. Gunderson <sgunderson@bigfoot.com>
Wed, 15 Nov 2017 19:43:05 +0000 (20:43 +0100)
This depends on Google's microbenchmark library (latest git version,
at least as soon as they pull in the pkg-config file), but it is
not mandatory.

Note that this makes Movit depend on C++11.

Makefile.in
README
configure.ac
deinterlace_effect_test.cpp
gtest_sdl_main.cpp
test_util.cpp
test_util.h
version.h

index 02d40a7..80dc0e0 100644 (file)
@@ -18,17 +18,21 @@ datadir = @datadir@
 top_builddir = @top_builddir@
 with_demo_app = @with_demo_app@
 with_SDL2 = @with_SDL2@
+with_benchmark = @with_benchmark@
 with_coverage = @with_coverage@
 
 CC=@CC@
 CXX=@CXX@
-CXXFLAGS=-Wall @CXXFLAGS@ -fvisibility-inlines-hidden -I$(GTEST_DIR)/include @SDL2_CFLAGS@ @SDL_CFLAGS@ @Eigen3_CFLAGS@ @epoxy_CFLAGS@ @FFTW3_CFLAGS@
+CXXFLAGS=-Wall @CXXFLAGS@ -fvisibility-inlines-hidden -I$(GTEST_DIR)/include @SDL2_CFLAGS@ @SDL_CFLAGS@ @Eigen3_CFLAGS@ @epoxy_CFLAGS@ @FFTW3_CFLAGS@ @benchmark_CFLAGS@
 ifeq ($(with_SDL2),yes)
 CXXFLAGS += -DHAVE_SDL2
 endif
+ifeq ($(with_benchmark),yes)
+CXXFLAGS += -DHAVE_BENCHMARK
+endif
 LDFLAGS=@LDFLAGS@
 LDLIBS=@epoxy_LIBS@ @FFTW3_LIBS@ -lpthread
-TEST_LDLIBS=@epoxy_LIBS@ @SDL2_LIBS@ @SDL_LIBS@ -lpthread
+TEST_LDLIBS=@epoxy_LIBS@ @SDL2_LIBS@ @SDL_LIBS@ @benchmark_LIBS@ -lpthread
 DEMO_LDLIBS=@SDL2_image_LIBS@ @SDL_image_LIBS@ -lrt -lpthread @libpng_LIBS@ @FFTW3_LIBS@
 SHELL=@SHELL@
 LIBTOOL=@LIBTOOL@ --tag=CXX
diff --git a/README b/README
index 3c72aba..06afdde 100644 (file)
--- a/README
+++ b/README
@@ -17,13 +17,15 @@ TL;DR, please give me download link and system demands
 
 OK, you need
 
-* A C++98 compiler. GCC will do. (I haven't tried Windows, but it
+* A C++11 compiler. GCC will do. (I haven't tried Windows, but it
   works fine on Linux and OS X, and Movit is not very POSIX-bound.)
 * GNU Make.
 * A GPU capable of running OpenGL 3.0 or newer. GLES3 (for mobile devices)
   will also work.
 * The [Eigen 3], [FFTW3] and [Google Test] libraries. (The library itself
   does not depend on the latter, but you probably want to run the unit tests.)
+  If you also have the Google microbenchmark library, you can get some
+  benchmarks as well.
 * The [epoxy] library, for dealing with OpenGL extensions on various
   platforms.
 
index 188d1fe..427e67d 100644 (file)
@@ -3,6 +3,8 @@ AC_INIT(movit, git)
 LT_INIT
 PKG_PROG_PKG_CONFIG
 
+CXXFLAGS="$CXXFLAGS -std=gnu++11"
+
 AC_CONFIG_SRCDIR(effect.cpp)
 AC_CONFIG_AUX_DIR(.)
 
@@ -28,7 +30,11 @@ else
 fi
 PKG_CHECK_MODULES([libpng], [libpng], [], [with_demo_app=no; AC_MSG_WARN([libpng not found, demo program will not be built])])
 
+# This is only needed for microbenchmarks, so optional.
+PKG_CHECK_MODULES([benchmark], [benchmark], [with_benchmark=yes], [with_benchmark=no; AC_MSG_WARN([Google microbenchmark framework not found, microbenchmarks will not be built])])
+
 AC_SUBST([with_demo_app])
+AC_SUBST([with_benchmark])
 AC_SUBST([with_SDL2])
 
 with_coverage=no
index 24e11a2..d2045eb 100644 (file)
@@ -1,5 +1,8 @@
 // Unit tests for DeinterlaceEffect.
 
+#ifdef HAVE_BENCHMARK
+#include <benchmark/benchmark.h>
+#endif
 #include <epoxy/gl.h>
 
 #include <algorithm>
@@ -193,4 +196,47 @@ TEST(DeinterlaceTest, FlickerBox) {
        }
 }
 
+#ifdef HAVE_BENCHMARK
+void BM_DeinterlaceEffect_Gray(benchmark::State &state)
+{
+       unsigned width = state.range(0), height = state.range(1);
+       unsigned field_height = height / 2;
+
+       float *field1 = new float[width * field_height];
+       float *field2 = new float[width * field_height];
+       float *field3 = new float[width * field_height];
+       float *field4 = new float[width * field_height];
+       float *field5 = new float[width * field_height];
+       float *out_data = new float[width * height];
+
+       for (unsigned i = 0; i < width * field_height; ++i) {
+               field1[i] = rand();
+               field2[i] = rand();
+               field3[i] = rand();
+               field4[i] = rand();
+               field5[i] = rand();
+       }
+
+       EffectChainTester tester(NULL, width, height);
+       Effect *input1 = tester.add_input(field1, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
+       Effect *input2 = tester.add_input(field2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
+       Effect *input3 = tester.add_input(field3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
+       Effect *input4 = tester.add_input(field4, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
+       Effect *input5 = tester.add_input(field5, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR, width, field_height);
+       Effect *deinterlace_effect = tester.get_chain()->add_effect(new DeinterlaceEffect(), input1, input2, input3, input4, input5);
+
+       ASSERT_TRUE(deinterlace_effect->set_int("current_field_position", 0));
+
+       tester.benchmark(state, out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR, OUTPUT_ALPHA_FORMAT_PREMULTIPLIED);
+
+       delete[] field1;
+       delete[] field2;
+       delete[] field3;
+       delete[] field4;
+       delete[] field5;
+       delete[] out_data;
+}
+BENCHMARK(BM_DeinterlaceEffect_Gray)->Args({720, 576})->Args({1280, 720})->Args({1920, 1080})->UseRealTime()->Unit(benchmark::kMicrosecond);
+#endif
+
 }  // namespace movit
index 90a929e..70fed13 100644 (file)
@@ -9,6 +9,9 @@
 #include <SDL/SDL_error.h>
 #include <SDL/SDL_video.h>
 #endif
+#ifdef HAVE_BENCHMARK
+#include <benchmark/benchmark.h>
+#endif
 #include <stdio.h>
 #include <stdlib.h>
 
@@ -50,8 +53,22 @@ int main(int argc, char **argv) {
        SDL_WM_SetCaption("OpenGL window for unit test", NULL);
 #endif
 
-       testing::InitGoogleTest(&argc, argv);
-       int err = RUN_ALL_TESTS();
+       int err;
+       if (argc >= 2 && strcmp(argv[1], "--benchmark") == 0) {
+#ifdef HAVE_BENCHMARK
+               --argc;
+               ::benchmark::Initialize(&argc, argv + 1);
+               if (::benchmark::ReportUnrecognizedArguments(argc, argv)) return 1;
+               ::benchmark::RunSpecifiedBenchmarks();
+               err = 0;
+#else
+               fprintf(stderr, "No support for microbenchmarks compiled in.\n");
+               err = 1;
+#endif
+       } else {
+               testing::InitGoogleTest(&argc, argv);
+               err = RUN_ALL_TESTS();
+       }
        SDL_Quit();
-       exit(err);
+       return err;
 }
index 4543ee3..65dbe8a 100644 (file)
@@ -153,8 +153,66 @@ void EffectChainTester::run_10_10_10_2(uint32_t *out_data, GLenum format, Colors
        internal_run<uint32_t>(out_data, NULL, NULL, NULL, GL_UNSIGNED_INT_2_10_10_10_REV, format, color_space, gamma_curve, alpha_format);
 }
 
+#ifdef HAVE_BENCHMARK
+
+void EffectChainTester::benchmark(benchmark::State &state, float *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<float>(out_data, NULL, NULL, NULL, GL_FLOAT, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, float *out_data, float *out_data2, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<float>(out_data, out_data2, NULL, NULL, GL_FLOAT, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, float *out_data, float *out_data2, float *out_data3, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<float>(out_data, out_data2, out_data3, NULL, GL_FLOAT, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, float *out_data, float *out_data2, float *out_data3, float *out_data4, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run(out_data, out_data2, out_data3, out_data4, GL_FLOAT, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, unsigned char *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<unsigned char>(out_data, NULL, NULL, NULL, GL_UNSIGNED_BYTE, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<unsigned char>(out_data, out_data2, NULL, NULL, GL_UNSIGNED_BYTE, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, unsigned char *out_data3, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<unsigned char>(out_data, out_data2, out_data3, NULL, GL_UNSIGNED_BYTE, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, unsigned char *out_data3, unsigned char *out_data4, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run(out_data, out_data2, out_data3, out_data4, GL_UNSIGNED_BYTE, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark(benchmark::State &state, uint16_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<uint16_t>(out_data, NULL, NULL, NULL, GL_UNSIGNED_SHORT, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+void EffectChainTester::benchmark_10_10_10_2(benchmark::State &state, uint32_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+{
+       internal_run<uint32_t>(out_data, NULL, NULL, NULL, GL_UNSIGNED_INT_2_10_10_10_REV, format, color_space, gamma_curve, alpha_format, &state);
+}
+
+#endif
+
 template<class T>
-void EffectChainTester::internal_run(T *out_data, T *out_data2, T *out_data3, T *out_data4, GLenum internal_format, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format)
+void EffectChainTester::internal_run(T *out_data, T *out_data2, T *out_data3, T *out_data4, GLenum internal_format, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format
+#ifdef HAVE_BENCHMARK
+, benchmark::State *benchmark_state
+#endif
+)
 {
        if (!finalized) {
                finalize_chain(color_space, gamma_curve, alpha_format);
@@ -215,6 +273,22 @@ void EffectChainTester::internal_run(T *out_data, T *out_data2, T *out_data3, T
 
        chain.render_to_fbo(fbo, width, height);
 
+#ifdef HAVE_BENCHMARK
+       // If running benchmarks: Now we've warmed up everything, so let's run the
+       // actual benchmark loop.
+       if (benchmark_state != nullptr) {
+               glFinish();
+               size_t iters = benchmark_state->max_iterations;
+               for (auto _ : *benchmark_state) {
+                       chain.render_to_fbo(fbo, width, height);
+                       if (--iters == 0) {
+                               glFinish();
+                       }
+               }
+               benchmark_state->SetItemsProcessed(benchmark_state->iterations() * width * height);
+       }
+#endif
+
        T *data[4] = { out_data, out_data2, out_data3, out_data4 };
 
        glBindFramebuffer(GL_FRAMEBUFFER, fbo);
index 2f76dea..b619aed 100644 (file)
@@ -2,6 +2,9 @@
 #define _MOVIT_TEST_UTIL_H 1
 
 #include <epoxy/gl.h>
+#ifdef HAVE_BENCHMARK
+#include <benchmark/benchmark.h>
+#endif
 #include "effect_chain.h"
 #include "image_format.h"
 
@@ -21,6 +24,7 @@ public:
        EffectChain *get_chain() { return &chain; }
        Input *add_input(const float *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width = -1, int input_height = -1);
        Input *add_input(const unsigned char *data, MovitPixelFormat pixel_format, Colorspace color_space, GammaCurve gamma_curve, int input_width = -1, int input_height = -1);
+
        void run(float *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        void run(float *out_data, float *out_data2, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        void run(float *out_data, float *out_data2, float *out_data3, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
@@ -31,6 +35,20 @@ public:
        void run(unsigned char *out_data, unsigned char *out_data2, unsigned char *out_data3, unsigned char *out_data4, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        void run(uint16_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
        void run_10_10_10_2(uint32_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+
+#ifdef HAVE_BENCHMARK
+       void benchmark(benchmark::State &state, float *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, float *out_data, float *out_data2, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, float *out_data, float *out_data2, float *out_data3, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, float *out_data, float *out_data2, float *out_data3, float *out_data4, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, unsigned char *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, unsigned char *out_data3, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, unsigned char *out_data, unsigned char *out_data2, unsigned char *out_data3, unsigned char *out_data4, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark(benchmark::State &state, uint16_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void benchmark_10_10_10_2(benchmark::State &state, uint32_t *out_data, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+#endif
+
        void add_output(const ImageFormat &format, OutputAlphaFormat alpha_format);
        void add_ycbcr_output(const ImageFormat &format, OutputAlphaFormat alpha_format, const YCbCrFormat &ycbcr_format, YCbCrOutputSplitting output_splitting = YCBCR_OUTPUT_INTERLEAVED, GLenum output_type = GL_UNSIGNED_BYTE);
 
@@ -38,7 +56,11 @@ private:
        void finalize_chain(Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format);
 
        template<class T>
-       void internal_run(T *out_data, T *out_data2, T *out_data3, T *out_data4, GLenum internal_format, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED);
+       void internal_run(T *out_data, T *out_data2, T *out_data3, T *out_data4, GLenum internal_format, GLenum format, Colorspace color_space, GammaCurve gamma_curve, OutputAlphaFormat alpha_format = OUTPUT_ALPHA_FORMAT_POSTMULTIPLIED
+#ifdef HAVE_BENCHMARK
+               , benchmark::State *state = NULL
+#endif
+);
 
        EffectChain chain;
        unsigned width, height;
index 64469bd..e73f188 100644 (file)
--- a/version.h
+++ b/version.h
@@ -5,6 +5,6 @@
 // changes, even within git versions. There is no specific version
 // documentation outside the regular changelogs, though.
 
-#define MOVIT_VERSION 32
+#define MOVIT_VERSION 33
 
 #endif // !defined(_MOVIT_VERSION_H)