Commit 2c41931c by Manh Nguyen Committed by Commit Bot

Batch-compile and batch-run-replay multiple tests

Multiple tests are batch-compiled into 1 replay application instead of multiple replay applications. Replay application now runs generated code of multiple tests instead of 1 test. This reduces overhead cost and brings down runtime. Main process now receives messages sent by workers via a message queue and prints them to the main stdout so that user can know if workers are hanging. Add handle for user interrupt (Ctrl-C) so that processes are properly destroyed and cleaned up. Trace files now have the option not to be deleted. Bug: angleproject:4817 Change-Id: Ic90ae0f430e1d3c261ffea5f963be5a4e94b0ad2 Reviewed-on: https://chromium-review.googlesource.com/c/angle/angle/+/2310909Reviewed-by: 's avatarCody Northrop <cnorthrop@google.com> Reviewed-by: 's avatarJamie Madill <jmadill@chromium.org> Commit-Queue: Manh Nguyen <nguyenmh@google.com>
parent d7d79de3
angle_capture_context* trace*/
\ No newline at end of file angle_trace_gl.h
results.txt
\ No newline at end of file
...@@ -3,6 +3,7 @@ ...@@ -3,6 +3,7 @@
# found in the LICENSE file. # found in the LICENSE file.
import("../../../gni/angle.gni") import("../../../gni/angle.gni")
declare_args() { declare_args() {
# Determines if we build the capture_replay_tests. Off by default. # Determines if we build the capture_replay_tests. Off by default.
angle_build_capture_replay_tests = false angle_build_capture_replay_tests = false
...@@ -10,27 +11,28 @@ declare_args() { ...@@ -10,27 +11,28 @@ declare_args() {
# Decide which context to replay, starting with desktop default # Decide which context to replay, starting with desktop default
angle_capture_replay_test_context_id = 1 angle_capture_replay_test_context_id = 1
#Set the trace directory. Default is traces # Set the trace directory. Default is traces
angle_capture_replay_test_trace_dir = "traces" angle_capture_replay_test_trace_dir = "traces"
angle_capture_replay_composite_file_id = 1
} }
if (angle_build_capture_replay_tests) { if (angle_build_capture_replay_tests) {
# TODO (nguyenmh): http://anglebug.com/4758: # TODO (nguyenmh): http://anglebug.com/4758:
# turn angle_executable into angle_test when adding android support # turn angle_executable into angle_test when adding android support
import(
"${angle_capture_replay_test_trace_dir}/traces${angle_capture_replay_composite_file_id}.gni")
angle_executable("capture_replay_tests") { angle_executable("capture_replay_tests") {
testonly = true testonly = true
_contextid = angle_capture_replay_test_context_id _contextid = angle_capture_replay_test_context_id
_trace_folder_relative_path = "./" + angle_capture_replay_test_trace_dir _trace_folder_relative_path = "./" + angle_capture_replay_test_trace_dir
_trace_sources = _trace_sources =
read_file(_trace_folder_relative_path + generated_sources + [
"/angle_capture_context${_contextid}_files.txt", "CompositeTests${angle_capture_replay_composite_file_id}.h",
"list lines") + "CompositeTests${angle_capture_replay_composite_file_id}.cpp",
[
"angle_capture_context${_contextid}.cpp",
"angle_capture_context${_contextid}.h",
] ]
sources = rebase_path(_trace_sources, ".", _trace_folder_relative_path) + sources = rebase_path(_trace_sources, ".", _trace_folder_relative_path) +
[ "CaptureReplayTest.cpp" ] [ "CaptureReplayTests.cpp" ]
deps = [ deps = [
"$angle_root:angle_common", "$angle_root:angle_common",
"$angle_root:angle_compression", "$angle_root:angle_compression",
...@@ -53,8 +55,11 @@ if (angle_build_capture_replay_tests) { ...@@ -53,8 +55,11 @@ if (angle_build_capture_replay_tests) {
defines = [ defines = [
"ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR=\"${_data_path}\"", "ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR=\"${_data_path}\"",
"ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID=${_contextid}", "ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID=${_contextid}",
"ANGLE_CAPTURE_REPLAY_TEST_HEADER=" + "${angle_capture_replay_test_trace_dir}/angle_capture_context${_contextid}.h", "ANGLE_CAPTURE_REPLAY_COMPOSITE_TESTS_HEADER=" +
angle_capture_replay_test_trace_dir +
"/CompositeTests${angle_capture_replay_composite_file_id}.h",
] ]
include_dirs = [ "." ]
} }
} else { } else {
group("capture_replay_tests") { group("capture_replay_tests") {
......
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <stdint.h> #include <stdint.h>
#include <string.h> #include <string.h>
#include <functional> #include <functional>
#include <iostream>
#include <list> #include <list>
#include <memory> #include <memory>
#include <string> #include <string>
...@@ -26,29 +27,31 @@ ...@@ -26,29 +27,31 @@
// Build the right context header based on replay ID // Build the right context header based on replay ID
// This will expand to "angle_capture_context<#>.h" // This will expand to "angle_capture_context<#>.h"
#include ANGLE_MACRO_STRINGIZE(ANGLE_CAPTURE_REPLAY_TEST_HEADER) #include ANGLE_MACRO_STRINGIZE(ANGLE_CAPTURE_REPLAY_COMPOSITE_TESTS_HEADER)
// Assign the context numbered functions based on GN arg selecting replay ID // Assign the context numbered functions based on GN arg selecting replay ID
std::function<void()> SetupContextReplay = reinterpret_cast<void (*)()>( std::function<void(uint32_t)> SetupContextReplay = reinterpret_cast<void (*)(uint32_t)>(
ANGLE_MACRO_CONCAT(SetupContext, ANGLE_MACRO_CONCAT(SetupContext,
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Replay))); ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Replay)));
std::function<void(int)> ReplayContextFrame = reinterpret_cast<void (*)(int)>( std::function<void(uint32_t, uint32_t)> ReplayContextFrame =
ANGLE_MACRO_CONCAT(ReplayContext, reinterpret_cast<void (*)(uint32_t, uint32_t)>(
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Frame))); ANGLE_MACRO_CONCAT(ReplayContext,
std::function<void()> ResetContextReplay = reinterpret_cast<void (*)()>( ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Frame)));
std::function<void(uint32_t)> ResetContextReplay = reinterpret_cast<void (*)(uint32_t)>(
ANGLE_MACRO_CONCAT(ResetContext, ANGLE_MACRO_CONCAT(ResetContext,
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Replay))); ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, Replay)));
std::function<std::vector<uint8_t>(uint32_t)> GetSerializedContextStateData = std::function<std::vector<uint8_t>(uint32_t, uint32_t)> GetSerializedContextStateData =
reinterpret_cast<std::vector<uint8_t> (*)(uint32_t)>( reinterpret_cast<std::vector<uint8_t> (*)(uint32_t, uint32_t)>(
ANGLE_MACRO_CONCAT(GetSerializedContext, ANGLE_MACRO_CONCAT(GetSerializedContext,
ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, StateData))); ANGLE_MACRO_CONCAT(ANGLE_CAPTURE_REPLAY_TEST_CONTEXT_ID, StateData)));
class CaptureReplayTest const std::string resultTag = "*RESULT";
class CaptureReplayTests
{ {
public: public:
CaptureReplayTest(EGLint glesMajorVersion, EGLint glesMinorVersion) CaptureReplayTests(EGLint glesMajorVersion, EGLint glesMinorVersion)
: mOSWindow(nullptr), mEGLWindow(nullptr) : mOSWindow(nullptr), mEGLWindow(nullptr)
{ {
mPlatformParams.renderer = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE; mPlatformParams.renderer = EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE;
mPlatformParams.deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE; mPlatformParams.deviceType = EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE;
...@@ -56,110 +59,124 @@ class CaptureReplayTest ...@@ -56,110 +59,124 @@ class CaptureReplayTest
// Load EGL library so we can initialize the display. // Load EGL library so we can initialize the display.
mEntryPointsLib.reset( mEntryPointsLib.reset(
angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir)); angle::OpenSharedLibrary(ANGLE_EGL_LIBRARY_NAME, angle::SearchType::ApplicationDir));
mEGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion); mEGLWindow = EGLWindow::New(glesMajorVersion, glesMinorVersion);
mOSWindow = OSWindow::New(); mOSWindow = OSWindow::New();
mOSWindow->disableErrorMessageDialog(); mOSWindow->disableErrorMessageDialog();
} }
~CaptureReplayTest() ~CaptureReplayTests()
{ {
EGLWindow::Delete(&mEGLWindow); EGLWindow::Delete(&mEGLWindow);
OSWindow::Delete(&mOSWindow); OSWindow::Delete(&mOSWindow);
} }
bool initialize() bool initializeTest(uint32_t testIndex, TestTraceInfo &testTraceInfo)
{
// Set CWD to executable directory.
std::string exeDir = angle::GetExecutableDirectory();
if (!angle::SetCWD(exeDir.c_str()))
return false;
if (kIsBinaryDataCompressed)
{
SetBinaryDataDecompressCallback(angle::DecompressBinaryData);
}
SetBinaryDataDir(ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR);
SetupContextReplay();
return true;
}
void swap() { mEGLWindow->swap(); }
int run()
{ {
if (!mOSWindow->initialize("Capture Replay Test", kReplayDrawSurfaceWidth, if (!mOSWindow->initialize(testTraceInfo.testName, testTraceInfo.replayDrawSurfaceWidth,
kReplayDrawSurfaceHeight)) testTraceInfo.replayDrawSurfaceHeight))
{ {
return -1; return false;
} }
mOSWindow->disableErrorMessageDialog();
mOSWindow->setVisible(true); mOSWindow->setVisible(true);
ConfigParameters configParams; ConfigParameters configParams;
configParams.redBits = kDefaultFramebufferRedBits; configParams.redBits = testTraceInfo.defaultFramebufferRedBits;
configParams.greenBits = kDefaultFramebufferGreenBits; configParams.greenBits = testTraceInfo.defaultFramebufferGreenBits;
configParams.blueBits = kDefaultFramebufferBlueBits; configParams.blueBits = testTraceInfo.defaultFramebufferBlueBits;
configParams.alphaBits = kDefaultFramebufferAlphaBits; configParams.alphaBits = testTraceInfo.defaultFramebufferAlphaBits;
configParams.depthBits = kDefaultFramebufferDepthBits; configParams.depthBits = testTraceInfo.defaultFramebufferDepthBits;
configParams.stencilBits = kDefaultFramebufferStencilBits; configParams.stencilBits = testTraceInfo.defaultFramebufferStencilBits;
if (!mEGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(), if (!mEGLWindow->initializeGL(mOSWindow, mEntryPointsLib.get(),
angle::GLESDriverType::AngleEGL, mPlatformParams, angle::GLESDriverType::AngleEGL, mPlatformParams,
configParams)) configParams))
{ {
return -1; mOSWindow->destroy();
return false;
} }
// Disable vsync // Disable vsync
if (!mEGLWindow->setSwapInterval(0)) if (!mEGLWindow->setSwapInterval(0))
{ {
return -1; cleanupTest();
return false;
}
// Set CWD to executable directory.
std::string exeDir = angle::GetExecutableDirectory();
if (!angle::SetCWD(exeDir.c_str()))
{
cleanupTest();
return false;
}
if (testTraceInfo.isBinaryDataCompressed)
{
SetBinaryDataDecompressCallback(testIndex, angle::DecompressBinaryData);
} }
SetBinaryDataDir(testIndex, ANGLE_CAPTURE_REPLAY_TEST_DATA_DIR);
SetupContextReplay(testIndex);
return true;
}
void cleanupTest()
{
mEGLWindow->destroyGL();
mOSWindow->destroy();
}
int result = 0; void swap() { mEGLWindow->swap(); }
if (!initialize()) int runTest(uint32_t testIndex, TestTraceInfo &testTraceInfo)
{
if (!initializeTest(testIndex, testTraceInfo))
{ {
result = -1; return -1;
} }
for (uint32_t frame = kReplayFrameStart; frame <= kReplayFrameEnd; frame++) for (uint32_t frame = testTraceInfo.replayFrameStart; frame <= testTraceInfo.replayFrameEnd;
frame++)
{ {
ReplayContextFrame(frame); ReplayContextFrame(testIndex, frame);
gl::Context *context = static_cast<gl::Context *>(mEGLWindow->getContext()); gl::Context *context = static_cast<gl::Context *>(mEGLWindow->getContext());
gl::BinaryOutputStream bos; gl::BinaryOutputStream bos;
// If swapBuffers is not called, then default framebuffer should not be serialized
if (angle::SerializeContext(&bos, context) != angle::Result::Continue) if (angle::SerializeContext(&bos, context) != angle::Result::Continue)
{ {
cleanupTest();
return -1; return -1;
} }
bool isEqual = compareSerializedStates(frame, bos); bool isEqual = compareSerializedStates(testIndex, frame, bos);
if (!isEqual) if (!isEqual)
{ {
cleanupTest();
return -1; return -1;
} }
swap(); swap();
} }
cleanupTest();
return 0;
}
mEGLWindow->destroyGL(); int run()
mOSWindow->destroy(); {
for (size_t i = 0; i < testTraceInfos.size(); i++)
return result; {
int result = runTest(static_cast<uint32_t>(i), testTraceInfos[i]);
std::cout << resultTag << " " << testTraceInfos[i].testName << " " << result << "\n";
}
return 0;
} }
private: private:
bool compareSerializedStates(uint32_t frame, bool compareSerializedStates(uint32_t testIndex,
uint32_t frame,
const gl::BinaryOutputStream &replaySerializedContextData) const gl::BinaryOutputStream &replaySerializedContextData)
{ {
return GetSerializedContextStateData(frame) == replaySerializedContextData.getData(); return GetSerializedContextStateData(testIndex, frame) ==
replaySerializedContextData.getData();
} }
OSWindow *mOSWindow; OSWindow *mOSWindow;
EGLWindow *mEGLWindow; EGLWindow *mEGLWindow;
EGLPlatformParameters mPlatformParams; EGLPlatformParameters mPlatformParams;
// Handle to the entry point binding library. // Handle to the entry point binding library.
std::unique_ptr<angle::Library> mEntryPointsLib; std::unique_ptr<angle::Library> mEntryPointsLib;
}; };
...@@ -169,6 +186,6 @@ int main(int argc, char **argv) ...@@ -169,6 +186,6 @@ int main(int argc, char **argv)
// TODO (nguyenmh): http://anglebug.com/4759: initialize app with arguments taken from cmdline // TODO (nguyenmh): http://anglebug.com/4759: initialize app with arguments taken from cmdline
const EGLint glesMajorVersion = 2; const EGLint glesMajorVersion = 2;
const GLint glesMinorVersion = 0; const GLint glesMinorVersion = 0;
CaptureReplayTest app(glesMajorVersion, glesMinorVersion); CaptureReplayTests app(glesMajorVersion, glesMinorVersion);
return app.run(); return app.run();
} }
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment