From 0ed2c7fe3876a49d1565e3425e5a491206ffe32d Mon Sep 17 00:00:00 2001 From: "Steinar H. Gunderson" Date: Wed, 15 Nov 2017 20:30:58 +0100 Subject: [PATCH] Add support for microbenchmarks. 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 | 8 +++- README | 4 +- configure.ac | 6 +++ deinterlace_effect_test.cpp | 46 ++++++++++++++++++++++ gtest_sdl_main.cpp | 23 +++++++++-- test_util.cpp | 76 ++++++++++++++++++++++++++++++++++++- test_util.h | 24 +++++++++++- version.h | 2 +- 8 files changed, 180 insertions(+), 9 deletions(-) diff --git a/Makefile.in b/Makefile.in index 02d40a7..80dc0e0 100644 --- a/Makefile.in +++ b/Makefile.in @@ -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 --- 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. diff --git a/configure.ac b/configure.ac index 188d1fe..427e67d 100644 --- a/configure.ac +++ b/configure.ac @@ -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 diff --git a/deinterlace_effect_test.cpp b/deinterlace_effect_test.cpp index 24e11a2..d2045eb 100644 --- a/deinterlace_effect_test.cpp +++ b/deinterlace_effect_test.cpp @@ -1,5 +1,8 @@ // Unit tests for DeinterlaceEffect. +#ifdef HAVE_BENCHMARK +#include +#endif #include #include @@ -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 diff --git a/gtest_sdl_main.cpp b/gtest_sdl_main.cpp index 90a929e..70fed13 100644 --- a/gtest_sdl_main.cpp +++ b/gtest_sdl_main.cpp @@ -9,6 +9,9 @@ #include #include #endif +#ifdef HAVE_BENCHMARK +#include +#endif #include #include @@ -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; } diff --git a/test_util.cpp b/test_util.cpp index 4543ee3..65dbe8a 100644 --- a/test_util.cpp +++ b/test_util.cpp @@ -153,8 +153,66 @@ void EffectChainTester::run_10_10_10_2(uint32_t *out_data, GLenum format, Colors internal_run(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(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(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(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(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(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(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(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(out_data, NULL, NULL, NULL, GL_UNSIGNED_INT_2_10_10_10_REV, format, color_space, gamma_curve, alpha_format, &state); +} + +#endif + template -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); diff --git a/test_util.h b/test_util.h index 2f76dea..b619aed 100644 --- a/test_util.h +++ b/test_util.h @@ -2,6 +2,9 @@ #define _MOVIT_TEST_UTIL_H 1 #include +#ifdef HAVE_BENCHMARK +#include +#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 - 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; diff --git a/version.h b/version.h index 64469bd..e73f188 100644 --- 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) -- 2.39.2