Home | History | Annotate | Download | only in tools
      1 /*
      2  * Copyright 2012 Google Inc.
      3  *
      4  * Use of this source code is governed by a BSD-style license that can be
      5  * found in the LICENSE file.
      6  */
      7 
      8 #include "SkBenchLogger.h"
      9 #include "BenchTimer.h"
     10 #include "PictureBenchmark.h"
     11 #include "SkCanvas.h"
     12 #include "SkPicture.h"
     13 #include "SkString.h"
     14 #include "picture_utils.h"
     15 
     16 namespace sk_tools {
     17 
     18 PictureBenchmark::PictureBenchmark()
     19 : fRepeats(1)
     20 , fLogger(NULL)
     21 , fRenderer(NULL)
     22 , fTimerResult(TimerData::kAvg_Result)
     23 , fTimerTypes(0)
     24 , fTimeIndividualTiles(false)
     25 {}
     26 
     27 PictureBenchmark::~PictureBenchmark() {
     28     SkSafeUnref(fRenderer);
     29 }
     30 
     31 void PictureBenchmark::setTimersToShow(bool wall,
     32                                        bool truncatedWall,
     33                                        bool cpu,
     34                                        bool truncatedCpu,
     35                                        bool gpu) {
     36     fTimerTypes = 0;
     37     fTimerTypes |= wall ? TimerData::kWall_Flag : 0;
     38     fTimerTypes |= truncatedWall ? TimerData::kTruncatedWall_Flag : 0;
     39     fTimerTypes |= cpu ? TimerData::kCpu_Flag : 0;
     40     fTimerTypes |= truncatedCpu ? TimerData::kTruncatedCpu_Flag : 0;
     41     fTimerTypes |= gpu ? TimerData::kGpu_Flag : 0;
     42 }
     43 
     44 BenchTimer* PictureBenchmark::setupTimer(bool useGLTimer) {
     45 #if SK_SUPPORT_GPU
     46     if (useGLTimer && fRenderer != NULL && fRenderer->isUsingGpuDevice()) {
     47         return SkNEW_ARGS(BenchTimer, (fRenderer->getGLContext()));
     48     }
     49 #endif
     50     return SkNEW_ARGS(BenchTimer, (NULL));
     51 }
     52 
     53 void PictureBenchmark::logProgress(const char msg[]) {
     54     if (fLogger != NULL) {
     55         fLogger->logProgress(msg);
     56     }
     57 }
     58 
     59 PictureRenderer* PictureBenchmark::setRenderer(sk_tools::PictureRenderer* renderer) {
     60     SkRefCnt_SafeAssign(fRenderer, renderer);
     61     return renderer;
     62 }
     63 
     64 void PictureBenchmark::run(SkPicture* pict) {
     65     SkASSERT(pict);
     66     if (NULL == pict) {
     67         return;
     68     }
     69 
     70     SkASSERT(fRenderer != NULL);
     71     if (NULL == fRenderer) {
     72         return;
     73     }
     74 
     75     fRenderer->init(pict);
     76 
     77     // We throw this away to remove first time effects (such as paging in this program)
     78     fRenderer->setup();
     79     fRenderer->render(NULL);
     80     fRenderer->resetState(true);
     81 
     82     bool usingGpu = false;
     83 #if SK_SUPPORT_GPU
     84     usingGpu = fRenderer->isUsingGpuDevice();
     85 #endif
     86 
     87     uint32_t timerTypes = fTimerTypes;
     88     if (!usingGpu) {
     89         timerTypes &= ~TimerData::kGpu_Flag;
     90     }
     91 
     92     SkString timeFormat;
     93     if (TimerData::kPerIter_Result == fTimerResult) {
     94         timeFormat = fRenderer->getPerIterTimeFormat();
     95     } else {
     96         timeFormat = fRenderer->getNormalTimeFormat();
     97     }
     98 
     99     if (fTimeIndividualTiles) {
    100         TiledPictureRenderer* tiledRenderer = fRenderer->getTiledRenderer();
    101         SkASSERT(tiledRenderer && tiledRenderer->supportsTimingIndividualTiles());
    102         if (NULL == tiledRenderer || !tiledRenderer->supportsTimingIndividualTiles()) {
    103             return;
    104         }
    105         int xTiles, yTiles;
    106         if (!tiledRenderer->tileDimensions(xTiles, yTiles)) {
    107             return;
    108         }
    109 
    110         // Insert a newline so that each tile is reported on its own line (separate from the line
    111         // that describes the skp being run).
    112         this->logProgress("\n");
    113 
    114         int x, y;
    115         while (tiledRenderer->nextTile(x, y)) {
    116             // There are two timers, which will behave slightly differently:
    117             // 1) longRunningTimer, along with perTileTimerData, will time how long it takes to draw
    118             // one tile fRepeats times, and take the average. As such, it will not respect thea
    119             // logPerIter or printMin options, since it does not know the time per iteration. It
    120             // will also be unable to call flush() for each tile.
    121             // The goal of this timer is to make up for a system timer that is not precise enough to
    122             // measure the small amount of time it takes to draw one tile once.
    123             //
    124             // 2) perTileTimer, along with perTileTimerData, will record each run separately, and
    125             // then take the average. As such, it supports logPerIter and printMin options.
    126             //
    127             // Although "legal", having two gpu timers running at the same time
    128             // seems to cause problems (i.e., INVALID_OPERATIONs) on several
    129             // platforms. To work around this, we disable the gpu timer on the
    130             // long running timer.
    131             SkAutoTDelete<BenchTimer> longRunningTimer(this->setupTimer());
    132             TimerData longRunningTimerData(1);
    133             SkAutoTDelete<BenchTimer> perTileTimer(this->setupTimer(false));
    134             TimerData perTileTimerData(fRepeats);
    135             longRunningTimer->start();
    136             for (int i = 0; i < fRepeats; ++i) {
    137                 perTileTimer->start();
    138                 tiledRenderer->drawCurrentTile();
    139                 perTileTimer->truncatedEnd();
    140                 tiledRenderer->resetState(false);
    141                 perTileTimer->end();
    142                 SkAssertResult(perTileTimerData.appendTimes(perTileTimer.get()));
    143             }
    144             longRunningTimer->truncatedEnd();
    145             tiledRenderer->resetState(true);
    146             longRunningTimer->end();
    147             SkAssertResult(longRunningTimerData.appendTimes(longRunningTimer.get()));
    148 
    149             SkString configName = tiledRenderer->getConfigName();
    150             configName.appendf(": tile [%i,%i] out of [%i,%i]", x, y, xTiles, yTiles);
    151 
    152             SkString result = perTileTimerData.getResult(timeFormat.c_str(), fTimerResult,
    153                                                          configName.c_str(), timerTypes);
    154             result.append("\n");
    155 
    156 // TODO(borenet): Turn off per-iteration tile time reporting for now.  Avoiding logging the time
    157 // for every iteration for each tile cuts down on data file size by a significant amount. Re-enable
    158 // this once we're loading the bench data directly into a data store and are no longer generating
    159 // SVG graphs.
    160 #if 0
    161             this->logProgress(result.c_str());
    162 #endif
    163 
    164             configName.append(" <averaged>");
    165             SkString longRunningResult = longRunningTimerData.getResult(
    166                 tiledRenderer->getNormalTimeFormat().c_str(),
    167                 TimerData::kAvg_Result,
    168                 configName.c_str(), timerTypes, fRepeats);
    169             longRunningResult.append("\n");
    170             this->logProgress(longRunningResult.c_str());
    171         }
    172     } else {
    173         SkAutoTDelete<BenchTimer> timer(this->setupTimer());
    174         TimerData timerData(fRepeats);
    175         for (int i = 0; i < fRepeats; ++i) {
    176             fRenderer->setup();
    177 
    178             timer->start();
    179             fRenderer->render(NULL);
    180             timer->truncatedEnd();
    181 
    182             // Finishes gl context
    183             fRenderer->resetState(true);
    184             timer->end();
    185 
    186             SkAssertResult(timerData.appendTimes(timer.get()));
    187         }
    188 
    189         SkString configName = fRenderer->getConfigName();
    190 
    191         SkString result = timerData.getResult(timeFormat.c_str(),
    192                                               fTimerResult,
    193                                               configName.c_str(),
    194                                               timerTypes);
    195         result.append("\n");
    196         this->logProgress(result.c_str());
    197     }
    198 
    199     fRenderer->end();
    200 }
    201 
    202 }
    203