From a0eeecba4a5e92164bad5f4e56cf25a85cbb7ca2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Vladim=C3=ADr=20Vondru=C5=A1?= Date: Sat, 14 Jan 2017 16:35:51 +0100 Subject: [PATCH] Added GPU time benchmarking to OpenGLTester. --- src/Magnum/OpenGLTester.cpp | 14 +++++ src/Magnum/OpenGLTester.h | 105 ++++++++++++++++++++++++++++++++++++ 2 files changed, 119 insertions(+) diff --git a/src/Magnum/OpenGLTester.cpp b/src/Magnum/OpenGLTester.cpp index 5a28fef49..8ead3b3c6 100644 --- a/src/Magnum/OpenGLTester.cpp +++ b/src/Magnum/OpenGLTester.cpp @@ -53,4 +53,18 @@ OpenGLTester::OpenGLTester(): TestSuite::Tester{TestSuite::Tester::TesterConfigu OpenGLTester::~OpenGLTester() = default; +void OpenGLTester::gpuTimeBenchmarkBegin() { + setBenchmarkName("GPU time"); + + /* Initialize, if not already */ + if(!_gpuTimeQuery.id()) _gpuTimeQuery = TimeQuery{TimeQuery::Target::TimeElapsed}; + + _gpuTimeQuery.begin(); +} + +std::uint64_t OpenGLTester::gpuTimeBenchmarkEnd() { + _gpuTimeQuery.end(); + return _gpuTimeQuery.result(); +} + } diff --git a/src/Magnum/OpenGLTester.h b/src/Magnum/OpenGLTester.h index 284d64602..538fa179c 100644 --- a/src/Magnum/OpenGLTester.h +++ b/src/Magnum/OpenGLTester.h @@ -32,6 +32,7 @@ #include #include "Magnum/Renderer.h" +#include "Magnum/TimeQuery.h" #ifdef MAGNUM_TARGET_HEADLESS #include "Magnum/Platform/WindowlessEglApplication.h" @@ -95,9 +96,56 @@ output. While it is possible, the tester class doesn't abort the test cases upon encountering a GL error -- this should be done explicitly with @ref MAGNUM_VERIFY_NO_ERROR() instead, as the debug output is not available on all platforms and not all GL errors are fatal. + +## GPU time benchmarks + +This class adds @ref BenchmarkType::GpuTime to the benchmark type enum, +allowing you to measure time spent on GPU as opposed to CPU or wall clock time. */ class OpenGLTester: public TestSuite::Tester { public: + /** + * @brief Benchmark type + * + * Extends @ref Corrade::TestSuite::Tester::BenchmarkType with GPU + * benchmark types. + * @see @ref addBenchmarks(), @ref addInstancedBenchmarks() + */ + enum class BenchmarkType { + /** + * See @ref Corrade::TestSuite::Tester::BenchmarkType::Default for + * details. + */ + Default = Int(Tester::BenchmarkType::Default), + + /** + * See @ref Corrade::TestSuite::Tester::BenchmarkType::WallTime for + * details. + */ + WallTime = Int(Tester::BenchmarkType::WallTime), + + /** + * See @ref Corrade::TestSuite::Tester::BenchmarkType::CpuTime for + * details. + */ + CpuTime = Int(Tester::BenchmarkType::CpuTime), + + /** + * See @ref Corrade::TestSuite::Tester::BenchmarkType::CpuCycles + * for details. + */ + CpuCycles = Int(Tester::BenchmarkType::CpuCycles), + + /** + * GPU time, measured using @ref TimeQuery::Target::TimeElapsed. + * Note that the result of the query is retrieved synchronously and + * thus may cause pipeline bubble. Increase number of iterations + * passed to @ref CORRADE_BENCHMARK() to amortize the measurement + * error. + */ + GpuTime = 32 + }; + /** * @brief Constructor * @@ -107,7 +155,62 @@ class OpenGLTester: public TestSuite::Tester { ~OpenGLTester(); + /** + * @brief Add benchmarks + * + * Extends @ref Corrade::TestSuite::Tester::addBenchmarks(std::initializer_list, std::size_t, BenchmarkType) with support + * for GPU benchmark types. + */ + template void addBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, BenchmarkType benchmarkType = BenchmarkType::Default) { + if(benchmarkType == BenchmarkType::GpuTime) + addCustomBenchmarks(benchmarks, batchCount, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, BenchmarkUnits::Nanoseconds); + else + Tester::addBenchmarks(benchmarks, batchCount, Tester::BenchmarkType(Int(benchmarkType))); + } + + /** + * @brief Add benchmarks with explicit setup and teardown functions + * + * Extends @ref Corrade::TestSuite::Tester::addBenchmarks(std::initializer_list, std::size_t, void(Derived::*)(), void(Derived::*)(), BenchmarkType) with support + * for GPU benchmark types. + */ + template void addBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, void(Derived::*setup)(), void(Derived::*teardown)(), BenchmarkType benchmarkType = BenchmarkType::Default) { + if(benchmarkType == BenchmarkType::GpuTime) + addCustomBenchmarks(benchmarks, batchCount, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, setup, teardown, BenchmarkUnits::Nanoseconds); + else + Tester::addBenchmarks(benchmarks, batchCount, setup, teardown, Tester::BenchmarkType(Int(benchmarkType))); + } + + /** + * @brief Add instanced benchmarks + * + * Extends @ref Corrade::TestSuite::Tester::addInstancedBenchmarks(std::initializer_list, std::size_t, std::size_t, BenchmarkType) with support for GPU + * benchmark types. + */ + template void addInstancedBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, std::size_t instanceCount, BenchmarkType benchmarkType = BenchmarkType::Default) { + if(benchmarkType == BenchmarkType::GpuTime) + addCustomInstancedBenchmarks(benchmarks, batchCount, instanceCount, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, BenchmarkUnits::Nanoseconds); + else + Tester::addInstancedBenchmarks(benchmarks, batchCount, instanceCount, Tester::BenchmarkType(Int(benchmarkType))); + } + + /** + * @brief Add instanced benchmarks with explicit setup and teardown functions + * + * Extends @ref Corrade::TestSuite::Tester::addInstancedBenchmarks(std::initializer_list, std::size_t, std::size_t, void(Derived::*)(), void(Derived::*)(), BenchmarkType) + * with support for GPU benchmark types. + */ + template void addInstancedBenchmarks(std::initializer_list benchmarks, std::size_t batchCount, std::size_t instanceCount, void(Derived::*setup)(), void(Derived::*teardown)(), BenchmarkType benchmarkType = BenchmarkType::Default) { + if(benchmarkType == BenchmarkType::GpuTime) + addCustomInstancedBenchmarks(benchmarks, batchCount, instanceCount, &OpenGLTester::gpuTimeBenchmarkBegin, &OpenGLTester::gpuTimeBenchmarkEnd, setup, teardown, BenchmarkUnits::Nanoseconds); + else + Tester::addInstancedBenchmarks(benchmarks, batchCount, instanceCount, setup, teardown, Tester::BenchmarkType(Int(benchmarkType))); + } + private: + void gpuTimeBenchmarkBegin(); + std::uint64_t gpuTimeBenchmarkEnd(); + struct WindowlessApplication: Platform::WindowlessApplication { explicit WindowlessApplication(const Arguments& arguments): Platform::WindowlessApplication{arguments, NoCreate} {} int exec() override final { return 0; } @@ -116,6 +219,8 @@ class OpenGLTester: public TestSuite::Tester { using Platform::WindowlessApplication::createContext; } _windowlessApplication; + + TimeQuery _gpuTimeQuery{NoCreate}; }; /** @hideinitializer