Commit 4024e217 by Jamie Madill Committed by Commit Bot

perftests: Record trace events to JSON file.

This allows us to view the timeline of events in the trace event browser. We can extend this to do GPU timestamp queries and analyze when work is actually in flight. The trace is enabled in standalone ANGLE only using the flag --enable-trace with angle_perftests. You can also optionally specify the trace output file with --trace-file <blah>. The default file is ANGLETrace.json. Bug: angleproject:2781 Change-Id: I871f28545d9bf18220b55aaf69e9554dcb4c834d Reviewed-on: https://chromium-review.googlesource.com/c/1259763 Commit-Queue: Jamie Madill <jmadill@chromium.org> Reviewed-by: 's avatarGeoff Lang <geofflang@chromium.org>
parent 3a482179
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include "libANGLE/Thread.h" #include "libANGLE/Thread.h"
#include "libANGLE/formatutils.h" #include "libANGLE/formatutils.h"
#include "libANGLE/renderer/EGLImplFactory.h" #include "libANGLE/renderer/EGLImplFactory.h"
#include "third_party/trace_event/trace_event.h"
namespace egl namespace egl
{ {
...@@ -222,6 +223,8 @@ EGLint Surface::getType() const ...@@ -222,6 +223,8 @@ EGLint Surface::getType() const
Error Surface::swap(const gl::Context *context) Error Surface::swap(const gl::Context *context)
{ {
TRACE_EVENT0("gpu.angle", "egl::Surface::swap");
ANGLE_TRY(mImplementation->swap(context)); ANGLE_TRY(mImplementation->swap(context));
postSwap(context); postSwap(context);
return NoError(); return NoError();
......
...@@ -238,6 +238,7 @@ if (is_win || is_linux || is_android || is_mac) { ...@@ -238,6 +238,7 @@ if (is_win || is_linux || is_android || is_mac) {
angle_root + ":libANGLE", angle_root + ":libANGLE",
angle_root + ":libEGL_static", angle_root + ":libEGL_static",
angle_root + ":libGLESv2_static", angle_root + ":libGLESv2_static",
angle_root + "/third_party/jsoncpp:jsoncpp",
] ]
if (is_android) { if (is_android) {
......
...@@ -10,6 +10,8 @@ ...@@ -10,6 +10,8 @@
#include <gtest/gtest.h> #include <gtest/gtest.h>
extern bool g_OnlyOneRunFrame; extern bool g_OnlyOneRunFrame;
extern bool gEnableTrace;
extern const char *gTraceFile;
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
...@@ -19,6 +21,15 @@ int main(int argc, char **argv) ...@@ -19,6 +21,15 @@ int main(int argc, char **argv)
{ {
g_OnlyOneRunFrame = true; g_OnlyOneRunFrame = true;
} }
if (strcmp("--enable-trace", argv[i]) == 0)
{
gEnableTrace = true;
}
if (strcmp("--trace-file", argv[i]) == 0 && i < argc - 1)
{
gTraceFile = argv[i + 1];
argc++;
}
} }
testing::InitGoogleTest(&argc, argv); testing::InitGoogleTest(&argc, argv);
......
...@@ -12,10 +12,15 @@ ...@@ -12,10 +12,15 @@
#include <cassert> #include <cassert>
#include <cmath> #include <cmath>
#include <fstream>
#include <iostream> #include <iostream>
#include <json/json.h>
namespace namespace
{ {
constexpr size_t kInitialTraceEventBufferSize = 50000;
void EmptyPlatformMethod(angle::PlatformMethods *, const char *) void EmptyPlatformMethod(angle::PlatformMethods *, const char *)
{ {
} }
...@@ -25,9 +30,87 @@ void OverrideWorkaroundsD3D(angle::PlatformMethods *platform, angle::Workarounds ...@@ -25,9 +30,87 @@ void OverrideWorkaroundsD3D(angle::PlatformMethods *platform, angle::Workarounds
auto *angleRenderTest = static_cast<ANGLERenderTest *>(platform->context); auto *angleRenderTest = static_cast<ANGLERenderTest *>(platform->context);
angleRenderTest->overrideWorkaroundsD3D(workaroundsD3D); angleRenderTest->overrideWorkaroundsD3D(workaroundsD3D);
} }
} // namespace
angle::TraceEventHandle AddTraceEvent(angle::PlatformMethods *platform,
char phase,
const unsigned char *categoryEnabledFlag,
const char *name,
unsigned long long id,
double timestamp,
int numArgs,
const char **argNames,
const unsigned char *argTypes,
const unsigned long long *argValues,
unsigned char flags)
{
ANGLERenderTest *renderTest = static_cast<ANGLERenderTest *>(platform->context);
std::vector<TraceEvent> &buffer = renderTest->getTraceEventBuffer();
buffer.emplace_back(phase, name, timestamp);
return buffer.size();
}
const unsigned char *GetTraceCategoryEnabledFlag(angle::PlatformMethods *platform,
const char *categoryName)
{
constexpr static unsigned char kNonZero = 1;
return &kNonZero;
}
void UpdateTraceEventDuration(angle::PlatformMethods *platform,
const unsigned char *categoryEnabledFlag,
const char *name,
angle::TraceEventHandle eventHandle)
{
// Not implemented.
}
double MonotonicallyIncreasingTime(angle::PlatformMethods *platform)
{
ANGLERenderTest *renderTest = static_cast<ANGLERenderTest *>(platform->context);
return renderTest->getTimer()->getElapsedTime();
}
void DumpTraceEventsToJSONFile(const std::vector<TraceEvent> &traceEvents,
const char *outputFileName)
{
Json::Value eventsValue(Json::arrayValue);
for (const TraceEvent &traceEvent : traceEvents)
{
Json::Value value(Json::objectValue);
std::stringstream phaseName;
phaseName << traceEvent.phase;
unsigned long long microseconds =
static_cast<unsigned long long>(traceEvent.timestamp * 1000.0 * 1000.0);
value["name"] = traceEvent.name;
value["cat"] = "gpu.angle";
value["ph"] = phaseName.str();
value["ts"] = microseconds;
value["pid"] = "ANGLE";
value["tid"] = "CPU";
eventsValue.append(value);
}
Json::Value root(Json::objectValue);
root["traceEvents"] = eventsValue;
std::ofstream outFile;
outFile.open(outputFileName);
Json::StyledWriter styledWrite;
outFile << styledWrite.write(root);
outFile.close();
}
} // anonymous namespace
bool g_OnlyOneRunFrame = false; bool g_OnlyOneRunFrame = false;
bool gEnableTrace = false;
const char *gTraceFile = "ANGLETrace.json";
ANGLEPerfTest::ANGLEPerfTest(const std::string &name, const std::string &suffix) ANGLEPerfTest::ANGLEPerfTest(const std::string &name, const std::string &suffix)
: mName(name), : mName(name),
...@@ -126,6 +209,8 @@ ANGLERenderTest::ANGLERenderTest(const std::string &name, const RenderTestParams ...@@ -126,6 +209,8 @@ ANGLERenderTest::ANGLERenderTest(const std::string &name, const RenderTestParams
mEGLWindow(createEGLWindow(testParams)), mEGLWindow(createEGLWindow(testParams)),
mOSWindow(nullptr) mOSWindow(nullptr)
{ {
// Try to ensure we don't trigger allocation during execution.
mTraceEventBuffer.reserve(kInitialTraceEventBufferSize);
} }
ANGLERenderTest::ANGLERenderTest(const std::string &name, ANGLERenderTest::ANGLERenderTest(const std::string &name,
...@@ -157,6 +242,10 @@ void ANGLERenderTest::SetUp() ...@@ -157,6 +242,10 @@ void ANGLERenderTest::SetUp()
mPlatformMethods.logError = EmptyPlatformMethod; mPlatformMethods.logError = EmptyPlatformMethod;
mPlatformMethods.logWarning = EmptyPlatformMethod; mPlatformMethods.logWarning = EmptyPlatformMethod;
mPlatformMethods.logInfo = EmptyPlatformMethod; mPlatformMethods.logInfo = EmptyPlatformMethod;
mPlatformMethods.addTraceEvent = AddTraceEvent;
mPlatformMethods.getTraceCategoryEnabledFlag = GetTraceCategoryEnabledFlag;
mPlatformMethods.updateTraceEventDuration = UpdateTraceEventDuration;
mPlatformMethods.monotonicallyIncreasingTime = MonotonicallyIncreasingTime;
mPlatformMethods.context = this; mPlatformMethods.context = this;
mEGLWindow->setPlatformMethods(&mPlatformMethods); mEGLWindow->setPlatformMethods(&mPlatformMethods);
...@@ -193,6 +282,12 @@ void ANGLERenderTest::TearDown() ...@@ -193,6 +282,12 @@ void ANGLERenderTest::TearDown()
mEGLWindow->destroyGL(); mEGLWindow->destroyGL();
mOSWindow->destroy(); mOSWindow->destroy();
// Dump trace events to json file.
if (gEnableTrace)
{
DumpTraceEventsToJSONFile(mTraceEventBuffer, gTraceFile);
}
ANGLEPerfTest::TearDown(); ANGLEPerfTest::TearDown();
} }
...@@ -269,6 +364,11 @@ void ANGLERenderTest::setRobustResourceInit(bool enabled) ...@@ -269,6 +364,11 @@ void ANGLERenderTest::setRobustResourceInit(bool enabled)
mEGLWindow->setRobustResourceInit(enabled); mEGLWindow->setRobustResourceInit(enabled);
} }
std::vector<TraceEvent> &ANGLERenderTest::getTraceEventBuffer()
{
return mTraceEventBuffer;
}
// static // static
EGLWindow *ANGLERenderTest::createEGLWindow(const RenderTestParams &testParams) EGLWindow *ANGLERenderTest::createEGLWindow(const RenderTestParams &testParams)
{ {
......
...@@ -37,6 +37,23 @@ class Event; ...@@ -37,6 +37,23 @@ class Event;
ASSERT_EQ(static_cast<GLenum>(expected), static_cast<GLenum>(actual)) ASSERT_EQ(static_cast<GLenum>(expected), static_cast<GLenum>(actual))
#endif // !defined(ASSERT_GLENUM_EQ) #endif // !defined(ASSERT_GLENUM_EQ)
// These are trace events according to Google's "Trace Event Format".
// See https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU
// Only a subset of the properties are implemented.
struct TraceEvent final
{
TraceEvent() {}
TraceEvent(char phaseIn, const char *nameIn, double timestampIn)
: phase(phaseIn), name(nameIn), timestamp(timestampIn)
{
}
char phase = 0;
const char *name = nullptr;
double timestamp = 0;
};
class ANGLEPerfTest : public testing::Test, angle::NonCopyable class ANGLEPerfTest : public testing::Test, angle::NonCopyable
{ {
public: public:
...@@ -48,6 +65,8 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable ...@@ -48,6 +65,8 @@ class ANGLEPerfTest : public testing::Test, angle::NonCopyable
// Called right before timer is stopped to let the test wait for asynchronous operations. // Called right before timer is stopped to let the test wait for asynchronous operations.
virtual void finishTest() {} virtual void finishTest() {}
Timer *getTimer() const { return mTimer; }
protected: protected:
void run(); void run();
void printResult(const std::string &trace, double value, const std::string &units, bool important) const; void printResult(const std::string &trace, double value, const std::string &units, bool important) const;
...@@ -100,6 +119,8 @@ class ANGLERenderTest : public ANGLEPerfTest ...@@ -100,6 +119,8 @@ class ANGLERenderTest : public ANGLEPerfTest
OSWindow *getWindow(); OSWindow *getWindow();
std::vector<TraceEvent> &getTraceEventBuffer();
virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {} virtual void overrideWorkaroundsD3D(angle::WorkaroundsD3D *workaroundsD3D) {}
protected: protected:
...@@ -123,6 +144,9 @@ class ANGLERenderTest : public ANGLEPerfTest ...@@ -123,6 +144,9 @@ class ANGLERenderTest : public ANGLEPerfTest
OSWindow *mOSWindow; OSWindow *mOSWindow;
std::vector<std::string> mExtensionPrerequisites; std::vector<std::string> mExtensionPrerequisites;
angle::PlatformMethods mPlatformMethods; angle::PlatformMethods mPlatformMethods;
// Trace event record that can be output.
std::vector<TraceEvent> mTraceEventBuffer;
}; };
extern bool g_OnlyOneRunFrame; extern bool g_OnlyOneRunFrame;
......
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