From 56537f8b06dee63553bca824e49bb48339387db3 Mon Sep 17 00:00:00 2001 From: Austin Eng Date: Wed, 19 May 2021 19:38:57 +0000 Subject: [PATCH] Move test parameterization macro from DawnPerfTest to DawnTest Also add macros to make it easier to generate a params struct. This makes it possible to generate parameterized tests in dawn_end2end_tests Bug: none Change-Id: I009475dcc08a5274f5871237a363489cff7298f1 Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/51000 Commit-Queue: Austin Eng Reviewed-by: Corentin Wallez --- src/common/BUILD.gn | 1 + src/common/CMakeLists.txt | 1 + src/common/Preprocessor.h | 71 +++++++++++++++++ src/tests/BUILD.gn | 2 + src/tests/DawnTest.h | 61 +++++++++++++- src/tests/ParamGenerator.h | 9 +++ src/tests/perf_tests/BufferUploadPerf.cpp | 14 ++-- src/tests/perf_tests/DawnPerfTest.h | 6 -- src/tests/perf_tests/DrawCallPerf.cpp | 3 +- src/tests/perf_tests/ShaderRobustnessPerf.cpp | 79 +++++++------------ .../perf_tests/SubresourceTrackingPerf.cpp | 10 +-- 11 files changed, 182 insertions(+), 75 deletions(-) create mode 100644 src/common/Preprocessor.h diff --git a/src/common/BUILD.gn b/src/common/BUILD.gn index 6b93bcb083..dd76c2a83e 100644 --- a/src/common/BUILD.gn +++ b/src/common/BUILD.gn @@ -183,6 +183,7 @@ if (is_win || is_linux || is_chromeos || is_mac || is_fuchsia || is_android) { "NonCopyable.h", "PlacementAllocated.h", "Platform.h", + "Preprocessor.h", "RefBase.h", "RefCounted.cpp", "RefCounted.h", diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 2a7db36126..c73410e69a 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -36,6 +36,7 @@ target_sources(dawn_common PRIVATE "NonCopyable.h" "PlacementAllocated.h" "Platform.h" + "Preprocessor.h" "RefBase.h" "RefCounted.cpp" "RefCounted.h" diff --git a/src/common/Preprocessor.h b/src/common/Preprocessor.h new file mode 100644 index 0000000000..b49fc3ab24 --- /dev/null +++ b/src/common/Preprocessor.h @@ -0,0 +1,71 @@ +// Copyright 2021 The Dawn Authors +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#ifndef COMMON_PREPROCESSOR_H_ +#define COMMON_PREPROCESSOR_H_ + +// DAWN_PP_GET_HEAD: get the first element of a __VA_ARGS__ without triggering empty +// __VA_ARGS__ warnings. +#define DAWN_INTERNAL_PP_GET_HEAD(firstParam, ...) firstParam +#define DAWN_PP_GET_HEAD(...) DAWN_INTERNAL_PP_GET_HEAD(__VA_ARGS__, dummyArg) + +// DAWN_PP_CONCATENATE: Concatenate tokens, first expanding the arguments passed in. +#define DAWN_PP_CONCATENATE(arg1, arg2) DAWN_PP_CONCATENATE_1(arg1, arg2) +#define DAWN_PP_CONCATENATE_1(arg1, arg2) DAWN_PP_CONCATENATE_2(arg1, arg2) +#define DAWN_PP_CONCATENATE_2(arg1, arg2) arg1##arg2 + +// DAWN_PP_EXPAND: Needed to help expand __VA_ARGS__ out on MSVC +#define DAWN_PP_EXPAND(...) __VA_ARGS__ + +// Implementation of DAWN_PP_FOR_EACH, called by concatenating DAWN_PP_FOR_EACH_ with a number. +#define DAWN_PP_FOR_EACH_1(func, x) func(x) +#define DAWN_PP_FOR_EACH_2(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_1)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_3(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_2)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_4(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_3)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_5(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_4)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_6(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_5)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_7(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_6)(func, __VA_ARGS__)) +#define DAWN_PP_FOR_EACH_8(func, x, ...) \ + func(x) DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_7)(func, __VA_ARGS__)) + +// Implementation for DAWN_PP_FOR_EACH. Get the number of args in __VA_ARGS__ so we can concat +// DAWN_PP_FOR_EACH_ and N. +// ex.) DAWN_PP_FOR_EACH_NARG(a, b, c) -> +// DAWN_PP_FOR_EACH_NARG(a, b, c, DAWN_PP_FOR_EACH_RSEQ()) -> +// DAWN_PP_FOR_EACH_NARG_(a, b, c, 8, 7, 6, 5, 4, 3, 2, 1, 0) -> +// DAWN_PP_FOR_EACH_ARG_N(a, b, c, 8, 7, 6, 5, 4, 3, 2, 1, 0) -> +// DAWN_PP_FOR_EACH_ARG_N( , , , , , , , , N) -> +// 3 +#define DAWN_PP_FOR_EACH_NARG(...) DAWN_PP_FOR_EACH_NARG_(__VA_ARGS__, DAWN_PP_FOR_EACH_RSEQ()) +#define DAWN_PP_FOR_EACH_NARG_(...) \ + DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH_ARG_N)(__VA_ARGS__)) +#define DAWN_PP_FOR_EACH_ARG_N(_1, _2, _3, _4, _5, _6, _7, _8, N, ...) N +#define DAWN_PP_FOR_EACH_RSEQ() 8, 7, 6, 5, 4, 3, 2, 1, 0 + +// Implementation for DAWN_PP_FOR_EACH. +// Creates a call to DAWN_PP_FOR_EACH_X where X is 1, 2, ..., etc. +#define DAWN_PP_FOR_EACH_(N, func, x, ...) \ + DAWN_PP_CONCATENATE(DAWN_PP_FOR_EACH_, N)(func, x, __VA_ARGS__) + +// DAWN_PP_FOR_EACH: Apply |func| to each argument in |x| and __VA_ARGS__ +#define DAWN_PP_FOR_EACH(func, x, ...) \ + DAWN_PP_FOR_EACH_(DAWN_PP_FOR_EACH_NARG(x, __VA_ARGS__), func, x, __VA_ARGS__) + +#endif // COMMON_PREPROCESSOR_H_ diff --git a/src/tests/BUILD.gn b/src/tests/BUILD.gn index ea8709b1d9..f90325d28d 100644 --- a/src/tests/BUILD.gn +++ b/src/tests/BUILD.gn @@ -284,6 +284,7 @@ source_set("dawn_end2end_tests_sources") { sources = [ "DawnTest.h", "MockCallback.h", + "ParamGenerator.h", "ToggleParser.cpp", "ToggleParser.h", "end2end/BasicTests.cpp", @@ -412,6 +413,7 @@ source_set("dawn_white_box_tests_sources") { sources = [ "DawnTest.h", + "ParamGenerator.h", "ToggleParser.h", ] diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h index 0ea5f52d59..124205a5c2 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -16,9 +16,11 @@ #define TESTS_DAWNTEST_H_ #include "common/Log.h" +#include "common/Preprocessor.h" #include "dawn/dawn_proc_table.h" #include "dawn/webgpu_cpp.h" #include "dawn_native/DawnNative.h" +#include "tests/ParamGenerator.h" #include "tests/ToggleParser.h" #include @@ -505,10 +507,6 @@ DawnTestWithParams::DawnTestWithParams() : DawnTestBase(this->GetParam() using DawnTest = DawnTestWithParams<>; -// Helpers to get the first element of a __VA_ARGS__ without triggering empty __VA_ARGS__ warnings. -#define DAWN_INTERNAL_PP_GET_HEAD(firstParam, ...) firstParam -#define DAWN_PP_GET_HEAD(...) DAWN_INTERNAL_PP_GET_HEAD(__VA_ARGS__, dummyArg) - // Instantiate the test once for each backend provided after the first argument. Use it like this: // DAWN_INSTANTIATE_TEST(MyTestFixture, MetalBackend, OpenGLBackend) #define DAWN_INSTANTIATE_TEST(testName, ...) \ @@ -520,6 +518,61 @@ using DawnTest = DawnTestWithParams<>; testing::PrintToStringParamName()); \ GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName) +// Instantiate the test once for each backend provided in the first param list. +// The test will be parameterized over the following param lists. +// Use it like this: +// DAWN_INSTANTIATE_TEST_P(MyTestFixture, {MetalBackend, OpenGLBackend}, {A, B, C}, {1, 2, 3}) +// MyTestFixture must extend DawnTestWithParam where Param is a struct that extends +// AdapterTestParam, and whose constructor looks like: +// Param(AdapterTestParam, ABorC, 12or3, ..., otherParams... ) +// You must also teach GTest how to print this struct. +// https://github.com/google/googletest/blob/master/docs/advanced.md#teaching-googletest-how-to-print-your-values +// Macro DAWN_TEST_PARAM_STRUCT can help generate this struct. +#define DAWN_INSTANTIATE_TEST_P(testName, ...) \ + INSTANTIATE_TEST_SUITE_P( \ + , testName, ::testing::ValuesIn(MakeParamGenerator(__VA_ARGS__)), \ + testing::PrintToStringParamName()); \ + GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName) + +// Implementation for DAWN_TEST_PARAM_STRUCT to declare/print struct fields. +#define DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD(Type) Type DAWN_PP_CONCATENATE(m, Type); +#define DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD(Type) \ + o << "__" << #Type << "_" << param.DAWN_PP_CONCATENATE(m, Type); + +// Usage: DAWN_TEST_PARAM_STRUCT(Foo, TypeA, TypeB, ...) +// Generate a test param struct called Foo which extends AdapterTestParam and generated +// struct _Dawn_Foo. _Dawn_Foo has members of types TypeA, TypeB, etc. which are named mTypeA, +// mTypeB, etc. in the order they are placed in the macro argument list. Struct Foo should be +// constructed with an AdapterTestParam as the first argument, followed by a list of values +// to initialize the base _Dawn_Foo struct. +// It is recommended to use alias declarations so that stringified types are more readable. +// Example: +// using MyParam = unsigned int; +// DAWN_TEST_PARAM_STRUCT(FooParams, MyParam) +#define DAWN_TEST_PARAM_STRUCT(StructName, ...) \ + struct DAWN_PP_CONCATENATE(_Dawn_, StructName) { \ + DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_DECL_STRUCT_FIELD, \ + __VA_ARGS__)) \ + }; \ + std::ostream& operator<<(std::ostream& o, \ + const DAWN_PP_CONCATENATE(_Dawn_, StructName) & param) { \ + DAWN_PP_EXPAND(DAWN_PP_EXPAND(DAWN_PP_FOR_EACH)(DAWN_TEST_PARAM_STRUCT_PRINT_STRUCT_FIELD, \ + __VA_ARGS__)) \ + return o; \ + } \ + struct StructName : AdapterTestParam, DAWN_PP_CONCATENATE(_Dawn_, StructName) { \ + template \ + StructName(const AdapterTestParam& param, Args&&... args) \ + : AdapterTestParam(param), \ + DAWN_PP_CONCATENATE(_Dawn_, StructName){std::forward(args)...} { \ + } \ + }; \ + std::ostream& operator<<(std::ostream& o, const StructName& param) { \ + o << static_cast(param); \ + o << "_" << static_cast(param); \ + return o; \ + } + namespace detail { // Helper functions used for DAWN_INSTANTIATE_TEST std::vector GetAvailableAdapterTestParamsForBackends( diff --git a/src/tests/ParamGenerator.h b/src/tests/ParamGenerator.h index 1497343fd2..213756a025 100644 --- a/src/tests/ParamGenerator.h +++ b/src/tests/ParamGenerator.h @@ -107,6 +107,15 @@ class ParamGenerator { ParamTuple mParams; }; +struct BackendTestConfig; +struct AdapterTestParam; + +namespace detail { + std::vector GetAvailableAdapterTestParamsForBackends( + const BackendTestConfig* params, + size_t numParams); +} + template auto MakeParamGenerator(std::vector&& first, std::initializer_list&&... params) { diff --git a/src/tests/perf_tests/BufferUploadPerf.cpp b/src/tests/perf_tests/BufferUploadPerf.cpp index 03d8bce776..70f257f34a 100644 --- a/src/tests/perf_tests/BufferUploadPerf.cpp +++ b/src/tests/perf_tests/BufferUploadPerf.cpp @@ -14,7 +14,6 @@ #include "tests/perf_tests/DawnPerfTest.h" -#include "tests/ParamGenerator.h" #include "utils/WGPUHelpers.h" namespace { @@ -148,10 +147,9 @@ TEST_P(BufferUploadPerf, Run) { RunTest(); } -DAWN_INSTANTIATE_PERF_TEST_SUITE_P(BufferUploadPerf, - {D3D12Backend(), MetalBackend(), OpenGLBackend(), - VulkanBackend()}, - {UploadMethod::WriteBuffer, UploadMethod::MappedAtCreation}, - {UploadSize::BufferSize_1KB, UploadSize::BufferSize_64KB, - UploadSize::BufferSize_1MB, UploadSize::BufferSize_4MB, - UploadSize::BufferSize_16MB}); +DAWN_INSTANTIATE_TEST_P(BufferUploadPerf, + {D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend()}, + {UploadMethod::WriteBuffer, UploadMethod::MappedAtCreation}, + {UploadSize::BufferSize_1KB, UploadSize::BufferSize_64KB, + UploadSize::BufferSize_1MB, UploadSize::BufferSize_4MB, + UploadSize::BufferSize_16MB}); diff --git a/src/tests/perf_tests/DawnPerfTest.h b/src/tests/perf_tests/DawnPerfTest.h index 3c1e7a9124..176029c463 100644 --- a/src/tests/perf_tests/DawnPerfTest.h +++ b/src/tests/perf_tests/DawnPerfTest.h @@ -120,10 +120,4 @@ class DawnPerfTestWithParams : public DawnTestWithParams, public DawnPer using DawnPerfTest = DawnPerfTestWithParams<>; -#define DAWN_INSTANTIATE_PERF_TEST_SUITE_P(testName, ...) \ - INSTANTIATE_TEST_SUITE_P( \ - , testName, ::testing::ValuesIn(MakeParamGenerator(__VA_ARGS__)), \ - testing::PrintToStringParamName()); \ - GTEST_ALLOW_UNINSTANTIATED_PARAMETERIZED_TEST(testName) - #endif // TESTS_PERFTESTS_DAWNPERFTEST_H_ diff --git a/src/tests/perf_tests/DrawCallPerf.cpp b/src/tests/perf_tests/DrawCallPerf.cpp index a0456c055d..8875e3b91f 100644 --- a/src/tests/perf_tests/DrawCallPerf.cpp +++ b/src/tests/perf_tests/DrawCallPerf.cpp @@ -17,7 +17,6 @@ #include "common/Assert.h" #include "common/Constants.h" #include "common/Math.h" -#include "tests/ParamGenerator.h" #include "utils/ComboRenderPipelineDescriptor.h" #include "utils/WGPUHelpers.h" @@ -607,7 +606,7 @@ TEST_P(DrawCallPerf, Run) { RunTest(); } -DAWN_INSTANTIATE_PERF_TEST_SUITE_P( +DAWN_INSTANTIATE_TEST_P( DrawCallPerf, {D3D12Backend(), MetalBackend(), OpenGLBackend(), VulkanBackend(), VulkanBackend({"skip_validation"})}, diff --git a/src/tests/perf_tests/ShaderRobustnessPerf.cpp b/src/tests/perf_tests/ShaderRobustnessPerf.cpp index 78c1b64378..ee1d3bbdd7 100644 --- a/src/tests/perf_tests/ShaderRobustnessPerf.cpp +++ b/src/tests/perf_tests/ShaderRobustnessPerf.cpp @@ -14,7 +14,6 @@ #include "tests/perf_tests/DawnPerfTest.h" -#include "tests/ParamGenerator.h" #include "utils/WGPUHelpers.h" namespace { @@ -355,47 +354,29 @@ namespace { MatMulVec4TwoDimSharedArray }; - struct ShaderRobustnessParams : AdapterTestParam { - ShaderRobustnessParams(const AdapterTestParam& param, - MatMulMethod matmulMethod, - uint32_t dimAOuter, - uint32_t dimInner, - uint32_t dimBOuter) - : AdapterTestParam(param), - matmulMethod(matmulMethod), - dimAOuter(dimAOuter), - dimInner(dimInner), - dimBOuter(dimBOuter) { - } - - MatMulMethod matmulMethod; - uint32_t dimAOuter; - uint32_t dimInner; - uint32_t dimBOuter; - }; - - std::ostream& operator<<(std::ostream& ostream, const ShaderRobustnessParams& param) { - ostream << static_cast(param); - switch (param.matmulMethod) { + std::ostream& operator<<(std::ostream& ostream, const MatMulMethod& matMulMethod) { + switch (matMulMethod) { case MatMulMethod::MatMulFloatOneDimSharedArray: - ostream << "_MatMulFloatOneDimSharedArray"; + ostream << "MatMulFloatOneDimSharedArray"; break; case MatMulMethod::MatMulFloatTwoDimSharedArray: - ostream << "_MatMulFloatTwoDimSharedArray"; + ostream << "MatMulFloatTwoDimSharedArray"; break; case MatMulMethod::MatMulVec4OneDimSharedArray: - ostream << "_MatMulVec4OneDimSharedArray"; + ostream << "MatMulVec4OneDimSharedArray"; break; case MatMulMethod::MatMulVec4TwoDimSharedArray: - ostream << "_MatMulVec4TwoDimSharedArray"; + ostream << "MatMulVec4TwoDimSharedArray"; break; } - - ostream << "_" << param.dimAOuter << "_" << param.dimInner << "_" << param.dimBOuter; - return ostream; } + using DimAOuter = uint32_t; + using DimInner = uint32_t; + using DimBOuter = uint32_t; + DAWN_TEST_PARAM_STRUCT(ShaderRobustnessParams, MatMulMethod, DimAOuter, DimInner, DimBOuter) + } // namespace // Test the execution time of matrix multiplication (A [dimAOuter, dimInner] * B [dimInner, @@ -404,9 +385,9 @@ class ShaderRobustnessPerf : public DawnPerfTestWithParams