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 <enga@chromium.org>
Reviewed-by: Kai Ninomiya <kainino@chromium.org>
This commit is contained in:
Austin Eng 2019-12-10 23:32:48 +00:00 committed by Commit Bot service account
parent d1db0e94b0
commit cbc206e84f
2 changed files with 59 additions and 0 deletions

View File

@ -19,6 +19,7 @@
#include "common/Log.h" #include "common/Log.h"
#include "common/Math.h" #include "common/Math.h"
#include "common/Platform.h" #include "common/Platform.h"
#include "common/SystemUtils.h"
#include "dawn/dawn_proc.h" #include "dawn/dawn_proc.h"
#include "dawn_native/DawnNative.h" #include "dawn_native/DawnNative.h"
#include "dawn_wire/WireClient.h" #include "dawn_wire/WireClient.h"
@ -28,6 +29,7 @@
#include "utils/WGPUHelpers.h" #include "utils/WGPUHelpers.h"
#include <algorithm> #include <algorithm>
#include <fstream>
#include <iomanip> #include <iomanip>
#include <sstream> #include <sstream>
#include <unordered_map> #include <unordered_map>
@ -158,6 +160,19 @@ DawnTestEnvironment::DawnTestEnvironment(int argc, char** argv) {
continue; 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) { if (strcmp("-h", argv[i]) == 0 || strcmp("--help", argv[i]) == 0) {
dawn::InfoLog() dawn::InfoLog()
<< "\n\nUsage: " << argv[0] << "\n\nUsage: " << argv[0]
@ -264,6 +279,13 @@ uint32_t DawnTestEnvironment::GetVendorIdFilter() const {
return mVendorIdFilter; return mVendorIdFilter;
} }
const char* DawnTestEnvironment::GetWireTraceDir() const {
if (mWireTraceDir.length() == 0) {
return nullptr;
}
return mWireTraceDir.c_str();
}
void DawnTestEnvironment::DiscoverOpenGLAdapter() { void DawnTestEnvironment::DiscoverOpenGLAdapter() {
#ifdef DAWN_ENABLE_BACKEND_OPENGL #ifdef DAWN_ENABLE_BACKEND_OPENGL
if (!glfwInit()) { if (!glfwInit()) {
@ -285,6 +307,23 @@ void DawnTestEnvironment::DiscoverOpenGLAdapter() {
#endif // DAWN_ENABLE_BACKEND_OPENGL #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<const char*>(commands), size);
return mServer->HandleCommands(commands, size);
}
private:
dawn_wire::WireServer* mServer;
std::ofstream mFile;
};
// Implementation of DawnTest // Implementation of DawnTest
DawnTestBase::DawnTestBase(const DawnTestParam& param) : mParam(param) { DawnTestBase::DawnTestBase(const DawnTestParam& param) : mParam(param) {
@ -497,6 +536,21 @@ void DawnTestBase::SetUp() {
mWireServer.reset(new dawn_wire::WireServer(serverDesc)); mWireServer.reset(new dawn_wire::WireServer(serverDesc));
mC2sBuf->SetHandler(mWireServer.get()); 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 = {}; dawn_wire::WireClientDescriptor clientDesc = {};
clientDesc.serializer = mC2sBuf.get(); clientDesc.serializer = mC2sBuf.get();

View File

@ -117,6 +117,7 @@ namespace detail {
} // namespace detail } // namespace detail
namespace dawn_wire { namespace dawn_wire {
class CommandHandler;
class WireClient; class WireClient;
class WireServer; class WireServer;
} // namespace dawn_wire } // namespace dawn_wire
@ -140,6 +141,7 @@ class DawnTestEnvironment : public testing::Environment {
dawn_native::Instance* GetInstance() const; dawn_native::Instance* GetInstance() const;
bool HasVendorIdFilter() const; bool HasVendorIdFilter() const;
uint32_t GetVendorIdFilter() const; uint32_t GetVendorIdFilter() const;
const char* GetWireTraceDir() const;
protected: protected:
std::unique_ptr<dawn_native::Instance> mInstance; std::unique_ptr<dawn_native::Instance> mInstance;
@ -154,6 +156,7 @@ class DawnTestEnvironment : public testing::Environment {
bool mBeginCaptureOnStartup = false; bool mBeginCaptureOnStartup = false;
bool mHasVendorIdFilter = false; bool mHasVendorIdFilter = false;
uint32_t mVendorIdFilter = 0; uint32_t mVendorIdFilter = 0;
std::string mWireTraceDir;
}; };
class DawnTestBase { class DawnTestBase {
@ -242,6 +245,8 @@ class DawnTestBase {
std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf; std::unique_ptr<utils::TerribleCommandBuffer> mC2sBuf;
std::unique_ptr<utils::TerribleCommandBuffer> mS2cBuf; std::unique_ptr<utils::TerribleCommandBuffer> mS2cBuf;
std::unique_ptr<dawn_wire::CommandHandler> mWireServerTraceLayer;
// Tracking for validation errors // Tracking for validation errors
static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata); static void OnDeviceError(WGPUErrorType type, const char* message, void* userdata);
bool mExpectError = false; bool mExpectError = false;