Breakdown profile time by command type in the overview pane
https://codereview.appspot.com/6851073/ git-svn-id: http://skia.googlecode.com/svn/trunk@6492 2bbb7eff-a529-9590-31e7-b0007b416f81
This commit is contained in:
parent
e0d44ff614
commit
8a1cdaece7
@ -9,9 +9,7 @@
|
||||
#include "SkGraphics.h"
|
||||
#include "SkImageDecoder.h"
|
||||
#include <QListWidgetItem>
|
||||
#include "PictureBenchmark.h"
|
||||
#include "PictureRenderer.h"
|
||||
#include "SkBenchLogger.h"
|
||||
#include "SkPictureRecord.h"
|
||||
#include "SkPicturePlayback.h"
|
||||
#include "BenchTimer.h"
|
||||
@ -138,21 +136,36 @@ public:
|
||||
, fCurCommand(0)
|
||||
, fOffsets(offsets) {
|
||||
fTimes.setCount(fOffsets.count());
|
||||
for (int i = 0; i < fOffsets.count(); ++i) {
|
||||
fTimes[i] = 0;
|
||||
fTypeTimes.setCount(LAST_DRAWTYPE_ENUM+1);
|
||||
this->resetTimes();
|
||||
}
|
||||
|
||||
void resetTimes() {
|
||||
for (int i = 0; i < fOffsets.count(); ++i) {
|
||||
fTimes[i] = 0.0;
|
||||
}
|
||||
for (int i = 0; i < fTypeTimes.count(); ++i) {
|
||||
fTypeTimes[i] = 0.0f;
|
||||
}
|
||||
fTot = 0.0;
|
||||
}
|
||||
|
||||
int count() const { return fTimes.count(); }
|
||||
|
||||
double time(int index) const { return fTimes[index] / fTot; }
|
||||
|
||||
const SkTDArray<double>* typeTimes() const { return &fTypeTimes; }
|
||||
|
||||
double totTime() const { return fTot; }
|
||||
|
||||
protected:
|
||||
BenchTimer fTimer;
|
||||
SkTDArray<size_t> fOffsets; // offset in the SkPicture for each command
|
||||
SkTDArray<double> fTimes; // sum of time consumed for each command
|
||||
SkTDArray<double> fTypeTimes; // sum of time consumed for each type of command (e.g., drawPath)
|
||||
double fTot; // total of all times in 'fTimes'
|
||||
size_t fCurOffset;
|
||||
int fCurType;
|
||||
int fCurCommand; // the current command being executed/timed
|
||||
|
||||
virtual void preDraw(size_t offset, int type) {
|
||||
@ -166,6 +179,15 @@ protected:
|
||||
}
|
||||
|
||||
fCurOffset = offset;
|
||||
fCurType = type;
|
||||
// The SkDebugCanvas doesn't recognize these types. This class needs to
|
||||
// convert or else we'll wind up with a mismatch between the type counts
|
||||
// the debugger displays and the profile times.
|
||||
if (DRAW_POS_TEXT_TOP_BOTTOM == type) {
|
||||
fCurType = DRAW_POS_TEXT;
|
||||
} else if (DRAW_POS_TEXT_H_TOP_BOTTOM == type) {
|
||||
fCurType = DRAW_POS_TEXT_H;
|
||||
}
|
||||
|
||||
fTimer.start();
|
||||
}
|
||||
@ -174,13 +196,16 @@ protected:
|
||||
fTimer.end();
|
||||
|
||||
SkASSERT(offset == fCurOffset);
|
||||
SkASSERT(fCurType <= LAST_DRAWTYPE_ENUM);
|
||||
|
||||
#if defined(SK_BUILD_FOR_WIN32)
|
||||
// CPU timer doesn't work well on Windows
|
||||
fTimes[fCurCommand] += fTimer.fWall;
|
||||
fTypeTimes[fCurType] += fTimer.fWall;
|
||||
fTot += fTimer.fWall;
|
||||
#else
|
||||
fTimes[fCurCommand] += fTimer.fCpu;
|
||||
fTypeTimes[fCurType] += fTimer.fCpu;
|
||||
fTot += fTimer.fCpu;
|
||||
#endif
|
||||
}
|
||||
@ -231,15 +256,59 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void resetTimes() { ((SkTimedPicturePlayback*) fPlayback)->resetTimes(); }
|
||||
|
||||
int count() const { return ((SkTimedPicturePlayback*) fPlayback)->count(); }
|
||||
|
||||
// return the fraction of the total time this command consumed
|
||||
double time(int index) const { return ((SkTimedPicturePlayback*) fPlayback)->time(index); }
|
||||
|
||||
const SkTDArray<double>* typeTimes() const { return ((SkTimedPicturePlayback*) fPlayback)->typeTimes(); }
|
||||
|
||||
double totTime() const { return ((SkTimedPicturePlayback*) fPlayback)->totTime(); }
|
||||
|
||||
private:
|
||||
// disallow default ctor b.c. we don't have a good way to setup the fPlayback ptr
|
||||
SkTimedPicture();
|
||||
// disallow the copy ctor - enabling would require copying code from SkPicture
|
||||
SkTimedPicture(const SkTimedPicture& src);
|
||||
|
||||
typedef SkPicture INHERITED;
|
||||
};
|
||||
|
||||
// This is a simplification of PictureBenchmark's run with the addition of
|
||||
// clearing of the times after the first pass (in resetTimes)
|
||||
void SkDebuggerGUI::run(SkTimedPicture* pict,
|
||||
sk_tools::PictureRenderer* renderer,
|
||||
int repeats) {
|
||||
SkASSERT(pict);
|
||||
if (NULL == pict) {
|
||||
return;
|
||||
}
|
||||
|
||||
SkASSERT(renderer != NULL);
|
||||
if (NULL == renderer) {
|
||||
return;
|
||||
}
|
||||
|
||||
renderer->init(pict);
|
||||
|
||||
renderer->setup();
|
||||
renderer->render(NULL);
|
||||
renderer->resetState();
|
||||
|
||||
// We throw this away the first batch of times to remove first time effects (such as paging in this program)
|
||||
pict->resetTimes();
|
||||
|
||||
for (int i = 0; i < repeats; ++i) {
|
||||
renderer->setup();
|
||||
renderer->render(NULL);
|
||||
renderer->resetState();
|
||||
}
|
||||
|
||||
renderer->end();
|
||||
}
|
||||
|
||||
void SkDebuggerGUI::actionProfile() {
|
||||
// In order to profile we pass the command offsets (that were read-in
|
||||
// in loadPicture by the SkOffsetPicture) to an SkTimedPlaybackPicture.
|
||||
@ -263,24 +332,21 @@ void SkDebuggerGUI::actionProfile() {
|
||||
return;
|
||||
}
|
||||
|
||||
sk_tools::PictureBenchmark benchmark;
|
||||
|
||||
// For now this #if allows switching between tiled and simple rendering
|
||||
// modes. Eventually this will be accomplished via the GUI
|
||||
#if 1
|
||||
sk_tools::TiledPictureRenderer* renderer = NULL;
|
||||
|
||||
renderer = SkNEW(sk_tools::TiledPictureRenderer);
|
||||
renderer->setTileWidth(256);
|
||||
renderer->setTileHeight(256);
|
||||
#else
|
||||
sk_tools::SimplePictureRenderer* renderer = NULL;
|
||||
|
||||
renderer = SkNEW(sk_tools::SimplePictureRenderer);
|
||||
#endif
|
||||
|
||||
benchmark.setRepeats(2);
|
||||
benchmark.setRenderer(renderer);
|
||||
benchmark.setTimersToShow(true, false, true, false, false);
|
||||
|
||||
SkBenchLogger logger;
|
||||
|
||||
benchmark.setLogger(&logger);
|
||||
|
||||
benchmark.run(&picture);
|
||||
run(&picture, renderer, 2);
|
||||
|
||||
SkASSERT(picture.count() == fListWidget.count());
|
||||
|
||||
@ -292,6 +358,8 @@ void SkDebuggerGUI::actionProfile() {
|
||||
|
||||
item->setData(Qt::UserRole + 4, 100.0*temp);
|
||||
}
|
||||
|
||||
setupOverviewText(picture.typeTimes(), picture.totTime());
|
||||
}
|
||||
|
||||
void SkDebuggerGUI::actionCancel() {
|
||||
@ -825,6 +893,11 @@ public:
|
||||
}
|
||||
|
||||
private:
|
||||
// disallow default ctor b.c. we don't have a good way to setup the fPlayback ptr
|
||||
SkOffsetPicture();
|
||||
// disallow the copy ctor - enabling would require copying code from SkPicture
|
||||
SkOffsetPicture(const SkOffsetPicture& src);
|
||||
|
||||
typedef SkPicture INHERITED;
|
||||
};
|
||||
|
||||
@ -845,7 +918,7 @@ void SkDebuggerGUI::loadPicture(const SkString& fileName) {
|
||||
SkSafeUnref(picture);
|
||||
|
||||
// Will this automatically clear out due to nature of refcnt?
|
||||
SkTDArray<SkString*>* commands = fDebugger.getDrawCommands();
|
||||
SkTArray<SkString>* commands = fDebugger.getDrawCommandsAsStrings();
|
||||
|
||||
// If SkPicturePlayback is compiled w/o SK_PICTURE_PROFILING_STUBS
|
||||
// the offset count will always be zero
|
||||
@ -863,6 +936,7 @@ void SkDebuggerGUI::loadPicture(const SkString& fileName) {
|
||||
|
||||
setupListWidget(commands);
|
||||
setupComboBox(commands);
|
||||
setupOverviewText(NULL, 0.0);
|
||||
fInspectorWidget.setDisabled(false);
|
||||
fSettingsWidget.setDisabled(false);
|
||||
fMenuEdit.setDisabled(false);
|
||||
@ -874,23 +948,23 @@ void SkDebuggerGUI::loadPicture(const SkString& fileName) {
|
||||
actionPlay();
|
||||
}
|
||||
|
||||
void SkDebuggerGUI::setupListWidget(SkTDArray<SkString*>* command) {
|
||||
void SkDebuggerGUI::setupListWidget(SkTArray<SkString>* command) {
|
||||
fListWidget.clear();
|
||||
int counter = 0;
|
||||
int indent = 0;
|
||||
for (int i = 0; i < command->count(); i++) {
|
||||
QListWidgetItem *item = new QListWidgetItem();
|
||||
item->setData(Qt::DisplayRole, (*command)[i]->c_str());
|
||||
item->setData(Qt::DisplayRole, (*command)[i].c_str());
|
||||
item->setData(Qt::UserRole + 1, counter++);
|
||||
|
||||
if (0 == strcmp("Restore", (*command)[i]->c_str())) {
|
||||
if (0 == strcmp("Restore", (*command)[i].c_str())) {
|
||||
indent -= 10;
|
||||
}
|
||||
|
||||
item->setData(Qt::UserRole + 3, indent);
|
||||
|
||||
if (0 == strcmp("Save", (*command)[i]->c_str()) ||
|
||||
0 == strcmp("Save Layer", (*command)[i]->c_str())) {
|
||||
if (0 == strcmp("Save", (*command)[i].c_str()) ||
|
||||
0 == strcmp("Save Layer", (*command)[i].c_str())) {
|
||||
indent += 10;
|
||||
}
|
||||
|
||||
@ -900,31 +974,75 @@ void SkDebuggerGUI::setupListWidget(SkTDArray<SkString*>* command) {
|
||||
}
|
||||
}
|
||||
|
||||
void SkDebuggerGUI::setupComboBox(SkTDArray<SkString*>* command) {
|
||||
fFilter.clear();
|
||||
fFilter.addItem("--Filter By Available Commands--");
|
||||
void SkDebuggerGUI::setupOverviewText(const SkTDArray<double>* typeTimes, double totTime) {
|
||||
|
||||
std::map<std::string, int> map;
|
||||
for (int i = 0; i < command->count(); i++) {
|
||||
map[(*command)[i]->c_str()]++;
|
||||
const SkTDArray<SkDrawCommand*>& commands = fDebugger.getDrawCommands();
|
||||
|
||||
SkTDArray<int> counts;
|
||||
counts.setCount(LAST_DRAWTYPE_ENUM+1);
|
||||
for (int i = 0; i < LAST_DRAWTYPE_ENUM+1; ++i) {
|
||||
counts[i] = 0;
|
||||
}
|
||||
|
||||
for (int i = 0; i < commands.count(); i++) {
|
||||
counts[commands[i]->getType()]++;
|
||||
}
|
||||
|
||||
QString overview;
|
||||
int counter = 0;
|
||||
for (std::map<std::string, int>::iterator it = map.begin(); it != map.end();
|
||||
++it) {
|
||||
overview.append((it->first).c_str());
|
||||
overview.append(": ");
|
||||
overview.append(QString::number(it->second));
|
||||
overview.append("<br/>");
|
||||
counter += it->second;
|
||||
fFilter.addItem((it->first).c_str());
|
||||
int total = 0;
|
||||
#ifdef SK_DEBUG
|
||||
double totPercent = 0, tempSum = 0;
|
||||
#endif
|
||||
for (int i = 0; i < LAST_DRAWTYPE_ENUM+1; ++i) {
|
||||
if (0 == counts[i]) {
|
||||
// if there were no commands of this type then they should've consumed no time
|
||||
SkASSERT(NULL == typeTimes || 0.0 == (*typeTimes)[i]);
|
||||
continue;
|
||||
}
|
||||
QString total;
|
||||
total.append("Total Draw Commands: ");
|
||||
total.append(QString::number(counter));
|
||||
total.append("<br/>");
|
||||
overview.insert(0, total);
|
||||
|
||||
overview.append(SkDrawCommand::GetCommandString((DrawType) i));
|
||||
overview.append(": ");
|
||||
overview.append(QString::number(counts[i]));
|
||||
if (NULL != typeTimes) {
|
||||
overview.append(" - ");
|
||||
overview.append(QString::number((*typeTimes)[i], 'f', 1));
|
||||
overview.append("ms");
|
||||
overview.append(" - ");
|
||||
double percent = 100.0*(*typeTimes)[i]/totTime;
|
||||
overview.append(QString::number(percent, 'f', 1));
|
||||
overview.append("%");
|
||||
#ifdef SK_DEBUG
|
||||
totPercent += percent;
|
||||
tempSum += (*typeTimes)[i];
|
||||
#endif
|
||||
}
|
||||
overview.append("<br/>");
|
||||
total += counts[i];
|
||||
}
|
||||
#ifdef SK_DEBUG
|
||||
if (NULL != typeTimes) {
|
||||
SkASSERT(SkScalarNearlyEqual(totPercent, 100.0));
|
||||
SkASSERT(SkScalarNearlyEqual(tempSum, totTime));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (totTime > 0.0) {
|
||||
overview.append("Total Time: ");
|
||||
overview.append(QString::number(totTime, 'f', 2));
|
||||
overview.append("ms");
|
||||
#ifdef SK_DEBUG
|
||||
overview.append(" ");
|
||||
overview.append(QString::number(totPercent));
|
||||
overview.append("% ");
|
||||
#endif
|
||||
overview.append("<br/>");
|
||||
}
|
||||
|
||||
QString totalStr;
|
||||
totalStr.append("Total Draw Commands: ");
|
||||
totalStr.append(QString::number(total));
|
||||
totalStr.append("<br/>");
|
||||
overview.insert(0, totalStr);
|
||||
|
||||
overview.append("<br/>");
|
||||
overview.append("SkPicture Width: ");
|
||||
@ -935,6 +1053,21 @@ void SkDebuggerGUI::setupComboBox(SkTDArray<SkString*>* command) {
|
||||
overview.append(QString::number(fDebugger.pictureHeight()));
|
||||
overview.append("px");
|
||||
fInspectorWidget.setText(overview, SkInspectorWidget::kOverview_TabType);
|
||||
}
|
||||
|
||||
void SkDebuggerGUI::setupComboBox(SkTArray<SkString>* command) {
|
||||
fFilter.clear();
|
||||
fFilter.addItem("--Filter By Available Commands--");
|
||||
|
||||
std::map<std::string, int> map;
|
||||
for (int i = 0; i < command->count(); i++) {
|
||||
map[(*command)[i].c_str()]++;
|
||||
}
|
||||
|
||||
for (std::map<std::string, int>::iterator it = map.begin(); it != map.end();
|
||||
++it) {
|
||||
fFilter.addItem((it->first).c_str());
|
||||
}
|
||||
|
||||
// NOTE(chudy): Makes first item unselectable.
|
||||
QStandardItemModel* model = qobject_cast<QStandardItemModel*>(
|
||||
|
@ -35,6 +35,11 @@
|
||||
#include <QtGui/QMenuBar>
|
||||
#include <vector>
|
||||
|
||||
class SkTimedPicture;
|
||||
namespace sk_tools {
|
||||
class PictureRenderer;
|
||||
}
|
||||
|
||||
/** \class SkDebuggerGUI
|
||||
|
||||
Container for the UI and it's functions.
|
||||
@ -286,18 +291,31 @@ private:
|
||||
/**
|
||||
Populates the list widget with the vector of strings passed in.
|
||||
*/
|
||||
void setupListWidget(SkTDArray<SkString*>* command);
|
||||
void setupListWidget(SkTArray<SkString>* command);
|
||||
|
||||
/**
|
||||
Populates the combo box widget with the vector of strings passed in.
|
||||
*/
|
||||
void setupComboBox(SkTDArray<SkString*>* command);
|
||||
void setupComboBox(SkTArray<SkString>* command);
|
||||
|
||||
/**
|
||||
Fills in the overview pane with text
|
||||
*/
|
||||
void setupOverviewText(const SkTDArray<double>* typeTimes, double totTime);
|
||||
|
||||
/**
|
||||
Updates the directory widget with the latest directory path stored in
|
||||
the global class variable fPath.
|
||||
*/
|
||||
void setupDirectoryWidget();
|
||||
|
||||
/**
|
||||
Render the supplied picture several times tracking the time consumed
|
||||
by each command.
|
||||
*/
|
||||
void run(SkTimedPicture* pict,
|
||||
sk_tools::PictureRenderer* renderer,
|
||||
int repeats);
|
||||
};
|
||||
|
||||
#endif // SKDEBUGGERUI_H
|
||||
|
@ -142,16 +142,16 @@ bool SkDebugCanvas::getDrawCommandVisibilityAt(int index) {
|
||||
return commandVector[index]->isVisible();
|
||||
}
|
||||
|
||||
SkTDArray <SkDrawCommand*> SkDebugCanvas::getDrawCommands() {
|
||||
const SkTDArray <SkDrawCommand*>& SkDebugCanvas::getDrawCommands() const {
|
||||
return commandVector;
|
||||
}
|
||||
|
||||
// TODO(chudy): Free command string memory.
|
||||
SkTDArray<SkString*>* SkDebugCanvas::getDrawCommandsAsStrings() {
|
||||
SkTDArray<SkString*>* commandString = new SkTDArray<SkString*>();
|
||||
SkTArray<SkString>* SkDebugCanvas::getDrawCommandsAsStrings() const {
|
||||
SkTArray<SkString>* commandString = new SkTArray<SkString>(commandVector.count());
|
||||
if (!commandVector.isEmpty()) {
|
||||
for (int i = 0; i < commandVector.count(); i ++) {
|
||||
commandString->push(new SkString(commandVector[i]->toString()));
|
||||
commandString->push_back() = commandVector[i]->toString();
|
||||
}
|
||||
}
|
||||
return commandString;
|
||||
|
@ -13,7 +13,7 @@
|
||||
#include "SkCanvas.h"
|
||||
#include "SkDrawCommand.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkTDArray.h"
|
||||
#include "SkTArray.h"
|
||||
#include "SkString.h"
|
||||
|
||||
class SkDebugCanvas : public SkCanvas {
|
||||
@ -85,12 +85,12 @@ public:
|
||||
/**
|
||||
Returns the vector of draw commands
|
||||
*/
|
||||
SkTDArray<SkDrawCommand*> getDrawCommands();
|
||||
const SkTDArray<SkDrawCommand*>& getDrawCommands() const;
|
||||
|
||||
/**
|
||||
* Returns the string vector of draw commands
|
||||
*/
|
||||
SkTDArray<SkString*>* getDrawCommandsAsStrings();
|
||||
SkTArray<SkString>* getDrawCommandsAsStrings() const;
|
||||
|
||||
/**
|
||||
Returns length of draw command vector.
|
||||
|
@ -12,6 +12,7 @@
|
||||
|
||||
#include "SkDebugCanvas.h"
|
||||
#include "SkPicture.h"
|
||||
#include "SkTArray.h"
|
||||
|
||||
class SkDebugger {
|
||||
public:
|
||||
@ -41,10 +42,14 @@ public:
|
||||
fDebugCanvas->toggleCommand(index, isVisible);
|
||||
}
|
||||
|
||||
SkTDArray<SkString*>* getDrawCommands() {
|
||||
SkTArray<SkString>* getDrawCommandsAsStrings() {
|
||||
return fDebugCanvas->getDrawCommandsAsStrings();
|
||||
}
|
||||
|
||||
const SkTDArray<SkDrawCommand*>& getDrawCommands() const {
|
||||
return fDebugCanvas->getDrawCommands();
|
||||
}
|
||||
|
||||
void highlightCurrentCommand(bool on) {
|
||||
fDebugCanvas->toggleFilter(on);
|
||||
}
|
||||
|
@ -37,13 +37,14 @@ public:
|
||||
virtual void execute(SkCanvas* canvas)=0;
|
||||
DrawType getType() { return fDrawType; };
|
||||
|
||||
static const char* GetCommandString(DrawType type);
|
||||
|
||||
protected:
|
||||
DrawType fDrawType;
|
||||
SkTDArray<SkString*> fInfo;
|
||||
|
||||
private:
|
||||
bool fVisible;
|
||||
static const char* GetCommandString(DrawType type);
|
||||
};
|
||||
|
||||
class Restore : public SkDrawCommand {
|
||||
|
@ -109,14 +109,6 @@
|
||||
'../debugger/QT/SkRasterWidget.h',
|
||||
'../debugger/QT/SkRasterWidget.cpp',
|
||||
|
||||
'../tools/PictureBenchmark.h',
|
||||
'../tools/PictureBenchmark.cpp',
|
||||
|
||||
'../bench/SkBenchLogger.h',
|
||||
'../bench/SkBenchLogger.cpp',
|
||||
'../bench/TimerData.h',
|
||||
'../bench/TimerData.cpp',
|
||||
|
||||
# To update this file edit SkIcons.qrc and rerun rcc to generate cpp
|
||||
'../debugger/QT/qrc_SkIcons.cpp',
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user