From cbc206e84f083eff8fb6d016798ab1df4b5f192e Mon Sep 17 00:00:00 2001 From: Austin Eng Date: Tue, 10 Dec 2019 23:32:48 +0000 Subject: [PATCH] Add intermediate dawn_wire command handler to dump command traces This adds an argument to Dawn tests to use an intermediate command handler which dumps command traces. In the near term, this will be useful to generate a seed corpus for fuzzing. In the future, we may be able to use the layer to produce reproducible traces of real applications. Bug: dawn:295 Change-Id: Ie36d10f4b46f4b16a3ad3ea34961fd38ba8041aa Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/14241 Commit-Queue: Austin Eng Reviewed-by: Kai Ninomiya --- src/tests/DawnTest.cpp | 54 ++++++++++++++++++++++++++++++++++++++++++ src/tests/DawnTest.h | 5 ++++ 2 files changed, 59 insertions(+) diff --git a/src/tests/DawnTest.cpp b/src/tests/DawnTest.cpp index 8df1cd830e..4d9a09ec5b 100644 --- a/src/tests/DawnTest.cpp +++ b/src/tests/DawnTest.cpp @@ -19,6 +19,7 @@ #include "common/Log.h" #include "common/Math.h" #include "common/Platform.h" +#include "common/SystemUtils.h" #include "dawn/dawn_proc.h" #include "dawn_native/DawnNative.h" #include "dawn_wire/WireClient.h" @@ -28,6 +29,7 @@ #include "utils/WGPUHelpers.h" #include +#include #include #include #include @@ -158,6 +160,19 @@ DawnTestEnvironment::DawnTestEnvironment(int argc, char** argv) { continue; } + constexpr const char kWireTraceDirArg[] = "--wire-trace-dir="; + if (strstr(argv[i], kWireTraceDirArg) == argv[i]) { + const char* wireTraceDir = argv[i] + strlen(kWireTraceDirArg); + if (wireTraceDir[0] != '\0') { + const char* sep = GetPathSeparator(); + mWireTraceDir = wireTraceDir; + if (mWireTraceDir.back() != *sep) { + mWireTraceDir += sep; + } + } + continue; + } + if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) { dawn::InfoLog() << "\n\nUsage: " << argv[0] @@ -264,6 +279,13 @@ uint32_t DawnTestEnvironment::GetVendorIdFilter() const { return mVendorIdFilter; } +const char* DawnTestEnvironment::GetWireTraceDir() const { + if (mWireTraceDir.length() == 0) { + return nullptr; + } + return mWireTraceDir.c_str(); +} + void DawnTestEnvironment::DiscoverOpenGLAdapter() { #ifdef DAWN_ENABLE_BACKEND_OPENGL if (!glfwInit()) { @@ -285,6 +307,23 @@ void DawnTestEnvironment::DiscoverOpenGLAdapter() { #endif // DAWN_ENABLE_BACKEND_OPENGL } +class WireServerTraceLayer : public dawn_wire::CommandHandler { + public: + WireServerTraceLayer(const char* file, dawn_wire::WireServer* server) + : dawn_wire::CommandHandler(), mServer(server) { + mFile.open(file, std::ios_base::app | std::ios_base::binary | std::ios_base::trunc); + } + + const volatile char* HandleCommands(const volatile char* commands, size_t size) override { + mFile.write(const_cast(commands), size); + return mServer->HandleCommands(commands, size); + } + + private: + dawn_wire::WireServer* mServer; + std::ofstream mFile; +}; + // Implementation of DawnTest DawnTestBase::DawnTestBase(const DawnTestParam& param) : mParam(param) { @@ -497,6 +536,21 @@ void DawnTestBase::SetUp() { mWireServer.reset(new dawn_wire::WireServer(serverDesc)); mC2sBuf->SetHandler(mWireServer.get()); + if (gTestEnv->GetWireTraceDir() != nullptr) { + std::string file = + std::string( + ::testing::UnitTest::GetInstance()->current_test_info()->test_suite_name()) + + "_" + ::testing::UnitTest::GetInstance()->current_test_info()->name(); + // Replace slashes in gtest names with underscores so everything is in one directory. + std::replace(file.begin(), file.end(), '/', '_'); + + std::string fullPath = gTestEnv->GetWireTraceDir() + file; + + mWireServerTraceLayer.reset( + new WireServerTraceLayer(fullPath.c_str(), mWireServer.get())); + mC2sBuf->SetHandler(mWireServerTraceLayer.get()); + } + dawn_wire::WireClientDescriptor clientDesc = {}; clientDesc.serializer = mC2sBuf.get(); diff --git a/src/tests/DawnTest.h b/src/tests/DawnTest.h index 3f23d4ea1c..d7e88a6ab1 100644 --- a/src/tests/DawnTest.h +++ b/src/tests/DawnTest.h @@ -117,6 +117,7 @@ namespace detail { } // namespace detail namespace dawn_wire { + class CommandHandler; class WireClient; class WireServer; } // namespace dawn_wire @@ -140,6 +141,7 @@ class DawnTestEnvironment : public testing::Environment { dawn_native::Instance* GetInstance() const; bool HasVendorIdFilter() const; uint32_t GetVendorIdFilter() const; + const char* GetWireTraceDir() const; protected: std::unique_ptr mInstance; @@ -154,6 +156,7 @@ class DawnTestEnvironment : public testing::Environment { bool mBeginCaptureOnStartup = false; bool mHasVendorIdFilter = false; uint32_t mVendorIdFilter = 0; + std::string mWireTraceDir; }; class DawnTestBase { @@ -242,6 +245,8 @@ class DawnTestBase { std::unique_ptr mC2sBuf; std::unique_ptr mS2cBuf; + std::unique_ptr mWireServerTraceLayer; + // Tracking for validation errors static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata); bool mExpectError = false;