Provide an option to bench drawing individual tiles in bench_pictures.
authorscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 13 Dec 2012 22:09:28 +0000 (22:09 +0000)
committerscroggo@google.com <scroggo@google.com@2bbb7eff-a529-9590-31e7-b0007b416f81>
Thu, 13 Dec 2012 22:09:28 +0000 (22:09 +0000)
Provides output like the following:
running bench [1236 12045] androidpolice.skp
  tile_256x256: tile [0,0] out of [5,48]: msecs =   1.00
  tile_256x256: tile [1,0] out of [5,48]: msecs =   1.50
  tile_256x256: tile [2,0] out of [5,48]: msecs =   1.00
  tile_256x256: tile [3,0] out of [5,48]: msecs =   1.50
  tile_256x256: tile [4,0] out of [5,48]: msecs =   2.50
  tile_256x256: tile [0,1] out of [5,48]: msecs =   2.00
  tile_256x256: tile [1,1] out of [5,48]: msecs =   3.50
  tile_256x256: tile [2,1] out of [5,48]: msecs =   3.50
  tile_256x256: tile [3,1] out of [5,48]: msecs =   6.00
  tile_256x256: tile [4,1] out of [5,48]: msecs =   2.50
  tile_256x256: tile [0,2] out of [5,48]: msecs =   2.00

BUG=https://code.google.com/p/skia/issues/detail?id=1016

Review URL: https://codereview.appspot.com/6937047

git-svn-id: http://skia.googlecode.com/svn/trunk@6805 2bbb7eff-a529-9590-31e7-b0007b416f81

tools/PictureBenchmark.cpp
tools/PictureBenchmark.h
tools/PictureRenderer.cpp
tools/PictureRenderer.h
tools/bench_pictures_main.cpp

index ca7795f..bdf1306 100644 (file)
@@ -27,6 +27,7 @@ PictureBenchmark::PictureBenchmark()
 , fShowCpuTime(true)
 , fShowTruncatedCpuTime(false)
 , fShowGpuTime(false)
+, fTimeIndividualTiles(false)
 {}
 
 PictureBenchmark::~PictureBenchmark() {
@@ -37,12 +38,9 @@ BenchTimer* PictureBenchmark::setupTimer() {
 #if SK_SUPPORT_GPU
     if (fRenderer != NULL && fRenderer->isUsingGpuDevice()) {
         return SkNEW_ARGS(BenchTimer, (fRenderer->getGLContext()));
-    } else {
-        return SkNEW_ARGS(BenchTimer, (NULL));
     }
-#else
-    return SkNEW_ARGS(BenchTimer, (NULL));
 #endif
+    return SkNEW_ARGS(BenchTimer, (NULL));
 }
 
 void PictureBenchmark::logProgress(const char msg[]) {
@@ -80,29 +78,67 @@ void PictureBenchmark::run(SkPicture* pict) {
     usingGpu = fRenderer->isUsingGpuDevice();
 #endif
 
-    TimerData timerData(fRenderer->getPerIterTimeFormat(), fRenderer->getNormalTimeFormat());
-    for (int i = 0; i < fRepeats; ++i) {
-        fRenderer->setup();
-
-        timer->start();
-        fRenderer->render(NULL);
-        timer->truncatedEnd();
-
-        // Finishes gl context
-        fRenderer->resetState();
-        timer->end();
-
-        timerData.appendTimes(timer, fRepeats - 1 == i);
+    if (fTimeIndividualTiles) {
+        TiledPictureRenderer* tiledRenderer = fRenderer->getTiledRenderer();
+        SkASSERT(tiledRenderer);
+        if (NULL == tiledRenderer) {
+            return;
+        }
+        int xTiles, yTiles;
+        if (!tiledRenderer->tileDimensions(xTiles, yTiles)) {
+            return;
+        }
+
+        // Insert a newline so that each tile is reported on its own line (separate from the line
+        // that describes the skp being run).
+        this->logProgress("\n");
+
+        int x, y;
+        while (tiledRenderer->nextTile(x, y)) {
+            TimerData timerData(tiledRenderer->getPerIterTimeFormat(),
+                                tiledRenderer->getNormalTimeFormat());
+            for (int i = 0; i < fRepeats; ++i) {
+                timer->start();
+                tiledRenderer->drawCurrentTile();
+                timer->truncatedEnd();
+                tiledRenderer->resetState();
+                timer->end();
+                timerData.appendTimes(timer, fRepeats - 1 == i);
+            }
+            SkString configName = tiledRenderer->getConfigName();
+            configName.appendf(": tile [%i,%i] out of [%i,%i]", x, y, xTiles, yTiles);
+            SkString result = timerData.getResult(fLogPerIter, fPrintMin, fRepeats,
+                                                  configName.c_str(), fShowWallTime,
+                                                  fShowTruncatedWallTime, fShowCpuTime,
+                                                  fShowTruncatedCpuTime, usingGpu && fShowGpuTime);
+            result.append("\n");
+            this->logProgress(result.c_str());
+        }
+    } else {
+        TimerData timerData(fRenderer->getPerIterTimeFormat(), fRenderer->getNormalTimeFormat());
+        for (int i = 0; i < fRepeats; ++i) {
+            fRenderer->setup();
+
+            timer->start();
+            fRenderer->render(NULL);
+            timer->truncatedEnd();
+
+            // Finishes gl context
+            fRenderer->resetState();
+            timer->end();
+
+            timerData.appendTimes(timer, fRepeats - 1 == i);
+        }
+
+        SkString configName = fRenderer->getConfigName();
+        SkString result = timerData.getResult(fLogPerIter, fPrintMin, fRepeats,
+                                              configName.c_str(), fShowWallTime,
+                                              fShowTruncatedWallTime, fShowCpuTime,
+                                              fShowTruncatedCpuTime, usingGpu && fShowGpuTime);
+        result.append("\n");
+        this->logProgress(result.c_str());
     }
 
-    SkString configName = fRenderer->getConfigName();
-    SkString result = timerData.getResult(fLogPerIter, fPrintMin, fRepeats,
-                                          configName.c_str(), fShowWallTime, fShowTruncatedWallTime,
-                                          fShowCpuTime, fShowTruncatedCpuTime,
-                                          usingGpu && fShowGpuTime);
-    result.append("\n");
-    this->logProgress(result.c_str());
-
     fRenderer->end();
     SkDELETE(timer);
 }
index 0ab5ff9..af81f69 100644 (file)
@@ -24,12 +24,25 @@ public:
 
     ~PictureBenchmark();
 
+    /**
+     * Draw the provided SkPicture fRepeats times while collecting timing data, and log the output
+     * via fLogger.
+     */
     void run(SkPicture* pict);
 
     void setRepeats(int repeats) {
         fRepeats = repeats;
     }
 
+    /**
+     * If true, tells run to log separate timing data for each individual tile. Each tile will be
+     * drawn fRepeats times. Requires the PictureRenderer set by setRenderer to be a
+     * TiledPictureRenderer.
+     */
+    void setTimeIndividualTiles(bool indiv) { fTimeIndividualTiles = true; }
+
+    bool timeIndividualTiles() { return fTimeIndividualTiles; }
+
     PictureRenderer* setRenderer(PictureRenderer*);
 
     void setDeviceType(PictureRenderer::SkDeviceTypes deviceType) {
@@ -63,6 +76,7 @@ private:
     bool             fShowCpuTime;
     bool             fShowTruncatedCpuTime;
     bool             fShowGpuTime;
+    bool             fTimeIndividualTiles;
 
     void logProgress(const char msg[]);
 
index ac5e47c..32c19e8 100644 (file)
@@ -321,7 +321,10 @@ TiledPictureRenderer::TiledPictureRenderer()
     , fTileHeight(kDefaultTileHeight)
     , fTileWidthPercentage(0.0)
     , fTileHeightPercentage(0.0)
-    , fTileMinPowerOf2Width(0) { }
+    , fTileMinPowerOf2Width(0)
+    , fCurrentTileOffset(-1)
+    , fTilesX(0)
+    , fTilesY(0) { }
 
 void TiledPictureRenderer::init(SkPicture* pict) {
     SkASSERT(pict != NULL);
@@ -348,6 +351,10 @@ void TiledPictureRenderer::init(SkPicture* pict) {
     } else {
         this->setupTiles();
     }
+    fCanvas.reset(this->setupCanvas(fTileWidth, fTileHeight));
+    // Initialize to -1 so that the first call to nextTile will set this up to draw tile 0 on the
+    // first call to drawCurrentTile.
+    fCurrentTileOffset = -1;
 }
 
 void TiledPictureRenderer::end() {
@@ -360,8 +367,14 @@ void TiledPictureRenderer::setupTiles() {
     const int width = this->getViewWidth();
     const int height = this->getViewHeight();
 
+    fTilesX = fTilesY = 0;
     for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
+        fTilesY++;
         for (int tile_x_start = 0; tile_x_start < width; tile_x_start += fTileWidth) {
+            if (0 == tile_y_start) {
+                // Only count tiles in the X direction on the first pass.
+                fTilesX++;
+            }
             *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
                                                     SkIntToScalar(tile_y_start),
                                                     SkIntToScalar(fTileWidth),
@@ -370,6 +383,15 @@ void TiledPictureRenderer::setupTiles() {
     }
 }
 
+bool TiledPictureRenderer::tileDimensions(int &x, int &y) {
+    if (fTileRects.count() == 0 || NULL == fPicture) {
+        return false;
+    }
+    x = fTilesX;
+    y = fTilesY;
+    return true;
+}
+
 // The goal of the powers of two tiles is to minimize the amount of wasted tile
 // space in the width-wise direction and then minimize the number of tiles. The
 // constraints are that every tile must have a pixel width that is a power of
@@ -392,8 +414,10 @@ void TiledPictureRenderer::setupPowerOf2Tiles() {
     int num_bits = SkScalarCeilToInt(SkScalarLog2(SkIntToScalar(width)));
     int largest_possible_tile_size = 1 << num_bits;
 
+    fTilesX = fTilesY = 0;
     // The tile height is constant for a particular picture.
     for (int tile_y_start = 0; tile_y_start < height; tile_y_start += fTileHeight) {
+        fTilesY++;
         int tile_x_start = 0;
         int current_width = largest_possible_tile_size;
         // Set fTileWidth to be the width of the widest tile, so that each canvas is large enough
@@ -403,6 +427,10 @@ void TiledPictureRenderer::setupPowerOf2Tiles() {
         while (current_width >= fTileMinPowerOf2Width) {
             // It is very important this is a bitwise AND.
             if (current_width & rounded_value) {
+                if (0 == tile_y_start) {
+                    // Only count tiles in the X direction on the first pass.
+                    fTilesX++;
+                }
                 *fTileRects.append() = SkRect::MakeXYWH(SkIntToScalar(tile_x_start),
                                                         SkIntToScalar(tile_y_start),
                                                         SkIntToScalar(current_width),
@@ -433,21 +461,31 @@ static void DrawTileToCanvas(SkCanvas* canvas, const SkRect& tileRect, T* playba
 
 ///////////////////////////////////////////////////////////////////////////////////////////////
 
+bool TiledPictureRenderer::nextTile(int &i, int &j) {
+    if (++fCurrentTileOffset < fTileRects.count()) {
+        i = fCurrentTileOffset % fTilesX;
+        j = fCurrentTileOffset / fTilesX;
+        return true;
+    }
+    return false;
+}
+
+void TiledPictureRenderer::drawCurrentTile() {
+    SkASSERT(fCurrentTileOffset >= 0 && fCurrentTileOffset < fTileRects.count());
+    DrawTileToCanvas(fCanvas, fTileRects[fCurrentTileOffset], fPicture);
+}
+
 bool TiledPictureRenderer::render(const SkString* path) {
     SkASSERT(fPicture != NULL);
     if (NULL == fPicture) {
         return false;
     }
 
-    // Reuse one canvas for all tiles.
-    SkCanvas* canvas = this->setupCanvas(fTileWidth, fTileHeight);
-    SkAutoUnref aur(canvas);
-
     bool success = true;
     for (int i = 0; i < fTileRects.count(); ++i) {
-        DrawTileToCanvas(canvas, fTileRects[i], fPicture);
+        DrawTileToCanvas(fCanvas, fTileRects[i], fPicture);
         if (NULL != path) {
-            success &= writeAppendNumber(canvas, path, i);
+            success &= writeAppendNumber(fCanvas, path, i);
         }
     }
     return success;
index 99c58e0..284f068 100644 (file)
@@ -33,7 +33,10 @@ class SkThread;
 
 namespace sk_tools {
 
+class TiledPictureRenderer;
+
 class PictureRenderer : public SkRefCnt {
+
 public:
     enum SkDeviceTypes {
         kBitmap_DeviceType,
@@ -97,6 +100,12 @@ public:
      */
     virtual void end();
 
+    /**
+     * If this PictureRenderer is actually a TiledPictureRender, return a pointer to this as a
+     * TiledPictureRender so its methods can be called.
+     */
+    virtual TiledPictureRenderer* getTiledRenderer() { return NULL; }
+
     void resetState();
 
     void setDeviceType(SkDeviceTypes deviceType) {
@@ -320,6 +329,36 @@ public:
         return fTileMinPowerOf2Width;
     }
 
+    virtual TiledPictureRenderer* getTiledRenderer() SK_OVERRIDE { return this; }
+
+    /**
+     * Report the number of tiles in the x and y directions. Must not be called before init.
+     * @param x Output parameter identifying the number of tiles in the x direction.
+     * @param y Output parameter identifying the number of tiles in the y direction.
+     * @return True if the tiles have been set up, and x and y are meaningful. If false, x and y are
+     *         unmodified.
+     */
+    bool tileDimensions(int& x, int&y);
+
+    /**
+     * Move to the next tile and return its indices. Must be called before calling drawCurrentTile
+     * for the first time.
+     * @param i Output parameter identifying the column of the next tile to be drawn on the next
+     *          call to drawNextTile.
+     * @param j Output parameter identifying the row  of the next tile to be drawn on the next call
+     *          to drawNextTile.
+     * @param True if the tiles have been created and the next tile to be drawn by drawCurrentTile
+     *        is within the range of tiles. If false, i and j are unmodified.
+     */
+    bool nextTile(int& i, int& j);
+
+    /**
+     * Render one tile. This will draw the same tile each time it is called until nextTile is
+     * called. The tile rendered will depend on how many calls have been made to nextTile.
+     * It is an error to call this without first calling nextTile, or if nextTile returns false.
+     */
+    void drawCurrentTile();
+
 protected:
     SkTDArray<SkRect> fTileRects;
 
@@ -327,11 +366,19 @@ protected:
     virtual SkString getConfigNameInternal() SK_OVERRIDE;
 
 private:
-    int               fTileWidth;
-    int               fTileHeight;
-    double            fTileWidthPercentage;
-    double            fTileHeightPercentage;
-    int               fTileMinPowerOf2Width;
+    int    fTileWidth;
+    int    fTileHeight;
+    double fTileWidthPercentage;
+    double fTileHeightPercentage;
+    int    fTileMinPowerOf2Width;
+
+    // These variables are only used for timing individual tiles.
+    // Next tile to draw in fTileRects.
+    int    fCurrentTileOffset;
+    // Number of tiles in the x direction.
+    int    fTilesX;
+    // Number of tiles in the y direction.
+    int    fTilesY;
 
     void setupTiles();
     void setupPowerOf2Tiles();
index ca63807..0bfbb28 100644 (file)
@@ -120,7 +120,7 @@ static void usage(const char* argv0) {
 "Usage: \n"
 "     %s <inputDir>...\n"
 "     [--logFile filename][--timers [wcgWC]*][--logPerIter 1|0][--min]\n"
-"     [--repeat] \n"
+"     [--repeat][--timeIndividualTiles] \n"
 "     [--mode pow2tile minWidth height | record | simple\n"
 "             | tile width height | playbackCreation]\n"
 "     [--pipe]\n"
@@ -144,6 +144,9 @@ static void usage(const char* argv0) {
     SkDebugf("     --min : Print the minimum times (instead of average).\n");
     SkDebugf("     --timers [wcgWC]* : "
              "Display wall, cpu, gpu, truncated wall or truncated cpu time for each picture.\n");
+    SkDebugf("     --timeIndividualTiles : Report times for drawing individual tiles, rather than\n"
+"                                          times for drawing the whole page.\n"
+"                                          Requires --mode tile\n");
     SkDebugf(
 "     --mode pow2tile minWidth height | copyTile width height | record | simple\n"
 "            | tile width height | playbackCreation:\n"
@@ -510,6 +513,8 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
                 gLogger.logError("Missing arg for --timers\n");
                 PRINT_USAGE_AND_EXIT;
             }
+        } else if (0 == strcmp(*argv, "--timeIndividualTiles")) {
+            benchmark->setTimeIndividualTiles(true);
         } else if (0 == strcmp(*argv, "--min")) {
             benchmark->setPrintMin(true);
         } else if (0 == strcmp(*argv, "--logPerIter")) {
@@ -613,6 +618,10 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
                 x = y = 4;
             }
             tiledRenderer = SkNEW_ARGS(sk_tools::CopyTilesRenderer, (x, y));
+            if (benchmark->timeIndividualTiles()) {
+                gLogger.logError("timeIndividualTiles is not compatible with copyTile\n");
+                PRINT_USAGE_AND_EXIT;
+            }
         } else if (numThreads > 1) {
             tiledRenderer = SkNEW_ARGS(sk_tools::MultiCorePictureRenderer, (numThreads));
         } else {
@@ -693,15 +702,21 @@ static void parse_commandline(int argc, char* const argv[], SkTArray<SkString>*
         }
         renderer.reset(tiledRenderer);
         if (usePipe) {
-            SkDebugf("Pipe rendering is currently not compatible with tiling.\n"
+            gLogger.logError("Pipe rendering is currently not compatible with tiling.\n"
                      "Turning off pipe.\n");
         }
-    } else if (usePipe) {
-        if (renderer.get() != NULL) {
-            SkDebugf("Pipe is incompatible with other modes.\n");
+    } else {
+        if (benchmark->timeIndividualTiles()) {
+            gLogger.logError("timeIndividualTiles requires tiled rendering.\n");
             PRINT_USAGE_AND_EXIT;
         }
-        renderer.reset(SkNEW(sk_tools::PipePictureRenderer));
+        if (usePipe) {
+            if (renderer.get() != NULL) {
+                gLogger.logError("Pipe is incompatible with other modes.\n");
+                PRINT_USAGE_AND_EXIT;
+            }
+            renderer.reset(SkNEW(sk_tools::PipePictureRenderer));
+        }
     }
     if (inputs->count() < 1) {
         PRINT_USAGE_AND_EXIT;