Expand VisualBench to a real benching tool
BUG=skia: Review URL: https://codereview.chromium.org/1159213002
This commit is contained in:
parent
038b01c081
commit
7fe8ee4cb7
@ -11,6 +11,7 @@
|
|||||||
'mac_bundle' : 1,
|
'mac_bundle' : 1,
|
||||||
'include_dirs' : [
|
'include_dirs' : [
|
||||||
'../include/gpu',
|
'../include/gpu',
|
||||||
|
'../src/core',
|
||||||
'../src/images',
|
'../src/images',
|
||||||
],
|
],
|
||||||
'sources': [
|
'sources': [
|
||||||
@ -22,6 +23,7 @@
|
|||||||
'flags.gyp:flags_common',
|
'flags.gyp:flags_common',
|
||||||
'images.gyp:images',
|
'images.gyp:images',
|
||||||
'skia_lib.gyp:skia_lib',
|
'skia_lib.gyp:skia_lib',
|
||||||
|
'tools.gyp:proc_stats',
|
||||||
'tools.gyp:timer',
|
'tools.gyp:timer',
|
||||||
'views.gyp:views',
|
'views.gyp:views',
|
||||||
],
|
],
|
||||||
|
@ -48,6 +48,7 @@ public:
|
|||||||
|
|
||||||
void setFullscreen(bool) override;
|
void setFullscreen(bool) override;
|
||||||
void setVsync(bool) override;
|
void setVsync(bool) override;
|
||||||
|
void closeWindow() override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
// Overridden from from SkWindow:
|
// Overridden from from SkWindow:
|
||||||
@ -64,7 +65,9 @@ private:
|
|||||||
void doPaint();
|
void doPaint();
|
||||||
void mapWindowAndWait();
|
void mapWindowAndWait();
|
||||||
|
|
||||||
void closeWindow();
|
// Forcefully closes the window. If a graceful shutdown is desired then call the public
|
||||||
|
// closeWindow method
|
||||||
|
void internalCloseWindow();
|
||||||
void initWindow(int newMSAASampleCount, AttachmentInfo* info);
|
void initWindow(int newMSAASampleCount, AttachmentInfo* info);
|
||||||
|
|
||||||
SkUnixWindow fUnixWindow;
|
SkUnixWindow fUnixWindow;
|
||||||
|
@ -82,6 +82,7 @@ public:
|
|||||||
|
|
||||||
virtual void setFullscreen(bool) {}
|
virtual void setFullscreen(bool) {}
|
||||||
virtual void setVsync(bool) {}
|
virtual void setVsync(bool) {}
|
||||||
|
virtual void closeWindow() {}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
virtual bool onEvent(const SkEvent&);
|
virtual bool onEvent(const SkEvent&);
|
||||||
|
@ -42,10 +42,10 @@ SkOSWindow::SkOSWindow(void*)
|
|||||||
}
|
}
|
||||||
|
|
||||||
SkOSWindow::~SkOSWindow() {
|
SkOSWindow::~SkOSWindow() {
|
||||||
this->closeWindow();
|
this->internalCloseWindow();
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkOSWindow::closeWindow() {
|
void SkOSWindow::internalCloseWindow() {
|
||||||
if (fUnixWindow.fDisplay) {
|
if (fUnixWindow.fDisplay) {
|
||||||
this->detach();
|
this->detach();
|
||||||
SkASSERT(fUnixWindow.fGc);
|
SkASSERT(fUnixWindow.fGc);
|
||||||
@ -61,7 +61,7 @@ void SkOSWindow::closeWindow() {
|
|||||||
|
|
||||||
void SkOSWindow::initWindow(int requestedMSAASampleCount, AttachmentInfo* info) {
|
void SkOSWindow::initWindow(int requestedMSAASampleCount, AttachmentInfo* info) {
|
||||||
if (fMSAASampleCount != requestedMSAASampleCount) {
|
if (fMSAASampleCount != requestedMSAASampleCount) {
|
||||||
this->closeWindow();
|
this->internalCloseWindow();
|
||||||
}
|
}
|
||||||
// presence of fDisplay means we already have a window
|
// presence of fDisplay means we already have a window
|
||||||
if (fUnixWindow.fDisplay) {
|
if (fUnixWindow.fDisplay) {
|
||||||
@ -461,7 +461,6 @@ void SkOSWindow::setFullscreen(bool setFullscreen) {
|
|||||||
if (NULL == dsp) {
|
if (NULL == dsp) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Window win = fUnixWindow.fWin;
|
|
||||||
|
|
||||||
// Full screen
|
// Full screen
|
||||||
Atom wm_state = XInternAtom(dsp, "_NET_WM_STATE", False);
|
Atom wm_state = XInternAtom(dsp, "_NET_WM_STATE", False);
|
||||||
@ -470,7 +469,7 @@ void SkOSWindow::setFullscreen(bool setFullscreen) {
|
|||||||
XEvent evt;
|
XEvent evt;
|
||||||
sk_bzero(&evt, sizeof(evt));
|
sk_bzero(&evt, sizeof(evt));
|
||||||
evt.type = ClientMessage;
|
evt.type = ClientMessage;
|
||||||
evt.xclient.window = win;
|
evt.xclient.window = fUnixWindow.fWin;
|
||||||
evt.xclient.message_type = wm_state;
|
evt.xclient.message_type = wm_state;
|
||||||
evt.xclient.format = 32;
|
evt.xclient.format = 32;
|
||||||
evt.xclient.data.l[0] = setFullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
evt.xclient.data.l[0] = setFullscreen ? _NET_WM_STATE_ADD : _NET_WM_STATE_REMOVE;
|
||||||
@ -488,6 +487,24 @@ void SkOSWindow::setVsync(bool vsync) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void SkOSWindow::closeWindow() {
|
||||||
|
Display* dsp = fUnixWindow.fDisplay;
|
||||||
|
if (NULL == dsp) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
XEvent evt;
|
||||||
|
sk_bzero(&evt, sizeof(evt));
|
||||||
|
evt.type = ClientMessage;
|
||||||
|
evt.xclient.message_type = XInternAtom(dsp, "WM_PROTOCOLS", true);
|
||||||
|
evt.xclient.window = fUnixWindow.fWin;
|
||||||
|
evt.xclient.format = 32;
|
||||||
|
evt.xclient.data.l[0] = XInternAtom(dsp, "WM_DELETE_WINDOW", false);
|
||||||
|
evt.xclient.data.l[1] = CurrentTime;
|
||||||
|
|
||||||
|
XSendEvent(dsp, fUnixWindow.fWin, false, NoEventMask, &evt);
|
||||||
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
void SkEvent::SignalNonEmptyQueue() {
|
void SkEvent::SignalNonEmptyQueue() {
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "VisualBench.h"
|
#include "VisualBench.h"
|
||||||
|
|
||||||
|
#include "ProcStats.h"
|
||||||
#include "SkApplication.h"
|
#include "SkApplication.h"
|
||||||
#include "SkCanvas.h"
|
#include "SkCanvas.h"
|
||||||
#include "SkCommandLineFlags.h"
|
#include "SkCommandLineFlags.h"
|
||||||
@ -18,35 +19,49 @@
|
|||||||
#include "SkImageDecoder.h"
|
#include "SkImageDecoder.h"
|
||||||
#include "SkOSFile.h"
|
#include "SkOSFile.h"
|
||||||
#include "SkStream.h"
|
#include "SkStream.h"
|
||||||
#include "Timer.h"
|
#include "Stats.h"
|
||||||
#include "gl/GrGLInterface.h"
|
#include "gl/GrGLInterface.h"
|
||||||
|
|
||||||
__SK_FORCE_IMAGE_DECODER_LINKING;
|
__SK_FORCE_IMAGE_DECODER_LINKING;
|
||||||
|
|
||||||
|
DEFINE_int32(gpuFrameLag, 5, "Overestimate of maximum number of frames GPU allows to lag.");
|
||||||
|
DEFINE_int32(samples, 10, "Number of times to render each skp.");
|
||||||
|
DEFINE_int32(loops, 5, "Number of times to time.");
|
||||||
|
DEFINE_int32(msaa, 0, "Number of msaa samples.");
|
||||||
|
|
||||||
|
static SkString humanize(double ms) {
|
||||||
|
if (FLAGS_verbose) {
|
||||||
|
return SkStringPrintf("%llu", (uint64_t)(ms*1e6));
|
||||||
|
}
|
||||||
|
return HumanizeMs(ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define HUMANIZE(time) humanize(time).c_str()
|
||||||
|
|
||||||
VisualBench::VisualBench(void* hwnd, int argc, char** argv)
|
VisualBench::VisualBench(void* hwnd, int argc, char** argv)
|
||||||
: INHERITED(hwnd)
|
: INHERITED(hwnd)
|
||||||
, fCurrentLoops(1)
|
, fLoop(0)
|
||||||
, fCurrentPicture(0)
|
, fCurrentPicture(0)
|
||||||
, fCurrentFrame(0) {
|
, fCurrentSample(0)
|
||||||
|
, fState(kPreWarm_State) {
|
||||||
SkCommandLineFlags::Parse(argc, argv);
|
SkCommandLineFlags::Parse(argc, argv);
|
||||||
|
|
||||||
|
// load all SKPs
|
||||||
SkTArray<SkString> skps;
|
SkTArray<SkString> skps;
|
||||||
for (int i = 0; i < FLAGS_skps.count(); i++) {
|
for (int i = 0; i < FLAGS_skps.count(); i++) {
|
||||||
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
|
if (SkStrEndsWith(FLAGS_skps[i], ".skp")) {
|
||||||
skps.push_back() = FLAGS_skps[i];
|
skps.push_back() = FLAGS_skps[i];
|
||||||
|
fTimings.push_back().fName = FLAGS_skps[i];
|
||||||
} else {
|
} else {
|
||||||
SkOSFile::Iter it(FLAGS_skps[i], ".skp");
|
SkOSFile::Iter it(FLAGS_skps[i], ".skp");
|
||||||
SkString path;
|
SkString path;
|
||||||
while (it.next(&path)) {
|
while (it.next(&path)) {
|
||||||
skps.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
|
skps.push_back() = SkOSPath::Join(FLAGS_skps[0], path.c_str());
|
||||||
|
fTimings.push_back().fName = path.c_str();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
this->setTitle();
|
|
||||||
this->setupBackend();
|
|
||||||
|
|
||||||
// Load picture for playback
|
|
||||||
for (int i = 0; i < skps.count(); i++) {
|
for (int i = 0; i < skps.count(); i++) {
|
||||||
SkFILEStream stream(skps[i].c_str());
|
SkFILEStream stream(skps[i].c_str());
|
||||||
if (stream.isValid()) {
|
if (stream.isValid()) {
|
||||||
@ -55,6 +70,13 @@ VisualBench::VisualBench(void* hwnd, int argc, char** argv)
|
|||||||
SkDebugf("couldn't load picture at \"path\"\n", skps[i].c_str());
|
SkDebugf("couldn't load picture at \"path\"\n", skps[i].c_str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (fPictures.empty()) {
|
||||||
|
SkDebugf("no valid skps found\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->setTitle();
|
||||||
|
this->setupBackend();
|
||||||
}
|
}
|
||||||
|
|
||||||
VisualBench::~VisualBench() {
|
VisualBench::~VisualBench() {
|
||||||
@ -79,7 +101,7 @@ bool VisualBench::setupBackend() {
|
|||||||
this->setVisibleP(true);
|
this->setVisibleP(true);
|
||||||
this->setClipToBounds(false);
|
this->setClipToBounds(false);
|
||||||
|
|
||||||
if (!this->attach(kNativeGL_BackEndType, 0 /*msaa*/, &fAttachmentInfo)) {
|
if (!this->attach(kNativeGL_BackEndType, FLAGS_msaa, &fAttachmentInfo)) {
|
||||||
SkDebugf("Not possible to create backend.\n");
|
SkDebugf("Not possible to create backend.\n");
|
||||||
INHERITED::detach();
|
INHERITED::detach();
|
||||||
return false;
|
return false;
|
||||||
@ -87,7 +109,11 @@ bool VisualBench::setupBackend() {
|
|||||||
|
|
||||||
this->setFullscreen(true);
|
this->setFullscreen(true);
|
||||||
this->setVsync(false);
|
this->setVsync(false);
|
||||||
|
this->resetContext();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualBench::resetContext() {
|
||||||
fInterface.reset(GrGLCreateNativeInterface());
|
fInterface.reset(GrGLCreateNativeInterface());
|
||||||
SkASSERT(fInterface);
|
SkASSERT(fInterface);
|
||||||
|
|
||||||
@ -97,26 +123,84 @@ bool VisualBench::setupBackend() {
|
|||||||
|
|
||||||
// setup rendertargets
|
// setup rendertargets
|
||||||
this->setupRenderTarget();
|
this->setupRenderTarget();
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualBench::setupRenderTarget() {
|
void VisualBench::setupRenderTarget() {
|
||||||
fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fContext));
|
fRenderTarget.reset(this->renderTarget(fAttachmentInfo, fInterface, fContext));
|
||||||
}
|
}
|
||||||
|
|
||||||
void VisualBench::draw(SkCanvas* canvas) {
|
inline void VisualBench::renderFrame(SkCanvas* canvas) {
|
||||||
fCurrentFrame++;
|
canvas->drawPicture(fPictures[fCurrentPicture]);
|
||||||
WallTimer timer;
|
|
||||||
timer.start();
|
|
||||||
for (int i = 0; i < fCurrentLoops; i++) {
|
|
||||||
canvas->drawPicture(fPictures[fCurrentPicture]);
|
|
||||||
}
|
|
||||||
// in case we have queued drawing calls
|
|
||||||
fContext->flush();
|
fContext->flush();
|
||||||
INHERITED::present();
|
INHERITED::present();
|
||||||
timer.end();
|
}
|
||||||
|
|
||||||
SkDebugf("%s\n", HumanizeMs(timer.fWall).c_str());
|
void VisualBench::printStats() {
|
||||||
|
const SkTArray<double>& measurements = fTimings[fCurrentPicture].fMeasurements;
|
||||||
|
if (FLAGS_verbose) {
|
||||||
|
for (int i = 0; i < measurements.count(); i++) {
|
||||||
|
SkDebugf("%s ", HUMANIZE(measurements[i]));
|
||||||
|
}
|
||||||
|
SkDebugf("%s\n", fTimings[fCurrentPicture].fName.c_str());
|
||||||
|
} else {
|
||||||
|
SkASSERT(measurements.count());
|
||||||
|
Stats stats(measurements.begin(), measurements.count());
|
||||||
|
const double stdDevPercent = 100 * sqrt(stats.var) / stats.mean;
|
||||||
|
SkDebugf("%4d/%-4dMB\t%s\t%s\t%s\t%s\t%.0f%%\t%s\n",
|
||||||
|
sk_tools::getCurrResidentSetSizeMB(),
|
||||||
|
sk_tools::getMaxResidentSetSizeMB(),
|
||||||
|
HUMANIZE(stats.min),
|
||||||
|
HUMANIZE(stats.median),
|
||||||
|
HUMANIZE(stats.mean),
|
||||||
|
HUMANIZE(stats.max),
|
||||||
|
stdDevPercent,
|
||||||
|
fTimings[fCurrentPicture].fName.c_str());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualBench::timePicture(SkCanvas* canvas) {
|
||||||
|
this->renderFrame(canvas);
|
||||||
|
switch (fState) {
|
||||||
|
case kPreWarm_State: {
|
||||||
|
if (fCurrentSample >= FLAGS_gpuFrameLag) {
|
||||||
|
// TODO we currently time across all frames to make sure we capture all GPU work
|
||||||
|
// We should also rendering an empty SKP to get a baseline to subtract from
|
||||||
|
// our timing
|
||||||
|
fState = kTiming_State;
|
||||||
|
fCurrentSample -= FLAGS_gpuFrameLag;
|
||||||
|
fTimer.start();
|
||||||
|
} else {
|
||||||
|
fCurrentSample++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case kTiming_State: {
|
||||||
|
if (fCurrentSample >= FLAGS_samples) {
|
||||||
|
fTimer.end();
|
||||||
|
fTimings[fCurrentPicture].fMeasurements.push_back(fTimer.fWall / FLAGS_samples);
|
||||||
|
this->resetContext();
|
||||||
|
fTimer = WallTimer();
|
||||||
|
fState = kPreWarm_State;
|
||||||
|
fCurrentSample = 0;
|
||||||
|
if (fLoop++ > FLAGS_loops) {
|
||||||
|
this->printStats();
|
||||||
|
fCurrentPicture++;
|
||||||
|
fLoop = 0;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
fCurrentSample++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void VisualBench::draw(SkCanvas* canvas) {
|
||||||
|
if (fCurrentPicture < fPictures.count()) {
|
||||||
|
this->timePicture(canvas);
|
||||||
|
} else {
|
||||||
|
this->closeWindow();
|
||||||
|
}
|
||||||
|
|
||||||
// Invalidate the window to force a redraw. Poor man's animation mechanism.
|
// Invalidate the window to force a redraw. Poor man's animation mechanism.
|
||||||
this->inval(NULL);
|
this->inval(NULL);
|
||||||
|
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "SkPicture.h"
|
#include "SkPicture.h"
|
||||||
#include "SkSurface.h"
|
#include "SkSurface.h"
|
||||||
|
#include "Timer.h"
|
||||||
#include "gl/SkGLContext.h"
|
#include "gl/SkGLContext.h"
|
||||||
|
|
||||||
class GrContext;
|
class GrContext;
|
||||||
@ -38,13 +39,30 @@ protected:
|
|||||||
private:
|
private:
|
||||||
void setTitle();
|
void setTitle();
|
||||||
bool setupBackend();
|
bool setupBackend();
|
||||||
|
void resetContext();
|
||||||
void setupRenderTarget();
|
void setupRenderTarget();
|
||||||
bool onHandleChar(SkUnichar unichar) override;
|
bool onHandleChar(SkUnichar unichar) override;
|
||||||
|
void printStats();
|
||||||
|
inline void timePicture(SkCanvas*);
|
||||||
|
inline void renderFrame(SkCanvas*);
|
||||||
|
|
||||||
int fCurrentLoops;
|
struct Timing {
|
||||||
|
SkString fName;
|
||||||
|
SkTArray<double> fMeasurements;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum State {
|
||||||
|
kPreWarm_State,
|
||||||
|
kTiming_State,
|
||||||
|
};
|
||||||
|
|
||||||
|
int fLoop;
|
||||||
int fCurrentPicture;
|
int fCurrentPicture;
|
||||||
int fCurrentFrame;
|
int fCurrentSample;
|
||||||
|
SkTArray<Timing> fTimings;
|
||||||
SkTArray<SkPicture*> fPictures;
|
SkTArray<SkPicture*> fPictures;
|
||||||
|
WallTimer fTimer;
|
||||||
|
State fState;
|
||||||
|
|
||||||
// support framework
|
// support framework
|
||||||
SkAutoTUnref<SkSurface> fSurface;
|
SkAutoTUnref<SkSurface> fSurface;
|
||||||
|
Loading…
Reference in New Issue
Block a user