aboutsummaryrefslogtreecommitdiffstats
path: root/bench
diff options
context:
space:
mode:
Diffstat (limited to 'bench')
-rw-r--r--bench/AAClipBench.cpp104
-rw-r--r--bench/Android.mk36
-rw-r--r--bench/BenchGpuTimer_gl.cpp209
-rw-r--r--bench/BenchGpuTimer_gl.h31
-rw-r--r--bench/BenchGpuTimer_none.cpp14
-rw-r--r--bench/BenchGpuTimer_none.h12
-rw-r--r--bench/BenchSysTimer_c.cpp7
-rw-r--r--bench/BenchSysTimer_c.h7
-rw-r--r--bench/BenchSysTimer_mach.cpp7
-rw-r--r--bench/BenchSysTimer_mach.h7
-rw-r--r--bench/BenchSysTimer_posix.cpp7
-rw-r--r--bench/BenchSysTimer_posix.h7
-rw-r--r--bench/BenchSysTimer_windows.cpp15
-rw-r--r--bench/BenchSysTimer_windows.h9
-rw-r--r--bench/BenchTimer.cpp49
-rw-r--r--bench/BenchTimer.h14
-rw-r--r--bench/BitmapBench.cpp27
-rw-r--r--bench/BlurBench.cpp106
-rw-r--r--bench/ChromeBench.cpp498
-rw-r--r--bench/DecodeBench.cpp9
-rw-r--r--bench/FPSBench.cpp108
-rw-r--r--bench/FontScalerBench.cpp60
-rw-r--r--bench/GradientBench.cpp153
-rw-r--r--bench/Makefile.am20
-rw-r--r--bench/MathBench.cpp316
-rw-r--r--bench/MatrixBench.cpp98
-rw-r--r--bench/MutexBench.cpp43
-rw-r--r--bench/PathBench.cpp55
-rw-r--r--bench/RectBench.cpp9
-rw-r--r--bench/RepeatTileBench.cpp9
-rw-r--r--bench/ScalarBench.cpp9
-rw-r--r--bench/ShaderMaskBench.cpp109
-rw-r--r--bench/SkBenchmark.cpp7
-rw-r--r--bench/SkBenchmark.h13
-rw-r--r--bench/TextBench.cpp135
-rw-r--r--bench/VertBench.cpp99
-rw-r--r--bench/bench_compare.py109
-rw-r--r--bench/bench_graph_svg.py750
-rw-r--r--bench/bench_util.py178
-rw-r--r--bench/benchmain.cpp232
40 files changed, 3116 insertions, 571 deletions
diff --git a/bench/AAClipBench.cpp b/bench/AAClipBench.cpp
new file mode 100644
index 0000000..39088c1
--- /dev/null
+++ b/bench/AAClipBench.cpp
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkAAClip.h"
+#include "SkPath.h"
+#include "SkRegion.h"
+#include "SkString.h"
+
+class AAClipBuilderBench : public SkBenchmark {
+ SkString fName;
+ SkPath fPath;
+ SkRect fRect;
+ SkRegion fRegion;
+ bool fDoPath;
+ bool fDoAA;
+
+ enum {
+ N = SkBENCHLOOP(200),
+ };
+
+public:
+ AAClipBuilderBench(void* param, bool doPath, bool doAA) : INHERITED(param) {
+ fDoPath = doPath;
+ fDoAA = doAA;
+
+ fName.printf("aaclip_build_%s_%s", doPath ? "path" : "rect",
+ doAA ? "AA" : "BW");
+
+ fRegion.setRect(0, 0, 640, 480);
+ fRect.set(fRegion.getBounds());
+ fRect.inset(SK_Scalar1/4, SK_Scalar1/4);
+ fPath.addRoundRect(fRect, SkIntToScalar(20), SkIntToScalar(20));
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ for (int i = 0; i < N; ++i) {
+ SkAAClip clip;
+ if (fDoPath) {
+ clip.setPath(fPath, &fRegion, fDoAA);
+ } else {
+ clip.setRect(fRect, fDoAA);
+ }
+ }
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+class AAClipRegionBench : public SkBenchmark {
+public:
+ AAClipRegionBench(void* param) : INHERITED(param) {
+ SkPath path;
+ // test conversion of a complex clip to a aaclip
+ path.addCircle(0, 0, SkIntToScalar(200));
+ path.addCircle(0, 0, SkIntToScalar(180));
+ // evenodd means we've constructed basically a stroked circle
+ path.setFillType(SkPath::kEvenOdd_FillType);
+
+ SkIRect bounds;
+ path.getBounds().roundOut(&bounds);
+ fRegion.setPath(path, SkRegion(bounds));
+ }
+
+protected:
+ virtual const char* onGetName() { return "aaclip_setregion"; }
+ virtual void onDraw(SkCanvas* canvas) {
+ for (int i = 0; i < N; ++i) {
+ SkAAClip clip;
+ clip.setRegion(fRegion);
+ }
+ }
+
+private:
+ enum {
+ N = SkBENCHLOOP(400),
+ };
+ SkRegion fRegion;
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact0(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, false)); }
+static SkBenchmark* Fact1(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, false, true)); }
+static SkBenchmark* Fact2(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, true, false)); }
+static SkBenchmark* Fact3(void* p) { return SkNEW_ARGS(AAClipBuilderBench, (p, true, true)); }
+
+static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg1(Fact1);
+static BenchRegistry gReg2(Fact2);
+static BenchRegistry gReg3(Fact3);
+
+static SkBenchmark* Fact01(void* p) { return SkNEW_ARGS(AAClipRegionBench, (p)); }
+static BenchRegistry gReg01(Fact01);
diff --git a/bench/Android.mk b/bench/Android.mk
index a0fe86c..ab2e588 100644
--- a/bench/Android.mk
+++ b/bench/Android.mk
@@ -3,36 +3,42 @@ LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := \
- BenchGpuTimer_none.cpp \
- BenchSysTimer_posix.cpp \
+ benchmain.cpp \
BenchTimer.cpp \
+ BenchSysTimer_posix.cpp \
+ BenchGpuTimer_gl.cpp \
+ SkBenchmark.cpp
+
+LOCAL_SRC_FILES += \
+ AAClipBench.cpp \
BitmapBench.cpp \
+ BlurBench.cpp \
+ ChromeBench.cpp \
DecodeBench.cpp \
- FPSBench.cpp \
+ FontScalerBench.cpp \
GradientBench.cpp \
+ MathBench.cpp \
MatrixBench.cpp \
+ MutexBench.cpp \
PathBench.cpp \
RectBench.cpp \
RepeatTileBench.cpp \
+ ScalarBench.cpp \
+ ShaderMaskBench.cpp \
TextBench.cpp \
- SkBenchmark.cpp \
- benchmain.cpp
-
-# additional optional class for this tool
-LOCAL_SRC_FILES += \
- ../src/utils/SkNWayCanvas.cpp \
- ../src/utils/SkParse.cpp
+ VertBench.cpp
-LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2
+LOCAL_SHARED_LIBRARIES := libcutils libskia libGLESv2 libEGL
LOCAL_STATIC_LIBRARIES := libskiagpu
LOCAL_C_INCLUDES := \
- external/skia/include/config \
external/skia/include/core \
+ external/skia/include/config \
+ external/skia/include/effects \
+ external/skia/include/gpu \
external/skia/include/images \
external/skia/include/utils \
- external/skia/include/effects \
- external/skia/gpu/include \
- external/skia/include/gpu
+ external/skia/src/core \
+ external/skia/src/gpu
#LOCAL_CFLAGS :=
diff --git a/bench/BenchGpuTimer_gl.cpp b/bench/BenchGpuTimer_gl.cpp
index ec2145d..885f7b2 100644
--- a/bench/BenchGpuTimer_gl.cpp
+++ b/bench/BenchGpuTimer_gl.cpp
@@ -1,159 +1,41 @@
-#include "BenchGpuTimer_gl.h"
-#include <string.h>
-
-//GL
-#define BENCH_GL_FUNCTION_TYPE
-#if defined(SK_MESA)
- #include <GL/osmesa.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != OSMesaGetCurrentContext())
-
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- OSMesaGetProcAddress("gl" #F);
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- OSMesaGetProcAddress("gl" #F #S);
-
-#elif defined(SK_BUILD_FOR_WIN32)
- #define WIN32_LEAN_AND_MEAN 1
- #include <Windows.h>
- #include <GL/GL.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != wglGetCurrentContext())
-
- #undef BENCH_GL_FUNCTION_TYPE
- #define BENCH_GL_FUNCTION_TYPE __stdcall
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- wglGetProcAddress("gl" #F);
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- wglGetProcAddress("gl" #F #S);
-
-#elif defined(SK_BUILD_FOR_MAC)
- #include <OpenGL/gl.h>
- #include <OpenGL/CGLCurrent.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != CGLGetCurrentContext())
-
-#elif defined(SK_BUILD_FOR_UNIX)
- #include <GL/gl.h>
- #include <GL/glx.h>
- #define SK_BENCH_CONTEXT_CHECK (NULL != glXGetCurrentContext())
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "BenchGpuTimer_gl.h"
+#include "SkGLContext.h"
+
+BenchGpuTimer::BenchGpuTimer(const SkGLContext* glctx) {
+ fContext = glctx;
+ glctx->ref();
+ glctx->makeCurrent();
+ fStarted = false;
+ fSupported = GrGLGetVersion(glctx->gl()) > GR_GL_VER(3,3) ||
+ GrGLHasExtension(glctx->gl(), "GL_ARB_timer_query") ||
+ GrGLHasExtension(glctx->gl(), "GL_EXT_timer_query");
- #define SK_GL_GET_PROC(F) gBenchGL.f ## F = (BenchGL ## F ## Proc) \
- glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F));
- #define SK_GL_GET_PROC_SUFFIX(F, S) gBenchGL.f ## F = (BenchGL##F##Proc)\
- glXGetProcAddressARB(reinterpret_cast<const GLubyte*>("gl" #F #S));
-#else
- #error unsupported platform
-#endif
-
-#define BenchGL_TIME_ELAPSED 0x88BF
-#define BenchGL_QUERY_RESULT 0x8866
-#define BenchGL_QUERY_RESULT_AVAILABLE 0x8867
-
-#if defined(SK_BUILD_FOR_WIN32)
-typedef UINT64 BenchGLuint64;
-#else
-#include <stdint.h>
-typedef uint64_t BenchGLuint64;
-#endif
-
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGenQueriesProc) (GLsizei n, GLuint *ids);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLBeginQueryProc) (GLenum target, GLuint id);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLEndQueryProc) (GLenum target);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLDeleteQueriesProc) (GLsizei n, const GLuint *ids);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectivProc) (GLuint id, GLenum pname, GLint *params);
-typedef void (BENCH_GL_FUNCTION_TYPE *BenchGLGetQueryObjectui64vProc) (GLuint id, GLenum pname, BenchGLuint64 *params);
-
-struct BenchGLInterface {
- bool fHasTimer;
- BenchGLGenQueriesProc fGenQueries;
- BenchGLBeginQueryProc fBeginQuery;
- BenchGLEndQueryProc fEndQuery;
- BenchGLDeleteQueriesProc fDeleteQueries;
- BenchGLGetQueryObjectivProc fGetQueryObjectiv;
- BenchGLGetQueryObjectui64vProc fGetQueryObjectui64v;
-};
-
-static bool BenchGLCheckExtension(const char* ext,
- const char* extensionString) {
- int extLength = strlen(ext);
-
- while (true) {
- int n = strcspn(extensionString, " ");
- if (n == extLength && 0 == strncmp(ext, extensionString, n)) {
- return true;
- }
- if (0 == extensionString[n]) {
- return false;
- }
- extensionString += n+1;
- }
-
- return false;
-}
-
-static BenchGLInterface gBenchGL;
-static bool gBenchGLInterfaceInit = false;
-
-static void BenchGLSetDefaultGLInterface() {
- gBenchGL.fHasTimer = false;
- if (gBenchGLInterfaceInit || !SK_BENCH_CONTEXT_CHECK) return;
-
- const char* glExts =
- reinterpret_cast<const char*>(glGetString(GL_EXTENSIONS));
- const GLboolean ext =
- BenchGLCheckExtension("GL_EXT_timer_query", glExts);
- const GLboolean arb =
- BenchGLCheckExtension("GL_ARB_timer_query", glExts);
- if (ext || arb) {
-#if defined(SK_BUILD_FOR_MAC)
- #if GL_EXT_timer_query || GL_ARB_timer_query
- gBenchGL.fHasTimer = true;
- gBenchGL.fGenQueries = glGenQueries;
- gBenchGL.fBeginQuery = glBeginQuery;
- gBenchGL.fEndQuery = glEndQuery;
- gBenchGL.fDeleteQueries = glDeleteQueries;
- gBenchGL.fGetQueryObjectiv = glGetQueryObjectiv;
- #endif
- #if GL_ARB_timer_query
- gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64v;
- #elif GL_EXT_timer_query
- gBenchGL.fGetQueryObjectui64v = glGetQueryObjectui64vEXT;
- #endif
-#else
- gBenchGL.fHasTimer = true;
- SK_GL_GET_PROC(GenQueries)
- SK_GL_GET_PROC(BeginQuery)
- SK_GL_GET_PROC(EndQuery)
- SK_GL_GET_PROC(DeleteQueries)
-
- SK_GL_GET_PROC(GetQueryObjectiv)
- if (arb) {
- SK_GL_GET_PROC(GetQueryObjectui64v)
- } else {
- SK_GL_GET_PROC_SUFFIX(GetQueryObjectui64v, EXT)
- }
-#endif
- }
- gBenchGLInterfaceInit = true;
-}
-
-BenchGpuTimer::BenchGpuTimer() {
- BenchGLSetDefaultGLInterface();
- if (gBenchGL.fHasTimer) {
- gBenchGL.fGenQueries(1, &this->fQuery);
+ if (fSupported) {
+ SK_GL(*glctx, GenQueries(1, &fQuery));
}
}
BenchGpuTimer::~BenchGpuTimer() {
- if (gBenchGL.fHasTimer) {
- gBenchGL.fDeleteQueries(1, &this->fQuery);
+ if (fSupported) {
+ fContext->makeCurrent();
+ SK_GL(*fContext, DeleteQueries(1, &fQuery));
}
+ fContext->unref();
}
void BenchGpuTimer::startGpu() {
- if (!gBenchGL.fHasTimer) return;
-
- this->fStarted = true;
- gBenchGL.fBeginQuery(BenchGL_TIME_ELAPSED, this->fQuery);
+ if (fSupported) {
+ fContext->makeCurrent();
+ fStarted = true;
+ SK_GL(*fContext, BeginQuery(GR_GL_TIME_ELAPSED, fQuery));
+ }
}
/**
@@ -161,21 +43,24 @@ void BenchGpuTimer::startGpu() {
* as this will cpu wait for the gpu to finish.
*/
double BenchGpuTimer::endGpu() {
- if (!gBenchGL.fHasTimer) return 0;
-
- this->fStarted = false;
- gBenchGL.fEndQuery(BenchGL_TIME_ELAPSED);
-
- GLint available = 0;
- while (!available) {
- gBenchGL.fGetQueryObjectiv(this->fQuery
- , BenchGL_QUERY_RESULT_AVAILABLE
- , &available);
+ if (fSupported) {
+ fStarted = false;
+ fContext->makeCurrent();
+ SK_GL(*fContext, EndQuery(GR_GL_TIME_ELAPSED));
+
+ GrGLint available = 0;
+ while (!available) {
+ SK_GL(*fContext, GetQueryObjectiv(fQuery,
+ GR_GL_QUERY_RESULT_AVAILABLE,
+ &available));
+ }
+ GrGLuint64 totalGPUTimeElapsed = 0;
+ SK_GL(*fContext, GetQueryObjectui64v(fQuery,
+ GR_GL_QUERY_RESULT,
+ &totalGPUTimeElapsed));
+
+ return totalGPUTimeElapsed / 1000000.0;
+ } else {
+ return 0;
}
- BenchGLuint64 totalGPUTimeElapsed = 0;
- gBenchGL.fGetQueryObjectui64v(this->fQuery
- , BenchGL_QUERY_RESULT
- , &totalGPUTimeElapsed);
-
- return totalGPUTimeElapsed / 1000000.0;
}
diff --git a/bench/BenchGpuTimer_gl.h b/bench/BenchGpuTimer_gl.h
index ac23482..7c7b5c2 100644
--- a/bench/BenchGpuTimer_gl.h
+++ b/bench/BenchGpuTimer_gl.h
@@ -1,33 +1,26 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchGpuTimer_DEFINED
#define SkBenchGpuTimer_DEFINED
-#if defined(SK_MESA)
- #include <GL/osmesa.h>
-
-#elif defined(SK_BUILD_FOR_WIN32)
- #define WIN32_LEAN_AND_MEAN 1
- #include <Windows.h>
- #include <GL/GL.h>
-
-#elif defined(SK_BUILD_FOR_MAC)
- #include <OpenGL/gl.h>
-
-#elif defined(SK_BUILD_FOR_UNIX)
- #include <GL/gl.h>
-
-#else
- #error unsupported platform
-#endif
+class SkGLContext;
class BenchGpuTimer {
public:
- BenchGpuTimer();
+ BenchGpuTimer(const SkGLContext* glctx);
~BenchGpuTimer();
void startGpu();
double endGpu();
private:
- GLuint fQuery;
+ unsigned fQuery;
int fStarted;
+ const SkGLContext* fContext;
+ bool fSupported;
};
#endif
diff --git a/bench/BenchGpuTimer_none.cpp b/bench/BenchGpuTimer_none.cpp
deleted file mode 100644
index 0dba6d7..0000000
--- a/bench/BenchGpuTimer_none.cpp
+++ /dev/null
@@ -1,14 +0,0 @@
-#include "BenchGpuTimer_none.h"
-
-BenchGpuTimer::BenchGpuTimer() {
-}
-
-BenchGpuTimer::~BenchGpuTimer() {
-}
-
-void BenchGpuTimer::startGpu() {
-}
-
-double BenchGpuTimer::endGpu() {
- return -1.0;
-}
diff --git a/bench/BenchGpuTimer_none.h b/bench/BenchGpuTimer_none.h
deleted file mode 100644
index 7069ca4..0000000
--- a/bench/BenchGpuTimer_none.h
+++ /dev/null
@@ -1,12 +0,0 @@
-#ifndef SkBenchGpuTimer_DEFINED
-#define SkBenchGpuTimer_DEFINED
-
-class BenchGpuTimer {
-public:
- BenchGpuTimer();
- ~BenchGpuTimer();
- void startGpu();
- double endGpu();
-};
-
-#endif
diff --git a/bench/BenchSysTimer_c.cpp b/bench/BenchSysTimer_c.cpp
index fc0850b..f4cbd39 100644
--- a/bench/BenchSysTimer_c.cpp
+++ b/bench/BenchSysTimer_c.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_c.h"
//Time
diff --git a/bench/BenchSysTimer_c.h b/bench/BenchSysTimer_c.h
index c598f30..2ddc83d 100644
--- a/bench/BenchSysTimer_c.h
+++ b/bench/BenchSysTimer_c.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_mach.cpp b/bench/BenchSysTimer_mach.cpp
index b23897c..c837ca3 100644
--- a/bench/BenchSysTimer_mach.cpp
+++ b/bench/BenchSysTimer_mach.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_mach.h"
//Time
diff --git a/bench/BenchSysTimer_mach.h b/bench/BenchSysTimer_mach.h
index da4fff0..44d0e5e 100644
--- a/bench/BenchSysTimer_mach.h
+++ b/bench/BenchSysTimer_mach.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_posix.cpp b/bench/BenchSysTimer_posix.cpp
index 5d28f40..e6767e5 100644
--- a/bench/BenchSysTimer_posix.cpp
+++ b/bench/BenchSysTimer_posix.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_posix.h"
//Time
diff --git a/bench/BenchSysTimer_posix.h b/bench/BenchSysTimer_posix.h
index 09dfb0e..de793f3 100644
--- a/bench/BenchSysTimer_posix.h
+++ b/bench/BenchSysTimer_posix.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
diff --git a/bench/BenchSysTimer_windows.cpp b/bench/BenchSysTimer_windows.cpp
index 923754c..3635ec5 100644
--- a/bench/BenchSysTimer_windows.cpp
+++ b/bench/BenchSysTimer_windows.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchSysTimer_windows.h"
//Time
@@ -35,7 +42,7 @@ void BenchSysTimer::startCpu() {
double BenchSysTimer::endCpu() {
ULONGLONG end_cpu = winCpuTime();
- return (end_cpu - this->fStartCpu) / 10000;
+ return static_cast<double>((end_cpu - this->fStartCpu)) / 10000.0L;
}
double BenchSysTimer::endWall() {
LARGE_INTEGER end_wall;
@@ -48,8 +55,10 @@ double BenchSysTimer::endWall() {
LARGE_INTEGER frequency;
if (0 == ::QueryPerformanceFrequency(&frequency)) {
- return 0;
+ return 0.0L;
} else {
- return (double)ticks_elapsed.QuadPart / frequency.QuadPart * 1000;
+ return static_cast<double>(ticks_elapsed.QuadPart)
+ / static_cast<double>(frequency.QuadPart)
+ * 1000.0L;
}
}
diff --git a/bench/BenchSysTimer_windows.h b/bench/BenchSysTimer_windows.h
index 72a3fb2..c3d0c9b 100644
--- a/bench/BenchSysTimer_windows.h
+++ b/bench/BenchSysTimer_windows.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchSysTimer_DEFINED
#define SkBenchSysTimer_DEFINED
@@ -5,7 +12,7 @@
#define WIN32_LEAN_AND_MEAN 1
#include <Windows.h>
-struct BenchSysTimer {
+class BenchSysTimer {
public:
void startWall();
void startCpu();
diff --git a/bench/BenchTimer.cpp b/bench/BenchTimer.cpp
index e7b0068..c3a1190 100644
--- a/bench/BenchTimer.cpp
+++ b/bench/BenchTimer.cpp
@@ -1,48 +1,55 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "BenchTimer.h"
#if defined(SK_BUILD_FOR_WIN32)
#include "BenchSysTimer_windows.h"
#elif defined(SK_BUILD_FOR_MAC)
#include "BenchSysTimer_mach.h"
-#elif defined(SK_BUILD_FOR_UNIX)
+#elif defined(SK_BUILD_FOR_UNIX) || defined(SK_BUILD_FOR_ANDROID)
#include "BenchSysTimer_posix.h"
#else
#include "BenchSysTimer_c.h"
#endif
-#if defined(SK_MESA) || \
- defined(SK_BUILD_FOR_WIN32) || \
- defined(SK_BUILD_FOR_MAC) || \
- defined(SK_BUILD_FOR_UNIX)
- #include "BenchGpuTimer_gl.h"
-
-#else
- #include "BenchGpuTimer_none.h"
-#endif
+#include "BenchGpuTimer_gl.h"
-BenchTimer::BenchTimer()
+BenchTimer::BenchTimer(SkGLContext* gl)
: fCpu(-1.0)
, fWall(-1.0)
, fGpu(-1.0)
{
- this->fSysTimer = new BenchSysTimer();
- this->fGpuTimer = new BenchGpuTimer();
+ fSysTimer = new BenchSysTimer();
+ if (gl) {
+ fGpuTimer = new BenchGpuTimer(gl);
+ } else {
+ fGpuTimer = NULL;
+ }
}
BenchTimer::~BenchTimer() {
- delete this->fSysTimer;
- delete this->fGpuTimer;
+ delete fSysTimer;
+ delete fGpuTimer;
}
void BenchTimer::start() {
- this->fSysTimer->startWall();
- this->fGpuTimer->startGpu();
- this->fSysTimer->startCpu();
+ fSysTimer->startWall();
+ if (fGpuTimer) {
+ fGpuTimer->startGpu();
+ }
+ fSysTimer->startCpu();
}
void BenchTimer::end() {
- this->fCpu = this->fSysTimer->endCpu();
+ fCpu = fSysTimer->endCpu();
//It is important to stop the cpu clocks first,
//as the following will cpu wait for the gpu to finish.
- this->fGpu = this->fGpuTimer->endGpu();
- this->fWall = this->fSysTimer->endWall();
+ if (fGpuTimer) {
+ fGpu = fGpuTimer->endGpu();
+ }
+ fWall = fSysTimer->endWall();
}
diff --git a/bench/BenchTimer.h b/bench/BenchTimer.h
index eae82d5..080bc6d 100644
--- a/bench/BenchTimer.h
+++ b/bench/BenchTimer.h
@@ -1,9 +1,21 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchTimer_DEFINED
#define SkBenchTimer_DEFINED
+#include <SkTypes.h>
+
+
class BenchSysTimer;
class BenchGpuTimer;
+class SkGLContext;
+
/**
* SysTimers and GpuTimers are implemented orthogonally.
* This class combines a SysTimer and a GpuTimer into one single,
@@ -11,7 +23,7 @@ class BenchGpuTimer;
*/
class BenchTimer {
public:
- BenchTimer();
+ BenchTimer(SkGLContext* gl = NULL);
~BenchTimer();
void start();
void end();
diff --git a/bench/BitmapBench.cpp b/bench/BitmapBench.cpp
index 77e7ade..3b16925 100644
--- a/bench/BitmapBench.cpp
+++ b/bench/BitmapBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkPaint.h"
@@ -93,13 +100,15 @@ class BitmapBench : public SkBenchmark {
SkBitmap fBitmap;
SkPaint fPaint;
bool fIsOpaque;
+ bool fForceUpdate; //bitmap marked as dirty before each draw. forces bitmap to be updated on device cache
int fTileX, fTileY; // -1 means don't use shader
SkString fName;
- enum { N = 300 };
+ enum { N = SkBENCHLOOP(300) };
public:
BitmapBench(void* param, bool isOpaque, SkBitmap::Config c,
+ bool forceUpdate = false, bool bitmapVolatile = false,
int tx = -1, int ty = -1)
- : INHERITED(param), fIsOpaque(isOpaque), fTileX(tx), fTileY(ty) {
+ : INHERITED(param), fIsOpaque(isOpaque), fForceUpdate(forceUpdate), fTileX(tx), fTileY(ty) {
const int w = 128;
const int h = 128;
SkBitmap bm;
@@ -124,6 +133,7 @@ public:
fBitmap.getColorTable()->setIsOpaque(isOpaque);
}
fBitmap.setIsOpaque(isOpaque);
+ fBitmap.setIsVolatile(bitmapVolatile);
}
protected:
@@ -137,6 +147,11 @@ protected:
}
fName.appendf("_%s%s", gConfigName[fBitmap.config()],
fIsOpaque ? "" : "_A");
+ if (fForceUpdate)
+ fName.append("_update");
+ if (fBitmap.isVolatile())
+ fName.append("_volatile");
+
return fName.c_str();
}
@@ -154,6 +169,10 @@ protected:
for (int i = 0; i < N; i++) {
SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+
+ if (fForceUpdate)
+ bitmap.notifyPixelsChanged();
+
canvas->drawBitmap(bitmap, x, y, &paint);
}
}
@@ -169,6 +188,8 @@ static SkBenchmark* Fact3(void* p) { return new BitmapBench(p, false, SkBitmap::
static SkBenchmark* Fact4(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_4444_Config); }
static SkBenchmark* Fact5(void* p) { return new BitmapBench(p, false, SkBitmap::kIndex8_Config); }
static SkBenchmark* Fact6(void* p) { return new BitmapBench(p, true, SkBitmap::kIndex8_Config); }
+static SkBenchmark* Fact7(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, true); }
+static SkBenchmark* Fact8(void* p) { return new BitmapBench(p, true, SkBitmap::kARGB_8888_Config, true, false); }
static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg1(Fact1);
@@ -177,3 +198,5 @@ static BenchRegistry gReg3(Fact3);
static BenchRegistry gReg4(Fact4);
static BenchRegistry gReg5(Fact5);
static BenchRegistry gReg6(Fact6);
+static BenchRegistry gReg7(Fact7);
+static BenchRegistry gReg8(Fact8);
diff --git a/bench/BlurBench.cpp b/bench/BlurBench.cpp
new file mode 100644
index 0000000..de78fe1
--- /dev/null
+++ b/bench/BlurBench.cpp
@@ -0,0 +1,106 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkShader.h"
+#include "SkString.h"
+#include "SkBlurMaskFilter.h"
+
+#define SMALL SkIntToScalar(2)
+#define REAL SkFloatToScalar(1.5f)
+#define BIG SkIntToScalar(10)
+
+static const char* gStyleName[] = {
+ "normal",
+ "solid",
+ "outer",
+ "inner"
+};
+
+class BlurBench : public SkBenchmark {
+ SkScalar fRadius;
+ SkBlurMaskFilter::BlurStyle fStyle;
+ SkString fName;
+
+public:
+ BlurBench(void* param, SkScalar rad, SkBlurMaskFilter::BlurStyle bs) : INHERITED(param) {
+ fRadius = rad;
+ fStyle = bs;
+ const char* name = rad > 0 ? gStyleName[bs] : "none";
+ if (SkScalarFraction(rad) != 0) {
+ fName.printf("blur_%.2f_%s", SkScalarToFloat(rad), name);
+ } else {
+ fName.printf("blur_%d_%s", SkScalarRound(rad), name);
+ }
+ }
+
+protected:
+ virtual const char* onGetName() {
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ paint.setAntiAlias(true);
+
+ SkRandom rand;
+ for (int i = 0; i < SkBENCHLOOP(10); i++) {
+ SkRect r = SkRect::MakeWH(rand.nextUScalar1() * 400,
+ rand.nextUScalar1() * 400);
+ r.offset(fRadius, fRadius);
+
+ if (fRadius > 0) {
+ SkMaskFilter* mf = SkBlurMaskFilter::Create(fRadius, fStyle, 0);
+ paint.setMaskFilter(mf)->unref();
+ }
+ canvas->drawOval(r, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+static SkBenchmark* Fact00(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact01(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact02(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact03(void* p) { return new BlurBench(p, SMALL, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* Fact10(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact11(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact12(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact13(void* p) { return new BlurBench(p, BIG, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* Fact20(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kNormal_BlurStyle); }
+static SkBenchmark* Fact21(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kSolid_BlurStyle); }
+static SkBenchmark* Fact22(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kOuter_BlurStyle); }
+static SkBenchmark* Fact23(void* p) { return new BlurBench(p, REAL, SkBlurMaskFilter::kInner_BlurStyle); }
+
+static SkBenchmark* FactNone(void* p) { return new BlurBench(p, 0, SkBlurMaskFilter::kNormal_BlurStyle); }
+
+static BenchRegistry gReg00(Fact00);
+static BenchRegistry gReg01(Fact01);
+static BenchRegistry gReg02(Fact02);
+static BenchRegistry gReg03(Fact03);
+
+static BenchRegistry gReg10(Fact10);
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg12(Fact12);
+static BenchRegistry gReg13(Fact13);
+
+static BenchRegistry gReg20(Fact20);
+static BenchRegistry gReg21(Fact21);
+static BenchRegistry gReg22(Fact22);
+static BenchRegistry gReg23(Fact23);
+
+static BenchRegistry gRegNone(FactNone);
+
diff --git a/bench/ChromeBench.cpp b/bench/ChromeBench.cpp
new file mode 100644
index 0000000..fc73d53
--- /dev/null
+++ b/bench/ChromeBench.cpp
@@ -0,0 +1,498 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkString.h"
+
+/**
+ Benchmarks that try to emulate a particular Skia call pattern observed in Chrome.
+*/
+
+/// blitRect() calls emitted by Chrome while scrolling through gmail: count, width, height.
+int gmailScrollingRectSpec [431*3] = {
+ 1, 1254, 1160,
+ 1, 64, 112,
+ 1, 1034, 261,
+ 1, 1166, 1,
+ 1, 1166, 20,
+ 1, 1254, 40,
+ 1, 140, 20,
+ 1, 22, 30,
+ 1, 22, 39,
+ 1, 294, 29,
+ 1, 336, 25,
+ 1, 336, 5,
+ 1, 37, 3,
+ 1, 37, 4,
+ 1, 37, 5,
+ 1, 41, 29,
+ 1, 57, 15,
+ 1, 72, 5,
+ 1, 72, 8,
+ 1, 76, 29,
+ 1, 981, 88,
+ 1, 990, 2,
+ 1, 990, 6,
+ 2, 220, 88,
+ 2, 294, 1,
+ 2, 37, 6,
+ 2, 391, 55,
+ 2, 57, 11,
+ 2, 57, 14,
+ 2, 57, 7,
+ 2, 981, 30,
+ 2, 990, 15,
+ 2, 990, 19,
+ 3, 114, 16,
+ 3, 1166, 39,
+ 3, 1254, 154,
+ 3, 12, 12,
+ 3, 162, 7,
+ 3, 164, 479,
+ 3, 167, 449,
+ 3, 16, 24,
+ 3, 204, 497,
+ 3, 205, 434,
+ 3, 220, 1127,
+ 3, 220, 1132,
+ 3, 220, 931,
+ 3, 220, 933,
+ 3, 220, 934,
+ 3, 297, 8,
+ 3, 72, 25,
+ 3, 87, 30,
+ 3, 981, 1,
+ 3, 981, 126,
+ 3, 990, 27,
+ 3, 990, 36,
+ 3, 991, 29,
+ 4, 1254, 306,
+ 4, 1254, 36,
+ 4, 1, 1,
+ 4, 1, 14,
+ 4, 1, 19,
+ 4, 1, 7,
+ 4, 21, 21,
+ 4, 220, 30,
+ 4, 46, 949,
+ 4, 509, 30,
+ 4, 57, 2,
+ 4, 57, 6,
+ 4, 990, 11,
+ 5, 13, 8,
+ 5, 198, 24,
+ 5, 24, 24,
+ 5, 25, 24,
+ 5, 2, 24,
+ 5, 37, 33,
+ 5, 57, 4,
+ 5, 599, 24,
+ 5, 90, 24,
+ 5, 981, 19,
+ 5, 990, 23,
+ 5, 990, 8,
+ 6, 101, 29,
+ 6, 117, 29,
+ 6, 1254, 88,
+ 6, 139, 29,
+ 6, 13, 12,
+ 6, 15, 15,
+ 6, 164, 25,
+ 6, 16, 16,
+ 6, 198, 7,
+ 6, 1, 12,
+ 6, 1, 15,
+ 6, 1, 27,
+ 6, 220, 936,
+ 6, 24, 7,
+ 6, 25, 7,
+ 6, 2, 7,
+ 6, 326, 29,
+ 6, 336, 29,
+ 6, 599, 7,
+ 6, 86, 29,
+ 6, 90, 7,
+ 6, 96, 29,
+ 6, 991, 31,
+ 7, 198, 12,
+ 7, 198, 20,
+ 7, 198, 33,
+ 7, 198, 35,
+ 7, 24, 12,
+ 7, 24, 20,
+ 7, 24, 33,
+ 7, 24, 35,
+ 7, 25, 12,
+ 7, 25, 20,
+ 7, 25, 33,
+ 7, 25, 35,
+ 7, 2, 12,
+ 7, 2, 20,
+ 7, 2, 33,
+ 7, 2, 35,
+ 7, 304, 1,
+ 7, 38, 29,
+ 7, 51, 29,
+ 7, 599, 12,
+ 7, 599, 20,
+ 7, 599, 33,
+ 7, 599, 35,
+ 7, 90, 12,
+ 7, 90, 20,
+ 7, 90, 33,
+ 7, 90, 35,
+ 8, 13, 5,
+ 8, 198, 13,
+ 8, 198, 23,
+ 8, 220, 1,
+ 8, 24, 13,
+ 8, 24, 23,
+ 8, 25, 13,
+ 8, 25, 23,
+ 8, 2, 13,
+ 8, 2, 23,
+ 8, 329, 28,
+ 8, 57, 10,
+ 8, 599, 13,
+ 8, 599, 23,
+ 8, 90, 13,
+ 8, 90, 23,
+ 9, 198, 17,
+ 9, 198, 19,
+ 9, 198, 37,
+ 9, 198, 5,
+ 9, 198, 8,
+ 9, 24, 17,
+ 9, 24, 19,
+ 9, 24, 37,
+ 9, 24, 5,
+ 9, 24, 8,
+ 9, 25, 17,
+ 9, 25, 19,
+ 9, 25, 37,
+ 9, 25, 5,
+ 9, 25, 8,
+ 9, 2, 17,
+ 9, 2, 19,
+ 9, 2, 37,
+ 9, 2, 5,
+ 9, 2, 8,
+ 9, 599, 17,
+ 9, 599, 19,
+ 9, 599, 37,
+ 9, 599, 5,
+ 9, 599, 8,
+ 9, 72, 29,
+ 9, 90, 17,
+ 9, 90, 19,
+ 9, 90, 37,
+ 9, 90, 5,
+ 9, 90, 8,
+ 10, 13, 11,
+ 10, 13, 9,
+ 10, 198, 26,
+ 10, 198, 28,
+ 10, 1, 23,
+ 10, 1, 4,
+ 10, 1, 6,
+ 10, 24, 26,
+ 10, 24, 28,
+ 10, 25, 26,
+ 10, 25, 28,
+ 10, 26, 24,
+ 10, 2, 26,
+ 10, 2, 28,
+ 10, 599, 26,
+ 10, 599, 28,
+ 10, 90, 26,
+ 10, 90, 28,
+ 11, 198, 27,
+ 11, 24, 27,
+ 11, 25, 27,
+ 11, 2, 27,
+ 11, 599, 27,
+ 11, 90, 27,
+ 12, 198, 14,
+ 12, 198, 21,
+ 12, 198, 3,
+ 12, 1, 11,
+ 12, 1, 2,
+ 12, 1, 8,
+ 12, 24, 14,
+ 12, 24, 21,
+ 12, 24, 3,
+ 12, 25, 14,
+ 12, 25, 21,
+ 12, 25, 3,
+ 12, 26, 7,
+ 12, 2, 14,
+ 12, 2, 21,
+ 12, 2, 3,
+ 12, 329, 14,
+ 12, 38, 2,
+ 12, 599, 14,
+ 12, 599, 21,
+ 12, 599, 3,
+ 12, 90, 14,
+ 12, 90, 21,
+ 12, 90, 3,
+ 13, 198, 11,
+ 13, 198, 15,
+ 13, 198, 31,
+ 13, 24, 11,
+ 13, 24, 15,
+ 13, 24, 31,
+ 13, 25, 11,
+ 13, 25, 15,
+ 13, 25, 31,
+ 13, 2, 11,
+ 13, 2, 15,
+ 13, 2, 31,
+ 13, 57, 13,
+ 13, 599, 11,
+ 13, 599, 15,
+ 13, 599, 31,
+ 13, 71, 29,
+ 13, 90, 11,
+ 13, 90, 15,
+ 13, 90, 31,
+ 14, 13, 2,
+ 14, 198, 10,
+ 14, 24, 10,
+ 14, 25, 10,
+ 14, 26, 12,
+ 14, 26, 20,
+ 14, 26, 33,
+ 14, 26, 35,
+ 14, 2, 10,
+ 14, 336, 1,
+ 14, 45, 29,
+ 14, 599, 10,
+ 14, 63, 29,
+ 14, 90, 10,
+ 15, 13, 3,
+ 15, 198, 2,
+ 15, 198, 29,
+ 15, 198, 34,
+ 15, 24, 2,
+ 15, 24, 29,
+ 15, 24, 34,
+ 15, 25, 2,
+ 15, 25, 29,
+ 15, 25, 34,
+ 15, 2, 2,
+ 15, 2, 29,
+ 15, 2, 34,
+ 15, 599, 2,
+ 15, 599, 29,
+ 15, 599, 34,
+ 15, 90, 2,
+ 15, 90, 29,
+ 15, 90, 34,
+ 16, 13, 4,
+ 16, 13, 6,
+ 16, 198, 16,
+ 16, 198, 9,
+ 16, 1, 10,
+ 16, 24, 16,
+ 16, 24, 9,
+ 16, 25, 16,
+ 16, 25, 9,
+ 16, 26, 13,
+ 16, 26, 23,
+ 16, 2, 16,
+ 16, 2, 9,
+ 16, 599, 16,
+ 16, 599, 9,
+ 16, 90, 16,
+ 16, 90, 9,
+ 17, 13, 7,
+ 17, 198, 18,
+ 17, 24, 18,
+ 17, 25, 18,
+ 17, 2, 18,
+ 17, 599, 18,
+ 17, 90, 18,
+ 18, 198, 22,
+ 18, 198, 32,
+ 18, 198, 36,
+ 18, 198, 4,
+ 18, 24, 22,
+ 18, 24, 32,
+ 18, 24, 36,
+ 18, 24, 4,
+ 18, 25, 22,
+ 18, 25, 32,
+ 18, 25, 36,
+ 18, 25, 4,
+ 18, 26, 17,
+ 18, 26, 19,
+ 18, 26, 37,
+ 18, 26, 5,
+ 18, 26, 8,
+ 18, 2, 22,
+ 18, 2, 32,
+ 18, 2, 36,
+ 18, 2, 4,
+ 18, 599, 22,
+ 18, 599, 32,
+ 18, 599, 36,
+ 18, 599, 4,
+ 18, 90, 22,
+ 18, 90, 32,
+ 18, 90, 36,
+ 18, 90, 4,
+ 19, 13, 10,
+ 20, 1254, 30,
+ 20, 16, 1007,
+ 20, 26, 26,
+ 20, 26, 28,
+ 21, 198, 6,
+ 21, 24, 6,
+ 21, 25, 6,
+ 21, 2, 6,
+ 21, 599, 6,
+ 21, 90, 6,
+ 22, 198, 38,
+ 22, 22, 40,
+ 22, 24, 38,
+ 22, 25, 38,
+ 22, 26, 27,
+ 22, 2, 38,
+ 22, 599, 38,
+ 22, 90, 38,
+ 23, 1254, 1160,
+ 24, 220, 930,
+ 24, 26, 14,
+ 24, 26, 21,
+ 24, 26, 3,
+ 26, 11, 11,
+ 26, 1, 13,
+ 26, 26, 11,
+ 26, 26, 15,
+ 26, 26, 31,
+ 28, 26, 10,
+ 30, 176, 60,
+ 30, 26, 2,
+ 30, 26, 29,
+ 30, 26, 34,
+ 32, 26, 16,
+ 32, 26, 9,
+ 34, 26, 18,
+ 36, 26, 22,
+ 36, 26, 32,
+ 36, 26, 36,
+ 36, 26, 4,
+ 36, 37, 26,
+ 42, 26, 6,
+ 43, 115, 29,
+ 44, 198, 25,
+ 44, 24, 25,
+ 44, 25, 25,
+ 44, 26, 38,
+ 44, 2, 25,
+ 44, 599, 25,
+ 44, 90, 25,
+ 46, 22, 1,
+ 47, 198, 30,
+ 47, 25, 30,
+ 47, 2, 30,
+ 47, 599, 30,
+ 47, 90, 30,
+ 48, 24, 30,
+ 52, 176, 30,
+ 58, 140, 24,
+ 58, 4, 30,
+ 63, 990, 29,
+ 64, 1254, 1,
+ 88, 26, 25,
+ 92, 198, 39,
+ 92, 25, 39,
+ 92, 2, 39,
+ 92, 599, 39,
+ 92, 90, 39,
+ 93, 24, 39,
+ 94, 26, 30,
+ 108, 1254, 1051,
+ 117, 140, 1,
+ 119, 160, 1,
+ 126, 1, 29,
+ 132, 135, 16,
+ 147, 72, 16,
+ 184, 26, 39,
+ 238, 990, 1,
+ 376, 11, 1007,
+ 380, 11, 487,
+ 1389, 1034, 1007,
+ 1870, 57, 16,
+ 4034, 1, 16,
+ 8521, 198, 40,
+ 8521, 25, 40,
+ 8521, 2, 40,
+ 8521, 599, 40,
+ 8521, 90, 40,
+ 8543, 24, 40,
+ 8883, 13, 13,
+ 17042, 26, 40,
+ 17664, 198, 1,
+ 17664, 25, 1,
+ 17664, 2, 1,
+ 17664, 599, 1,
+ 17664, 90, 1,
+ 17710, 24, 1,
+ 35328, 26, 1,
+};
+
+/// Emulates the mix of rects blitted by gmail during scrolling
+class ScrollGmailBench : public SkBenchmark {
+ enum {
+ W = 1254,
+ H = 1160,
+ N = 431
+ };
+public:
+ ScrollGmailBench(void* param) : INHERITED(param) { }
+
+protected:
+
+ virtual const char* onGetName() { return "chrome_scrollGmail"; }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkDEBUGCODE(this->validateBounds(canvas));
+ SkPaint paint;
+ this->setupPaint(&paint);
+ for (int i = 0; i < N; i++) {
+ SkRect current;
+ setRectangle(current, i);
+ for (int j = 0; j < SkBENCHLOOP(gmailScrollingRectSpec[i*3]); j++) {
+ canvas->drawRect(current, paint);
+ }
+ }
+ }
+ virtual SkIPoint onGetSize() { return SkIPoint::Make(W, H); }
+
+ void setRectangle(SkRect& current, int i) {
+ current.set(0, 0,
+ SkIntToScalar(gmailScrollingRectSpec[i*3+1]), SkIntToScalar(gmailScrollingRectSpec[i*3+2]));
+ }
+ void validateBounds(SkCanvas* canvas) {
+ SkIRect bounds;
+ canvas->getClipDeviceBounds(&bounds);
+ SkASSERT(bounds.right()-bounds.left() >= W);
+ SkASSERT(bounds.bottom()-bounds.top() >= H);
+ }
+
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+static SkBenchmark* ScrollGmailFactory(void* p) {
+ return SkNEW_ARGS(ScrollGmailBench, (p));
+}
+
+static BenchRegistry gScrollGmailReg(ScrollGmailFactory);
diff --git a/bench/DecodeBench.cpp b/bench/DecodeBench.cpp
index ac11089..6761690 100644
--- a/bench/DecodeBench.cpp
+++ b/bench/DecodeBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkImageDecoder.h"
@@ -11,7 +18,7 @@ class DecodeBench : public SkBenchmark {
const char* fFilename;
SkBitmap::Config fPrefConfig;
SkString fName;
- enum { N = 10 };
+ enum { N = SkBENCHLOOP(10) };
public:
DecodeBench(void* param, SkBitmap::Config c) : SkBenchmark(param) {
fFilename = this->findDefine("decode-filename");
diff --git a/bench/FPSBench.cpp b/bench/FPSBench.cpp
deleted file mode 100644
index 28668fe..0000000
--- a/bench/FPSBench.cpp
+++ /dev/null
@@ -1,108 +0,0 @@
-#include "SkBenchmark.h"
-#include "SkCanvas.h"
-#include "SkPaint.h"
-#include "SkRandom.h"
-#include "SkString.h"
-
-class FPSBench : public SkBenchmark {
- int32_t fWidth;
- int32_t fHeight;
-public:
- FPSBench(void* p) : INHERITED(p) {
- fWidth = 640;
- (void)this->findDefine32("width", &fWidth);
- fHeight = 480;
- (void)this->findDefine32("height", &fHeight);
- }
-
- int width() const { return fWidth; }
- int height() const { return fHeight; }
-
-protected:
- virtual SkIPoint onGetSize() { return SkIPoint::Make(fWidth, fHeight); }
-
-private:
- typedef SkBenchmark INHERITED;
-};
-
-///////////////////////////////////////////////////////////////////////////////
-
-class Color_FPSBench : public FPSBench {
-public:
- Color_FPSBench(void* p, SkColor c, const char name[]) : INHERITED(p) {
- fColor = c;
- fName = name;
- }
-
-protected:
- virtual const char* onGetName() { return fName; }
- virtual void onDraw(SkCanvas* canvas) {
- canvas->drawColor(fColor);
- }
-
-private:
- const char* fName;
- SkColor fColor;
-
- typedef FPSBench INHERITED;
-};
-
-class Bitmap_FPSBench : public FPSBench {
-public:
- Bitmap_FPSBench(void* p, SkBitmap::Config config, bool doOpaque, bool doScale) : INHERITED(p) {
- fBitmap.setConfig(config, this->width(), this->height());
- fBitmap.allocPixels();
- fBitmap.eraseColor(0xFFFF0000);
- if (doOpaque) {
- fBitmap.setIsOpaque(true);
- }
-
- const char* configStr = "565";
- if (config == SkBitmap::kARGB_8888_Config) {
- if (doOpaque) {
- configStr = "X888";
- } else {
- configStr = "8888";
- }
- }
- fName.printf("fps_bitmap_%s_%s", configStr,
- doScale ? "scale" : "noscale");
-
- fMatrix.reset();
- if (doScale) {
- fMatrix.setScale(SkIntToScalar(3)/2, SkIntToScalar(3)/2);
- }
- }
-
-protected:
- virtual const char* onGetName() { return fName.c_str(); }
- virtual void onDraw(SkCanvas* canvas) {
- canvas->drawBitmapMatrix(fBitmap, fMatrix);
- }
-
-private:
- SkBitmap fBitmap;
- SkMatrix fMatrix;
- SkString fName;
-
- typedef FPSBench INHERITED;
-};
-
-static SkBenchmark* FillFactory(void* p) { return SkNEW_ARGS(Color_FPSBench, (p, 0xFFFF0000, "fps_fill")); }
-static SkBenchmark* BlendFactory(void* p) { return SkNEW_ARGS(Color_FPSBench, (p, 0x80FF0000, "fps_blend")); }
-static SkBenchmark* BMFactory0(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, false, false)); }
-static SkBenchmark* BMFactory1(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, false, true)); }
-static SkBenchmark* BMFactory2(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, true, false)); }
-static SkBenchmark* BMFactory3(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kARGB_8888_Config, true, true)); }
-static SkBenchmark* BMFactory4(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kRGB_565_Config, false, false)); }
-static SkBenchmark* BMFactory5(void* p) { return SkNEW_ARGS(Bitmap_FPSBench, (p, SkBitmap::kRGB_565_Config, false, true)); }
-
-static BenchRegistry gFillReg(FillFactory);
-static BenchRegistry gBlendReg(BlendFactory);
-static BenchRegistry gBMReg0(BMFactory0);
-static BenchRegistry gBMReg1(BMFactory1);
-static BenchRegistry gBMReg2(BMFactory2);
-static BenchRegistry gBMReg3(BMFactory3);
-static BenchRegistry gBMReg4(BMFactory4);
-static BenchRegistry gBMReg5(BMFactory5);
-
diff --git a/bench/FontScalerBench.cpp b/bench/FontScalerBench.cpp
new file mode 100644
index 0000000..4ac6a35
--- /dev/null
+++ b/bench/FontScalerBench.cpp
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkGraphics.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkString.h"
+
+extern bool gSkSuppressFontCachePurgeSpew;
+
+class FontScalerBench : public SkBenchmark {
+ SkString fName;
+ SkString fText;
+ bool fDoLCD;
+public:
+ FontScalerBench(void* param, bool doLCD) : INHERITED(param) {
+ fName.printf("fontscaler_%s", doLCD ? "lcd" : "aa");
+ fText.set("abcdefghijklmnopqrstuvwxyz01234567890");
+ fDoLCD = doLCD;
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+ paint.setLCDRenderText(fDoLCD);
+
+ bool prev = gSkSuppressFontCachePurgeSpew;
+ gSkSuppressFontCachePurgeSpew = true;
+
+ // this is critical - we want to time the creation process, so we
+ // explicitly flush our cache before each run
+ SkGraphics::PurgeFontCache();
+
+ for (int ps = 9; ps <= 24; ps += 2) {
+ paint.setTextSize(SkIntToScalar(ps));
+ canvas->drawText(fText.c_str(), fText.size(),
+ 0, SkIntToScalar(20), paint);
+ }
+
+ gSkSuppressFontCachePurgeSpew = prev;
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact0(void* p) { return SkNEW_ARGS(FontScalerBench, (p, false)); }
+static SkBenchmark* Fact1(void* p) { return SkNEW_ARGS(FontScalerBench, (p, true)); }
+
+static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg1(Fact1);
diff --git a/bench/GradientBench.cpp b/bench/GradientBench.cpp
index 5ecca6b..a5032ea 100644
--- a/bench/GradientBench.cpp
+++ b/bench/GradientBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -31,23 +38,29 @@ static const GradData gGradData[] = {
{ 5, gColors, gPos2 }
};
+/// Ignores scale
static SkShader* MakeLinear(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
return SkGradientShader::CreateLinear(pts, data.fColors, data.fPos,
data.fCount, tm, mapper);
}
static SkShader* MakeRadial(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center;
center.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
- return SkGradientShader::CreateRadial(center, center.fX, data.fColors,
+ return SkGradientShader::CreateRadial(center, center.fX * scale,
+ data.fColors,
data.fPos, data.fCount, tm, mapper);
}
+/// Ignores scale
static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center;
center.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
@@ -55,21 +68,24 @@ static SkShader* MakeSweep(const SkPoint pts[2], const GradData& data,
data.fPos, data.fCount, mapper);
}
+/// Ignores scale
static SkShader* Make2Radial(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper) {
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale) {
SkPoint center0, center1;
center0.set(SkScalarAve(pts[0].fX, pts[1].fX),
SkScalarAve(pts[0].fY, pts[1].fY));
center1.set(SkScalarInterp(pts[0].fX, pts[1].fX, SkIntToScalar(3)/5),
SkScalarInterp(pts[0].fY, pts[1].fY, SkIntToScalar(1)/4));
return SkGradientShader::CreateTwoPointRadial(
- center1, (pts[1].fX - pts[0].fX) / 7,
- center0, (pts[1].fX - pts[0].fX) / 2,
- data.fColors, data.fPos, data.fCount, tm, mapper);
+ center1, (pts[1].fX - pts[0].fX) / 7,
+ center0, (pts[1].fX - pts[0].fX) / 2,
+ data.fColors, data.fPos, data.fCount, tm, mapper);
}
typedef SkShader* (*GradMaker)(const SkPoint pts[2], const GradData& data,
- SkShader::TileMode tm, SkUnitMapper* mapper);
+ SkShader::TileMode tm, SkUnitMapper* mapper,
+ float scale);
static const struct {
GradMaker fMaker;
@@ -89,6 +105,37 @@ enum GradType { // these must match the order in gGrads
kRadial2_GradType
};
+enum GeomType {
+ kRect_GeomType,
+ kOval_GeomType
+};
+
+static const char* tilemodename(SkShader::TileMode tm) {
+ switch (tm) {
+ case SkShader::kClamp_TileMode:
+ return "clamp";
+ case SkShader::kRepeat_TileMode:
+ return "repeat";
+ case SkShader::kMirror_TileMode:
+ return "mirror";
+ default:
+ SkASSERT(!"unknown tilemode");
+ return "error";
+ }
+}
+
+static const char* geomtypename(GeomType gt) {
+ switch (gt) {
+ case kRect_GeomType:
+ return "rectangle";
+ case kOval_GeomType:
+ return "oval";
+ default:
+ SkASSERT(!"unknown geometry type");
+ return "error";
+ }
+}
+
///////////////////////////////////////////////////////////////////////////////
class GradientBench : public SkBenchmark {
@@ -101,17 +148,26 @@ class GradientBench : public SkBenchmark {
N = 1
};
public:
- GradientBench(void* param, GradType gt) : INHERITED(param) {
- fName.printf("gradient_%s", gGrads[gt].fName);
+ GradientBench(void* param, GradType gradType,
+ SkShader::TileMode tm = SkShader::kClamp_TileMode,
+ GeomType geomType = kRect_GeomType,
+ float scale = 1.0f)
+ : INHERITED(param) {
+ fName.printf("gradient_%s_%s", gGrads[gradType].fName,
+ tilemodename(tm));
+ if (geomType != kRect_GeomType) {
+ fName.append("_");
+ fName.append(geomtypename(geomType));
+ }
const SkPoint pts[2] = {
{ 0, 0 },
{ SkIntToScalar(W), SkIntToScalar(H) }
};
- fCount = N * gGrads[gt].fRepeat;
- fShader = gGrads[gt].fMaker(pts, gGradData[0],
- SkShader::kClamp_TileMode, NULL);
+ fCount = SkBENCHLOOP(N * gGrads[gradType].fRepeat);
+ fShader = gGrads[gradType].fMaker(pts, gGradData[0], tm, NULL, scale);
+ fGeomType = geomType;
}
virtual ~GradientBench() {
@@ -131,21 +187,86 @@ protected:
SkRect r = { 0, 0, SkIntToScalar(W), SkIntToScalar(H) };
for (int i = 0; i < fCount; i++) {
- canvas->drawRect(r, paint);
+ switch (fGeomType) {
+ case kRect_GeomType:
+ canvas->drawRect(r, paint);
+ break;
+ case kOval_GeomType:
+ canvas->drawOval(r, paint);
+ break;
+ }
}
}
private:
typedef SkBenchmark INHERITED;
+
+ GeomType fGeomType;
+};
+
+class Gradient2Bench : public SkBenchmark {
+public:
+ Gradient2Bench(void* param) : INHERITED(param) {}
+
+protected:
+ virtual const char* onGetName() {
+ return "gradient_create";
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ const SkRect r = { 0, 0, SkIntToScalar(4), SkIntToScalar(4) };
+ const SkPoint pts[] = {
+ { 0, 0 },
+ { SkIntToScalar(100), SkIntToScalar(100) },
+ };
+
+ for (int i = 0; i < SkBENCHLOOP(1000); i++) {
+ const int a = i % 256;
+ SkColor colors[] = {
+ SK_ColorBLACK,
+ SkColorSetARGB(a, a, a, a),
+ SK_ColorWHITE };
+ SkShader* s = SkGradientShader::CreateLinear(pts, colors, NULL,
+ SK_ARRAY_COUNT(colors),
+ SkShader::kClamp_TileMode);
+ paint.setShader(s)->unref();
+ canvas->drawRect(r, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
};
static SkBenchmark* Fact0(void* p) { return new GradientBench(p, kLinear_GradType); }
-static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType); }
+static SkBenchmark* Fact01(void* p) { return new GradientBench(p, kLinear_GradType, SkShader::kMirror_TileMode); }
+
+// Draw a radial gradient of radius 1/2 on a rectangle; half the lines should
+// be completely pinned, the other half should pe partially pinned
+static SkBenchmark* Fact1(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kRect_GeomType, 0.5f); }
+
+// Draw a radial gradient on a circle of equal size; all the lines should
+// hit the unpinned fast path (so long as GradientBench.W == H)
+static SkBenchmark* Fact1o(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kClamp_TileMode, kOval_GeomType); }
+
+static SkBenchmark* Fact11(void* p) { return new GradientBench(p, kRadial_GradType, SkShader::kMirror_TileMode); }
static SkBenchmark* Fact2(void* p) { return new GradientBench(p, kSweep_GradType); }
static SkBenchmark* Fact3(void* p) { return new GradientBench(p, kRadial2_GradType); }
+static SkBenchmark* Fact31(void* p) { return new GradientBench(p, kRadial2_GradType, SkShader::kMirror_TileMode); }
+
+static SkBenchmark* Fact4(void* p) { return new Gradient2Bench(p); }
static BenchRegistry gReg0(Fact0);
+static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg1(Fact1);
+static BenchRegistry gReg1o(Fact1o);
+static BenchRegistry gReg11(Fact11);
static BenchRegistry gReg2(Fact2);
static BenchRegistry gReg3(Fact3);
+static BenchRegistry gReg31(Fact31);
+
+static BenchRegistry gReg4(Fact4);
diff --git a/bench/Makefile.am b/bench/Makefile.am
deleted file mode 100644
index 2b67862..0000000
--- a/bench/Makefile.am
+++ /dev/null
@@ -1,20 +0,0 @@
-AM_CPPFLAGS = -I$(top_builddir)/include/core -I$(top_builddir)/include/images
-AM_LDFLAGS = -lpng -lpthread
-
-bin_PROGRAMS = Bench
-Bench_SOURCES = RectBench.cpp \
- FPSBench.cpp \
- SkBenchmark.cpp \
- BenchTool/main.cpp \
- $(top_builddir)/src/images/SkImageDecoder.cpp \
- $(top_builddir)/src/images/SkImageDecoder_libpng.cpp \
- $(top_builddir)/src/images/SkScaledBitmapSampler.cpp \
- $(top_builddir)/src/ports/SkGlobals_global.cpp \
- $(top_builddir)/src/ports/SkOSFile_stdio.cpp \
- $(top_builddir)/src/ports/SkThread_pthread.cpp \
- $(top_builddir)/src/ports/SkTime_Unix.cpp \
- $(top_builddir)/src/ports/SkFontHost_none.cpp
-
-
-Bench_LDADD = $(top_builddir)/src/core/libskia.a
-
diff --git a/bench/MathBench.cpp b/bench/MathBench.cpp
new file mode 100644
index 0000000..9feb5af
--- /dev/null
+++ b/bench/MathBench.cpp
@@ -0,0 +1,316 @@
+#include "SkBenchmark.h"
+#include "SkColorPriv.h"
+#include "SkMatrix.h"
+#include "SkRandom.h"
+#include "SkString.h"
+#include "SkPaint.h"
+
+class MathBench : public SkBenchmark {
+ enum {
+ kBuffer = 100,
+ kLoop = 10000
+ };
+ SkString fName;
+ float fSrc[kBuffer], fDst[kBuffer];
+public:
+ MathBench(void* param, const char name[]) : INHERITED(param) {
+ fName.printf("math_%s", name);
+
+ SkRandom rand;
+ for (int i = 0; i < kBuffer; ++i) {
+ fSrc[i] = rand.nextSScalar1();
+ }
+ }
+
+ virtual void performTest(float dst[], const float src[], int count) = 0;
+
+protected:
+ virtual int mulLoopCount() const { return 1; }
+
+ virtual const char* onGetName() {
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ int n = SkBENCHLOOP(kLoop * this->mulLoopCount());
+ for (int i = 0; i < n; i++) {
+ this->performTest(fDst, fSrc, kBuffer);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+class MathBenchU32 : public MathBench {
+public:
+ MathBenchU32(void* param, const char name[]) : INHERITED(param, name) {}
+
+protected:
+ virtual void performITest(uint32_t* dst, const uint32_t* src, int count) = 0;
+
+ virtual void performTest(float* SK_RESTRICT dst, const float* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ uint32_t* d = SkTCast<uint32_t*>(dst);
+ const uint32_t* s = SkTCast<const uint32_t*>(src);
+ this->performITest(d, s, count);
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+class NoOpMathBench : public MathBench {
+public:
+ NoOpMathBench(void* param) : INHERITED(param, "noOp") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = src[i] + 1;
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+class SlowISqrtMathBench : public MathBench {
+public:
+ SlowISqrtMathBench(void* param) : INHERITED(param, "slowIsqrt") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = 1.0f / sk_float_sqrt(src[i]);
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+static inline float SkFastInvSqrt(float x) {
+ float xhalf = 0.5f*x;
+ int i = *(int*)&x;
+ i = 0x5f3759df - (i>>1);
+ x = *(float*)&i;
+ x = x*(1.5f-xhalf*x*x);
+// x = x*(1.5f-xhalf*x*x); // this line takes err from 10^-3 to 10^-6
+ return x;
+}
+
+class FastISqrtMathBench : public MathBench {
+public:
+ FastISqrtMathBench(void* param) : INHERITED(param, "fastIsqrt") {}
+protected:
+ virtual void performTest(float dst[], const float src[], int count) {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = SkFastInvSqrt(src[i]);
+ }
+ }
+private:
+ typedef MathBench INHERITED;
+};
+
+static inline uint32_t QMul64(uint32_t value, U8CPU alpha) {
+ SkASSERT((uint8_t)alpha == alpha);
+ const uint32_t mask = 0xFF00FF;
+
+ uint64_t tmp = value;
+ tmp = (tmp & mask) | ((tmp & ~mask) << 24);
+ tmp *= alpha;
+ return ((tmp >> 8) & mask) | ((tmp >> 32) & ~mask);
+}
+
+class QMul64Bench : public MathBenchU32 {
+public:
+ QMul64Bench(void* param) : INHERITED(param, "qmul64") {}
+protected:
+ virtual void performITest(uint32_t* SK_RESTRICT dst,
+ const uint32_t* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = QMul64(src[i], (uint8_t)i);
+ }
+ }
+private:
+ typedef MathBenchU32 INHERITED;
+};
+
+class QMul32Bench : public MathBenchU32 {
+public:
+ QMul32Bench(void* param) : INHERITED(param, "qmul32") {}
+protected:
+ virtual void performITest(uint32_t* SK_RESTRICT dst,
+ const uint32_t* SK_RESTRICT src,
+ int count) SK_OVERRIDE {
+ for (int i = 0; i < count; ++i) {
+ dst[i] = SkAlphaMulQ(src[i], (uint8_t)i);
+ }
+ }
+private:
+ typedef MathBenchU32 INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static bool isFinite_int(float x) {
+ uint32_t bits = SkFloat2Bits(x); // need unsigned for our shifts
+ int exponent = bits << 1 >> 24;
+ return exponent != 0xFF;
+}
+
+static bool isFinite_float(float x) {
+ return sk_float_isfinite(x);
+}
+
+static bool isFinite_mulzero(float x) {
+ float y = x * 0;
+ return y == y;
+}
+
+static bool isfinite_and_int(const float data[4]) {
+ return isFinite_int(data[0]) && isFinite_int(data[1]) && isFinite_int(data[2]) && isFinite_int(data[3]);
+}
+
+static bool isfinite_and_float(const float data[4]) {
+ return isFinite_float(data[0]) && isFinite_float(data[1]) && isFinite_float(data[2]) && isFinite_float(data[3]);
+}
+
+static bool isfinite_and_mulzero(const float data[4]) {
+ return isFinite_mulzero(data[0]) && isFinite_mulzero(data[1]) && isFinite_mulzero(data[2]) && isFinite_mulzero(data[3]);
+}
+
+#define mulzeroadd(data) (data[0]*0 + data[1]*0 + data[2]*0 + data[3]*0)
+
+static bool isfinite_plus_int(const float data[4]) {
+ return isFinite_int(mulzeroadd(data));
+}
+
+static bool isfinite_plus_float(const float data[4]) {
+ return !sk_float_isnan(mulzeroadd(data));
+}
+
+static bool isfinite_plus_mulzero(const float data[4]) {
+ float x = mulzeroadd(data);
+ return x == x;
+}
+
+typedef bool (*IsFiniteProc)(const float[]);
+
+#define MAKEREC(name) { name, #name }
+
+static const struct {
+ IsFiniteProc fProc;
+ const char* fName;
+} gRec[] = {
+ MAKEREC(isfinite_and_int),
+ MAKEREC(isfinite_and_float),
+ MAKEREC(isfinite_and_mulzero),
+ MAKEREC(isfinite_plus_int),
+ MAKEREC(isfinite_plus_float),
+ MAKEREC(isfinite_plus_mulzero),
+};
+
+#undef MAKEREC
+
+static bool isFinite(const SkRect& r) {
+ // x * 0 will be NaN iff x is infinity or NaN.
+ // a + b will be NaN iff either a or b is NaN.
+ float value = r.fLeft * 0 + r.fTop * 0 + r.fRight * 0 + r.fBottom * 0;
+
+ // value is either NaN or it is finite (zero).
+ // value==value will be true iff value is not NaN
+ return value == value;
+}
+
+class IsFiniteBench : public SkBenchmark {
+ enum {
+ N = SkBENCHLOOP(1000),
+ NN = SkBENCHLOOP(1000),
+ };
+ float fData[N];
+public:
+
+ IsFiniteBench(void* param, int index) : INHERITED(param) {
+ SkRandom rand;
+
+ for (int i = 0; i < N; ++i) {
+ fData[i] = rand.nextSScalar1();
+ }
+
+ if (index < 0) {
+ fProc = NULL;
+ fName = "isfinite_rect";
+ } else {
+ fProc = gRec[index].fProc;
+ fName = gRec[index].fName;
+ }
+ }
+
+protected:
+ virtual void onDraw(SkCanvas* canvas) {
+ IsFiniteProc proc = fProc;
+ const float* data = fData;
+ // do this so the compiler won't throw away the function call
+ int counter = 0;
+
+ if (proc) {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ counter += proc(&data[i]);
+ }
+ }
+ } else {
+ for (int j = 0; j < NN; ++j) {
+ for (int i = 0; i < N - 4; ++i) {
+ const SkRect* r = reinterpret_cast<const SkRect*>(&data[i]);
+ counter += r->isFinite();
+ }
+ }
+ }
+
+ SkPaint paint;
+ if (paint.getAlpha() == 0) {
+ SkDebugf("%d\n", counter);
+ }
+ }
+
+ virtual const char* onGetName() {
+ return fName;
+ }
+
+private:
+ IsFiniteProc fProc;
+ const char* fName;
+
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* M0(void* p) { return new NoOpMathBench(p); }
+static SkBenchmark* M1(void* p) { return new SlowISqrtMathBench(p); }
+static SkBenchmark* M2(void* p) { return new FastISqrtMathBench(p); }
+static SkBenchmark* M3(void* p) { return new QMul64Bench(p); }
+static SkBenchmark* M4(void* p) { return new QMul32Bench(p); }
+
+static SkBenchmark* M5neg1(void* p) { return new IsFiniteBench(p, -1); }
+static SkBenchmark* M50(void* p) { return new IsFiniteBench(p, 0); }
+static SkBenchmark* M51(void* p) { return new IsFiniteBench(p, 1); }
+static SkBenchmark* M52(void* p) { return new IsFiniteBench(p, 2); }
+static SkBenchmark* M53(void* p) { return new IsFiniteBench(p, 3); }
+static SkBenchmark* M54(void* p) { return new IsFiniteBench(p, 4); }
+static SkBenchmark* M55(void* p) { return new IsFiniteBench(p, 5); }
+
+static BenchRegistry gReg0(M0);
+static BenchRegistry gReg1(M1);
+static BenchRegistry gReg2(M2);
+static BenchRegistry gReg3(M3);
+static BenchRegistry gReg4(M4);
+
+static BenchRegistry gReg5neg1(M5neg1);
+static BenchRegistry gReg50(M50);
+static BenchRegistry gReg51(M51);
+static BenchRegistry gReg52(M52);
+static BenchRegistry gReg53(M53);
+static BenchRegistry gReg54(M54);
+static BenchRegistry gReg55(M55);
diff --git a/bench/MatrixBench.cpp b/bench/MatrixBench.cpp
index dce0358..a2e459a 100644
--- a/bench/MatrixBench.cpp
+++ b/bench/MatrixBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkMatrix.h"
#include "SkRandom.h"
@@ -21,7 +28,7 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- int n = N * this->mulLoopCount();
+ int n = SkBENCHLOOP(N * this->mulLoopCount());
for (int i = 0; i < n; i++) {
this->performTest();
}
@@ -56,9 +63,6 @@ protected:
always_do(m0 == m1);
always_do(m1 == m2);
always_do(m2 == m0);
- always_do(m0.getType());
- always_do(m1.getType());
- always_do(m2.getType());
}
private:
typedef MatrixBench INHERITED;
@@ -214,26 +218,71 @@ private:
typedef MatrixBench INHERITED;
};
+class GetTypeMatrixBench : public MatrixBench {
+public:
+ GetTypeMatrixBench(void* param)
+ : INHERITED(param, "gettype") {
+ fArray[0] = (float) fRnd.nextS();
+ fArray[1] = (float) fRnd.nextS();
+ fArray[2] = (float) fRnd.nextS();
+ fArray[3] = (float) fRnd.nextS();
+ fArray[4] = (float) fRnd.nextS();
+ fArray[5] = (float) fRnd.nextS();
+ fArray[6] = (float) fRnd.nextS();
+ fArray[7] = (float) fRnd.nextS();
+ fArray[8] = (float) fRnd.nextS();
+ }
+protected:
+ // Putting random generation of the matrix inside performTest()
+ // would help us avoid anomalous runs, but takes up 25% or
+ // more of the function time.
+ virtual void performTest() {
+ fMatrix.setAll(fArray[0], fArray[1], fArray[2],
+ fArray[3], fArray[4], fArray[5],
+ fArray[6], fArray[7], fArray[8]);
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ fMatrix.dirtyMatrixTypeCache();
+ always_do(fMatrix.getType());
+ }
+private:
+ SkMatrix fMatrix;
+ float fArray[9];
+ SkRandom fRnd;
+ typedef MatrixBench INHERITED;
+};
+
#ifdef SK_SCALAR_IS_FLOAT
class ScaleTransMixedMatrixBench : public MatrixBench {
public:
ScaleTransMixedMatrixBench(void* p) : INHERITED(p, "scaletrans_mixed"), fCount (16) {
- fMatrix.setAll(fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
- fRandom.nextS(), fRandom.nextS(), fRandom.nextS(),
- fRandom.nextS(), fRandom.nextS(), fRandom.nextS());
+ fMatrix.setAll(fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
+ fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1(),
+ fRandom.nextSScalar1(), fRandom.nextSScalar1(), fRandom.nextSScalar1());
int i;
- for (i = 0; i < fCount; i++) {
- fSrc[i].fX = fRandom.nextS();
- fSrc[i].fY = fRandom.nextS();
- fDst[i].fX = fRandom.nextS();
- fDst[i].fY = fRandom.nextS();
+ for (i = 0; i < SkBENCHLOOP(fCount); i++) {
+ fSrc[i].fX = fRandom.nextSScalar1();
+ fSrc[i].fY = fRandom.nextSScalar1();
+ fDst[i].fX = fRandom.nextSScalar1();
+ fDst[i].fY = fRandom.nextSScalar1();
}
}
protected:
virtual void performTest() {
SkPoint* dst = fDst;
const SkPoint* src = fSrc;
- int count = fCount;
+ int count = SkBENCHLOOP(fCount);
float mx = fMatrix[SkMatrix::kMScaleX];
float my = fMatrix[SkMatrix::kMScaleY];
float tx = fMatrix[SkMatrix::kMTransX];
@@ -254,29 +303,28 @@ class ScaleTransMixedMatrixBench : public MatrixBench {
typedef MatrixBench INHERITED;
};
-
class ScaleTransDoubleMatrixBench : public MatrixBench {
public:
ScaleTransDoubleMatrixBench(void* p) : INHERITED(p, "scaletrans_double"), fCount (16) {
init9(fMatrix);
int i;
- for (i = 0; i < fCount; i++) {
- fSrc[i].fX = fRandom.nextS();
- fSrc[i].fY = fRandom.nextS();
- fDst[i].fX = fRandom.nextS();
- fDst[i].fY = fRandom.nextS();
+ for (i = 0; i < SkBENCHLOOP(fCount); i++) {
+ fSrc[i].fX = fRandom.nextSScalar1();
+ fSrc[i].fY = fRandom.nextSScalar1();
+ fDst[i].fX = fRandom.nextSScalar1();
+ fDst[i].fY = fRandom.nextSScalar1();
}
}
protected:
virtual void performTest() {
SkPoint* dst = fDst;
const SkPoint* src = fSrc;
- int count = fCount;
+ int count = SkBENCHLOOP(fCount);
// As doubles, on Z600 Linux systems this is 2.5x as expensive as mixed mode
- float mx = fMatrix[SkMatrix::kMScaleX];
- float my = fMatrix[SkMatrix::kMScaleY];
- float tx = fMatrix[SkMatrix::kMTransX];
- float ty = fMatrix[SkMatrix::kMTransY];
+ float mx = (float) fMatrix[SkMatrix::kMScaleX];
+ float my = (float) fMatrix[SkMatrix::kMScaleY];
+ float tx = (float) fMatrix[SkMatrix::kMTransX];
+ float ty = (float) fMatrix[SkMatrix::kMTransY];
do {
dst->fY = src->fY * my + ty;
dst->fX = src->fX * mx + tx;
@@ -303,12 +351,14 @@ static SkBenchmark* M1(void* p) { return new ScaleMatrixBench(p); }
static SkBenchmark* M2(void* p) { return new FloatConcatMatrixBench(p); }
static SkBenchmark* M3(void* p) { return new FloatDoubleConcatMatrixBench(p); }
static SkBenchmark* M4(void* p) { return new DoubleConcatMatrixBench(p); }
+static SkBenchmark* M5(void* p) { return new GetTypeMatrixBench(p); }
static BenchRegistry gReg0(M0);
static BenchRegistry gReg1(M1);
static BenchRegistry gReg2(M2);
static BenchRegistry gReg3(M3);
static BenchRegistry gReg4(M4);
+static BenchRegistry gReg5(M5);
#ifdef SK_SCALAR_IS_FLOAT
static SkBenchmark* FlM0(void* p) { return new ScaleTransMixedMatrixBench(p); }
diff --git a/bench/MutexBench.cpp b/bench/MutexBench.cpp
new file mode 100644
index 0000000..d9b427b
--- /dev/null
+++ b/bench/MutexBench.cpp
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkThread.h"
+
+class MutexBench : public SkBenchmark {
+ enum {
+ N = SkBENCHLOOP(80),
+ M = SkBENCHLOOP(200)
+ };
+public:
+ MutexBench(void* param) : INHERITED(param) {
+
+ }
+protected:
+ virtual const char* onGetName() {
+ return "mutex";
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ for (int i = 0; i < N; i++) {
+ SkMutex mu;
+ for (int j = 0; j < M; j++) {
+ mu.acquire();
+ mu.release();
+ }
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact(void* p) { return new MutexBench(p); }
+
+static BenchRegistry gReg01(Fact);
+
diff --git a/bench/PathBench.cpp b/bench/PathBench.cpp
index 19e3aae..d3e01b7 100644
--- a/bench/PathBench.cpp
+++ b/bench/PathBench.cpp
@@ -1,8 +1,16 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
#include "SkPaint.h"
+#include "SkRandom.h"
#include "SkShader.h"
#include "SkString.h"
@@ -20,7 +28,7 @@ class PathBench : public SkBenchmark {
SkPaint fPaint;
SkString fName;
Flags fFlags;
- enum { N = 1000 };
+ enum { N = SkBENCHLOOP(1000) };
public:
PathBench(void* param, Flags flags) : INHERITED(param), fFlags(flags) {
fPaint.setStyle(flags & kStroke_Flag ? SkPaint::kStroke_Style :
@@ -31,7 +39,7 @@ public:
virtual void appendName(SkString*) = 0;
virtual void makePath(SkPath*) = 0;
- virtual bool iscomplex() { return false; }
+ virtual int complexity() { return 0; }
protected:
virtual const char* onGetName() {
@@ -58,9 +66,7 @@ protected:
if (fFlags & kBig_Flag) {
count >>= 2;
}
- if (this->iscomplex()) {
- count >>= 3;
- }
+ count >>= (3 * complexity());
for (int i = 0; i < count; i++) {
canvas->drawPath(path, paint);
@@ -146,11 +152,38 @@ public:
path->lineTo(x0, y + 2 * dy);
path->close();
}
- virtual bool iscomplex() { return true; }
+ virtual int complexity() { return 1; }
private:
typedef PathBench INHERITED;
};
+class LongCurvedPathBench : public PathBench {
+public:
+ LongCurvedPathBench(void * param, Flags flags)
+ : INHERITED(param, flags) {
+ }
+
+ virtual void appendName(SkString* name) {
+ name->append("long_curved");
+ }
+ virtual void makePath(SkPath* path) {
+ SkRandom rand (12);
+ int i;
+ for (i = 0; i < 100; i++) {
+ path->quadTo(SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(640)),
+ SkScalarMul(rand.nextUScalar1(), SkIntToScalar(480)));
+ }
+ path->close();
+ }
+ virtual int complexity() { return 2; }
+private:
+ typedef PathBench INHERITED;
+};
+
+
+
static SkBenchmark* FactT00(void* p) { return new TrianglePathBench(p, FLAGS00); }
static SkBenchmark* FactT01(void* p) { return new TrianglePathBench(p, FLAGS01); }
static SkBenchmark* FactT10(void* p) { return new TrianglePathBench(p, FLAGS10); }
@@ -169,6 +202,13 @@ static SkBenchmark* FactO11(void* p) { return new OvalPathBench(p, FLAGS11); }
static SkBenchmark* FactS00(void* p) { return new SawToothPathBench(p, FLAGS00); }
static SkBenchmark* FactS01(void* p) { return new SawToothPathBench(p, FLAGS01); }
+static SkBenchmark* FactLC00(void* p) {
+ return new LongCurvedPathBench(p, FLAGS00);
+}
+static SkBenchmark* FactLC01(void* p) {
+ return new LongCurvedPathBench(p, FLAGS01);
+}
+
static BenchRegistry gRegT00(FactT00);
static BenchRegistry gRegT01(FactT01);
static BenchRegistry gRegT10(FactT10);
@@ -187,3 +227,6 @@ static BenchRegistry gRegO11(FactO11);
static BenchRegistry gRegS00(FactS00);
static BenchRegistry gRegS01(FactS01);
+static BenchRegistry gRegLC00(FactLC00);
+static BenchRegistry gRegLC01(FactLC01);
+
diff --git a/bench/RectBench.cpp b/bench/RectBench.cpp
index fb54640..cef2e22 100644
--- a/bench/RectBench.cpp
+++ b/bench/RectBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkPaint.h"
@@ -11,7 +18,7 @@ public:
enum {
W = 640,
H = 480,
- N = 300
+ N = SkBENCHLOOP(300)
};
SkRect fRects[N];
SkColor fColors[N];
diff --git a/bench/RepeatTileBench.cpp b/bench/RepeatTileBench.cpp
index 97bbeb8..8470bed 100644
--- a/bench/RepeatTileBench.cpp
+++ b/bench/RepeatTileBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkBitmap.h"
#include "SkCanvas.h"
@@ -79,7 +86,7 @@ static void convertToIndex666(const SkBitmap& src, SkBitmap* dst) {
class RepeatTileBench : public SkBenchmark {
SkPaint fPaint;
SkString fName;
- enum { N = 20 };
+ enum { N = SkBENCHLOOP(20) };
public:
RepeatTileBench(void* param, SkBitmap::Config c) : INHERITED(param) {
const int w = 50;
diff --git a/bench/ScalarBench.cpp b/bench/ScalarBench.cpp
index 29fe5c4..8bedfbd 100644
--- a/bench/ScalarBench.cpp
+++ b/bench/ScalarBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkFloatBits.h"
#include "SkRandom.h"
@@ -21,7 +28,7 @@ protected:
}
virtual void onDraw(SkCanvas* canvas) {
- int n = N * this->mulLoopCount();
+ int n = SkBENCHLOOP(N * this->mulLoopCount());
for (int i = 0; i < n; i++) {
this->performTest();
}
diff --git a/bench/ShaderMaskBench.cpp b/bench/ShaderMaskBench.cpp
new file mode 100644
index 0000000..62be6c5
--- /dev/null
+++ b/bench/ShaderMaskBench.cpp
@@ -0,0 +1,109 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkColorShader.h"
+#include "SkFontHost.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkSfntUtils.h"
+#include "SkString.h"
+#include "SkTemplates.h"
+
+#define STR "Hamburgefons"
+
+enum FontQuality {
+ kBW,
+ kAA,
+ kLCD
+};
+
+static const char* fontQualityName(const SkPaint& paint) {
+ if (!paint.isAntiAlias()) {
+ return "BW";
+ }
+ if (paint.isLCDRenderText()) {
+ return "LCD";
+ }
+ return "AA";
+}
+
+class ShaderMaskBench : public SkBenchmark {
+ SkPaint fPaint;
+ SkString fText;
+ SkString fName;
+ FontQuality fFQ;
+ enum { N = SkBENCHLOOP(500) };
+public:
+ ShaderMaskBench(void* param, bool isOpaque, FontQuality fq) : INHERITED(param) {
+ fFQ = fq;
+ fText.set(STR);
+
+ fPaint.setAntiAlias(kBW != fq);
+ fPaint.setLCDRenderText(kLCD == fq);
+ fPaint.setAlpha(isOpaque ? 0xFF : 0x80);
+ fPaint.setShader(new SkColorShader)->unref();
+ }
+
+protected:
+ virtual const char* onGetName() {
+ fName.printf("shadermask", SkScalarToFloat(fPaint.getTextSize()));
+ fName.appendf("_%s", fontQualityName(fPaint));
+ fName.appendf("_%02X", fPaint.getAlpha());
+ return fName.c_str();
+ }
+
+ virtual void onDraw(SkCanvas* canvas) {
+ const SkIPoint dim = this->getSize();
+ SkRandom rand;
+
+ SkPaint paint(fPaint);
+ this->setupPaint(&paint);
+ // explicitly need these
+ paint.setAlpha(fPaint.getAlpha());
+ paint.setAntiAlias(kBW != fFQ);
+ paint.setLCDRenderText(kLCD == fFQ);
+
+ const SkScalar x0 = SkIntToScalar(-10);
+ const SkScalar y0 = SkIntToScalar(-10);
+
+ paint.setTextSize(SkIntToScalar(12));
+ for (int i = 0; i < N; i++) {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+ canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
+ }
+
+ paint.setTextSize(SkIntToScalar(48));
+ for (int i = 0; i < N/4; i++) {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
+ canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
+ }
+ }
+
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact00(void* p) { return new ShaderMaskBench(p, true, kBW); }
+static SkBenchmark* Fact01(void* p) { return new ShaderMaskBench(p, false, kBW); }
+static SkBenchmark* Fact10(void* p) { return new ShaderMaskBench(p, true, kAA); }
+static SkBenchmark* Fact11(void* p) { return new ShaderMaskBench(p, false, kAA); }
+static SkBenchmark* Fact20(void* p) { return new ShaderMaskBench(p, true, kLCD); }
+static SkBenchmark* Fact21(void* p) { return new ShaderMaskBench(p, false, kLCD); }
+
+static BenchRegistry gReg00(Fact00);
+static BenchRegistry gReg01(Fact01);
+static BenchRegistry gReg10(Fact10);
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg20(Fact20);
+static BenchRegistry gReg21(Fact21);
+
diff --git a/bench/SkBenchmark.cpp b/bench/SkBenchmark.cpp
index 230a7af..a69402b 100644
--- a/bench/SkBenchmark.cpp
+++ b/bench/SkBenchmark.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkPaint.h"
#include "SkParse.h"
diff --git a/bench/SkBenchmark.h b/bench/SkBenchmark.h
index 945db80..5019b23 100644
--- a/bench/SkBenchmark.h
+++ b/bench/SkBenchmark.h
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#ifndef SkBenchmark_DEFINED
#define SkBenchmark_DEFINED
@@ -6,6 +13,12 @@
#include "SkTDict.h"
#include "SkTRegistry.h"
+#ifdef SK_DEBUG
+ #define SkBENCHLOOP(n) 1
+#else
+ #define SkBENCHLOOP(n) n
+#endif
+
class SkCanvas;
class SkPaint;
diff --git a/bench/TextBench.cpp b/bench/TextBench.cpp
index f2b9604..63a7167 100644
--- a/bench/TextBench.cpp
+++ b/bench/TextBench.cpp
@@ -1,3 +1,10 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkFontHost.h"
@@ -7,6 +14,22 @@
#include "SkString.h"
#include "SkTemplates.h"
+enum FontQuality {
+ kBW,
+ kAA,
+ kLCD
+};
+
+static const char* fontQualityName(const SkPaint& paint) {
+ if (!paint.isAntiAlias()) {
+ return "BW";
+ }
+ if (paint.isLCDRenderText()) {
+ return "LCD";
+ }
+ return "AA";
+}
+
/* Some considerations for performance:
short -vs- long strings (measuring overhead)
tiny -vs- large pointsize (measure blit -vs- overhead)
@@ -18,34 +41,35 @@
*/
class TextBench : public SkBenchmark {
SkPaint fPaint;
- int fCount;
- SkPoint* fPos;
SkString fText;
SkString fName;
- enum { N = 600 };
+ FontQuality fFQ;
+ bool fDoPos;
+ SkPoint* fPos;
+ enum { N = SkBENCHLOOP(800) };
public:
- TextBench(void* param, const char text[], int ps, bool linearText,
- bool posText, SkColor color = SK_ColorBLACK) : INHERITED(param) {
+ TextBench(void* param, const char text[], int ps,
+ SkColor color, FontQuality fq, bool doPos = false) : INHERITED(param) {
+ fFQ = fq;
+ fDoPos = doPos;
fText.set(text);
- fPaint.setAntiAlias(true);
+ fPaint.setAntiAlias(kBW != fq);
+ fPaint.setLCDRenderText(kLCD == fq);
fPaint.setTextSize(SkIntToScalar(ps));
- fPaint.setLinearText(linearText);
fPaint.setColor(color);
- if (posText) {
- SkAutoTArray<SkScalar> storage(fText.size());
- SkScalar* widths = storage.get();
- fCount = fPaint.getTextWidths(fText.c_str(), fText.size(), widths);
- fPos = new SkPoint[fCount];
+ if (doPos) {
+ size_t len = strlen(text);
+ SkScalar* adv = new SkScalar[len];
+ fPaint.getTextWidths(text, len, adv);
+ fPos = new SkPoint[len];
SkScalar x = 0;
- for (int i = 0; i < fCount; i++) {
- fPos[i].set(x, 0);
- x += widths[i];
+ for (size_t i = 0; i < len; ++i) {
+ fPos[i].set(x, SkIntToScalar(50));
+ x += adv[i];
}
- } else {
- fCount = 0;
- fPos = NULL;
+ delete[] adv;
}
}
@@ -56,15 +80,14 @@ public:
protected:
virtual const char* onGetName() {
fName.printf("text_%g", SkScalarToFloat(fPaint.getTextSize()));
- if (fPaint.isLinearText()) {
- fName.append("_linear");
- }
- if (fPos) {
- fName.append("_pos");
+ if (fDoPos) {
+ fName.appendf("_pos");
}
-
+ fName.appendf("_%s", fontQualityName(fPaint));
if (SK_ColorBLACK != fPaint.getColor()) {
fName.appendf("_%02X", fPaint.getAlpha());
+ } else {
+ fName.appendf("_BK");
}
return fName.c_str();
}
@@ -75,20 +98,26 @@ protected:
SkPaint paint(fPaint);
this->setupPaint(&paint);
- paint.setColor(fPaint.getColor()); // need our specified color
+ // explicitly need these
+ paint.setColor(fPaint.getColor());
+ paint.setAntiAlias(kBW != fFQ);
+ paint.setLCDRenderText(kLCD == fFQ);
const SkScalar x0 = SkIntToScalar(-10);
const SkScalar y0 = SkIntToScalar(-10);
+ if (fDoPos) {
+ // realistically, the matrix is often at least translated, so we
+ // do that since it exercises different code in drawPosText.
+ canvas->translate(SK_Scalar1, SK_Scalar1);
+ }
+
for (int i = 0; i < N; i++) {
- SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
- SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
- if (fPos) {
- canvas->save(SkCanvas::kMatrix_SaveFlag);
- canvas->translate(x, y);
+ if (fDoPos) {
canvas->drawPosText(fText.c_str(), fText.size(), fPos, paint);
- canvas->restore();
} else {
+ SkScalar x = x0 + rand.nextUScalar1() * dim.fX;
+ SkScalar y = y0 + rand.nextUScalar1() * dim.fY;
canvas->drawText(fText.c_str(), fText.size(), x, y, paint);
}
}
@@ -101,35 +130,31 @@ private:
///////////////////////////////////////////////////////////////////////////////
#define STR "Hamburgefons"
-#define SMALL 9
-#define BIG 48
-static SkBenchmark* Fact0(void* p) { return new TextBench(p, STR, SMALL, false, false); }
-static SkBenchmark* Fact01(void* p) { return new TextBench(p, STR, SMALL, false, false, 0xFFFF0000); }
-static SkBenchmark* Fact02(void* p) { return new TextBench(p, STR, SMALL, false, false, 0x88FF0000); }
+static SkBenchmark* Fact01(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kBW); }
+static SkBenchmark* Fact02(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kBW); }
+static SkBenchmark* Fact03(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kBW); }
-static SkBenchmark* Fact1(void* p) { return new TextBench(p, STR, SMALL, false, true); }
-static SkBenchmark* Fact2(void* p) { return new TextBench(p, STR, SMALL, true, false); }
-static SkBenchmark* Fact3(void* p) { return new TextBench(p, STR, SMALL, true, true); }
+static SkBenchmark* Fact11(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kAA); }
+static SkBenchmark* Fact12(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kAA); }
+static SkBenchmark* Fact13(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kAA); }
-static SkBenchmark* Fact4(void* p) { return new TextBench(p, STR, BIG, false, false); }
-static SkBenchmark* Fact41(void* p) { return new TextBench(p, STR, BIG, false, false, 0xFFFF0000); }
-static SkBenchmark* Fact42(void* p) { return new TextBench(p, STR, BIG, false, false, 0x88FF0000); }
+static SkBenchmark* Fact21(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kLCD); }
+static SkBenchmark* Fact22(void* p) { return new TextBench(p, STR, 16, 0xFFFF0000, kLCD); }
+static SkBenchmark* Fact23(void* p) { return new TextBench(p, STR, 16, 0x88FF0000, kLCD); }
-static SkBenchmark* Fact5(void* p) { return new TextBench(p, STR, BIG, false, true); }
-static SkBenchmark* Fact6(void* p) { return new TextBench(p, STR, BIG, true, false); }
-static SkBenchmark* Fact7(void* p) { return new TextBench(p, STR, BIG, true, true); }
+static SkBenchmark* Fact111(void* p) { return new TextBench(p, STR, 16, 0xFF000000, kAA, true); }
-static BenchRegistry gReg0(Fact0);
static BenchRegistry gReg01(Fact01);
static BenchRegistry gReg02(Fact02);
-static BenchRegistry gReg1(Fact1);
-static BenchRegistry gReg2(Fact2);
-static BenchRegistry gReg3(Fact3);
-static BenchRegistry gReg4(Fact4);
-static BenchRegistry gReg41(Fact41);
-static BenchRegistry gReg42(Fact42);
-static BenchRegistry gReg5(Fact5);
-static BenchRegistry gReg6(Fact6);
-static BenchRegistry gReg7(Fact7);
+static BenchRegistry gReg03(Fact03);
+
+static BenchRegistry gReg11(Fact11);
+static BenchRegistry gReg12(Fact12);
+static BenchRegistry gReg13(Fact13);
+
+static BenchRegistry gReg21(Fact21);
+static BenchRegistry gReg22(Fact22);
+static BenchRegistry gReg23(Fact23);
+static BenchRegistry gReg111(Fact111);
diff --git a/bench/VertBench.cpp b/bench/VertBench.cpp
new file mode 100644
index 0000000..98df449
--- /dev/null
+++ b/bench/VertBench.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+#include "SkBenchmark.h"
+#include "SkCanvas.h"
+#include "SkPaint.h"
+#include "SkRandom.h"
+#include "SkString.h"
+#include "SkShader.h"
+
+enum VertFlags {
+ kColors_VertFlag,
+ kTexture_VertFlag,
+};
+
+class VertBench : public SkBenchmark {
+ SkString fName;
+ enum {
+ W = 640,
+ H = 480,
+ ROW = 20,
+ COL = 20,
+ PTS = (ROW + 1) * (COL + 1),
+ IDX = ROW * COL * 6,
+ N = SkBENCHLOOP(10)
+ };
+
+ SkPoint fPts[PTS];
+ SkColor fColors[PTS];
+ SkPoint fTex[PTS];
+ uint16_t fIdx[IDX];
+
+ static void load_2_tris(uint16_t idx[], int x, int y, int rb) {
+ int n = y * rb + x;
+ idx[0] = n; idx[1] = n + 1; idx[2] = rb + n + 1;
+ idx[3] = n; idx[4] = rb + n + 1; idx[5] = n + rb;
+ }
+
+public:
+ VertBench(void* param) : INHERITED(param) {
+ const SkScalar dx = SkIntToScalar(W) / COL;
+ const SkScalar dy = SkIntToScalar(H) / COL;
+
+ SkPoint* pts = fPts;
+ uint16_t* idx = fIdx;
+
+ SkScalar yy = 0;
+ for (int y = 0; y <= ROW; y++) {
+ SkScalar xx = 0;
+ for (int x = 0; x <= COL; ++x) {
+ pts->set(xx, yy);
+ pts += 1;
+ xx += dx;
+
+ if (x < COL && y < ROW) {
+ load_2_tris(idx, x, y, COL + 1);
+ for (int i = 0; i < 6; i++) {
+ SkASSERT(idx[i] < PTS);
+ }
+ idx += 6;
+ }
+ }
+ yy += dy;
+ }
+ SkASSERT(PTS == pts - fPts);
+ SkASSERT(IDX == idx - fIdx);
+
+ SkRandom rand;
+ for (int i = 0; i < PTS; ++i) {
+ fColors[i] = rand.nextU() | (0xFF << 24);
+ }
+
+ fName.set("verts");
+ }
+
+protected:
+ virtual const char* onGetName() { return fName.c_str(); }
+ virtual void onDraw(SkCanvas* canvas) {
+ SkPaint paint;
+ this->setupPaint(&paint);
+
+ for (int i = 0; i < N; i++) {
+ canvas->drawVertices(SkCanvas::kTriangles_VertexMode, PTS,
+ fPts, NULL, fColors, NULL, fIdx, IDX, paint);
+ }
+ }
+private:
+ typedef SkBenchmark INHERITED;
+};
+
+///////////////////////////////////////////////////////////////////////////////
+
+static SkBenchmark* Fact(void* p) { return SkNEW_ARGS(VertBench, (p)); }
+
+static BenchRegistry gReg(Fact);
diff --git a/bench/bench_compare.py b/bench/bench_compare.py
index f6909b1..c1a1ff9 100644
--- a/bench/bench_compare.py
+++ b/bench/bench_compare.py
@@ -5,31 +5,7 @@ Created on May 16, 2011
'''
import sys
import getopt
-import re
-
-def parse(lines):
- """Takes iterable lines of bench output, returns {bench:{config:time}}."""
-
- benches = {}
- current_bench = None
-
- for line in lines:
- #see if this line starts a new bench
- new_bench = re.search('running bench \[\d+ \d+\] (.{28})', line)
- if new_bench:
- current_bench = new_bench.group(1)
-
- #add configs on this line to the current bench
- if current_bench:
- for new_config in re.finditer(' (.{4}): msecs = (\d+\.\d+)', line):
- current_config = new_config.group(1)
- current_time = float(new_config.group(2))
- if current_bench in benches:
- benches[current_bench][current_config] = current_time
- else:
- benches[current_bench] = {current_config : current_time}
-
- return benches
+import bench_util
def usage():
"""Prints simple usage information."""
@@ -38,20 +14,39 @@ def usage():
print '-n <file> the new bench output file.'
print '-h causes headers to be output.'
print '-f <fieldSpec> which fields to output and in what order.'
- print ' Not specifying is the same as -f "bcondp".'
+ print ' Not specifying is the same as -f "bctondp".'
print ' b: bench'
print ' c: config'
+ print ' t: time type'
print ' o: old time'
print ' n: new time'
print ' d: diff'
print ' p: percent diff'
-
+class BenchDiff:
+ """A compare between data points produced by bench.
+
+ (BenchDataPoint, BenchDataPoint)"""
+ def __init__(self, old, new):
+ self.old = old
+ self.new = new
+ self.diff = old.time - new.time
+ diffp = 0
+ if old.time != 0:
+ diffp = self.diff / old.time
+ self.diffp = diffp
+
+ def __repr__(self):
+ return "BenchDiff(%s, %s)" % (
+ str(self.new),
+ str(self.old),
+ )
+
def main():
"""Parses command line and writes output."""
try:
- opts, args = getopt.getopt(sys.argv[1:], "f:o:n:h")
+ opts, _ = getopt.getopt(sys.argv[1:], "f:o:n:h")
except getopt.GetoptError, err:
print str(err)
usage()
@@ -60,25 +55,27 @@ def main():
column_formats = {
'b' : '{bench: >28} ',
'c' : '{config: <4} ',
+ 't' : '{time_type: <4} ',
'o' : '{old_time: >10.2f} ',
'n' : '{new_time: >10.2f} ',
'd' : '{diff: >+10.2f} ',
- 'p' : '{diffp: >+7.1%} ',
+ 'p' : '{diffp: >+8.1%} ',
}
header_formats = {
'b' : '{bench: >28} ',
'c' : '{config: <4} ',
+ 't' : '{time_type: <4} ',
'o' : '{old_time: >10} ',
'n' : '{new_time: >10} ',
'd' : '{diff: >10} ',
- 'p' : '{diffp: >7} ',
+ 'p' : '{diffp: >8} ',
}
old = None
new = None
column_format = ""
header_format = ""
- columns = 'bcondp'
+ columns = 'bctondp'
header = False
for option, value in opts:
@@ -110,31 +107,43 @@ def main():
print header_format.format(
bench='bench'
, config='conf'
+ , time_type='time'
, old_time='old'
, new_time='new'
, diff='diff'
, diffp='diffP'
)
- old_benches = parse(open(old, 'r'))
- new_benches = parse(open(new, 'r'))
-
- for old_bench, old_configs in old_benches.items():
- if old_bench in new_benches:
- new_configs = new_benches[old_bench]
- for old_config, old_time in old_configs.items():
- if old_config in new_configs:
- new_time = new_configs[old_config]
- old_time = old_configs[old_config]
- print column_format.format(
- bench=old_bench.strip()
- , config=old_config.strip()
- , old_time=old_time
- , new_time=new_time
- , diff=(old_time - new_time)
- , diffp=((old_time-new_time)/old_time)
- )
-
+ old_benches = bench_util.parse({}, open(old, 'r'))
+ new_benches = bench_util.parse({}, open(new, 'r'))
+
+ bench_diffs = []
+ for old_bench in old_benches:
+ #filter new_benches for benches that match old_bench
+ new_bench_match = [bench for bench in new_benches
+ if old_bench.bench == bench.bench and
+ old_bench.config == bench.config and
+ old_bench.time_type == bench.time_type
+ ]
+ if (len(new_bench_match) < 1):
+ continue
+ bench_diffs.append(BenchDiff(old_bench, new_bench_match[0]))
+
+ bench_diffs.sort(key=lambda d : [d.diffp,
+ d.old.bench,
+ d.old.config,
+ d.old.time_type,
+ ])
+ for bench_diff in bench_diffs:
+ print column_format.format(
+ bench=bench_diff.old.bench.strip()
+ , config=bench_diff.old.config.strip()
+ , time_type=bench_diff.old.time_type
+ , old_time=bench_diff.old.time
+ , new_time=bench_diff.new.time
+ , diff=bench_diff.diff
+ , diffp=bench_diff.diffp
+ )
if __name__ == "__main__":
main()
diff --git a/bench/bench_graph_svg.py b/bench/bench_graph_svg.py
new file mode 100644
index 0000000..d8cd54b
--- /dev/null
+++ b/bench/bench_graph_svg.py
@@ -0,0 +1,750 @@
+'''
+Created on May 16, 2011
+
+@author: bungeman
+'''
+import sys
+import getopt
+import re
+import os
+import bench_util
+import json
+import xml.sax.saxutils
+
+def usage():
+ """Prints simple usage information."""
+
+ print '-d <dir> a directory containing bench_r<revision>_<scalar> files.'
+ print '-b <bench> the bench to show.'
+ print '-c <config> the config to show (GPU, 8888, 565, etc).'
+ print '-t <time> the time to show (w, c, g, etc).'
+ print '-s <setting>[=<value>] a setting to show (alpha, scalar, etc).'
+ print '-r <revision>[:<revision>] the revisions to show.'
+ print ' Negative <revision> is taken as offset from most recent revision.'
+ print '-f <revision>[:<revision>] the revisions to use for fitting.'
+ print ' Negative <revision> is taken as offset from most recent revision.'
+ print '-x <int> the desired width of the svg.'
+ print '-y <int> the desired height of the svg.'
+ print '-l <title> title to use for the output graph'
+ print '--default-setting <setting>[=<value>] setting for those without.'
+
+
+class Label:
+ """The information in a label.
+
+ (str, str, str, str, {str:str})"""
+ def __init__(self, bench, config, time_type, settings):
+ self.bench = bench
+ self.config = config
+ self.time_type = time_type
+ self.settings = settings
+
+ def __repr__(self):
+ return "Label(%s, %s, %s, %s)" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.settings),
+ )
+
+ def __str__(self):
+ return "%s_%s_%s_%s" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.settings),
+ )
+
+ def __eq__(self, other):
+ return (self.bench == other.bench and
+ self.config == other.config and
+ self.time_type == other.time_type and
+ self.settings == other.settings)
+
+ def __hash__(self):
+ return (hash(self.bench) ^
+ hash(self.config) ^
+ hash(self.time_type) ^
+ hash(frozenset(self.settings.iteritems())))
+
+def get_latest_revision(directory):
+ """Returns the latest revision number found within this directory.
+ """
+ latest_revision_found = -1
+ for bench_file in os.listdir(directory):
+ file_name_match = re.match('bench_r(\d+)_(\S+)', bench_file)
+ if (file_name_match is None):
+ continue
+ revision = int(file_name_match.group(1))
+ if revision > latest_revision_found:
+ latest_revision_found = revision
+ if latest_revision_found < 0:
+ return None
+ else:
+ return latest_revision_found
+
+def parse_dir(directory, default_settings, oldest_revision, newest_revision):
+ """Parses bench data from files like bench_r<revision>_<scalar>.
+
+ (str, {str, str}, Number, Number) -> {int:[BenchDataPoints]}"""
+ revision_data_points = {} # {revision : [BenchDataPoints]}
+ for bench_file in os.listdir(directory):
+ file_name_match = re.match('bench_r(\d+)_(\S+)', bench_file)
+ if (file_name_match is None):
+ continue
+
+ revision = int(file_name_match.group(1))
+ scalar_type = file_name_match.group(2)
+
+ if (revision < oldest_revision or revision > newest_revision):
+ continue
+
+ file_handle = open(directory + '/' + bench_file, 'r')
+
+ if (revision not in revision_data_points):
+ revision_data_points[revision] = []
+ default_settings['scalar'] = scalar_type
+ revision_data_points[revision].extend(
+ bench_util.parse(default_settings, file_handle))
+ file_handle.close()
+ return revision_data_points
+
+def create_lines(revision_data_points, settings
+ , bench_of_interest, config_of_interest, time_of_interest):
+ """Convert revision data into sorted line data.
+
+ ({int:[BenchDataPoints]}, {str:str}, str?, str?, str?)
+ -> {Label:[(x,y)] | [n].x <= [n+1].x}"""
+ revisions = revision_data_points.keys()
+ revisions.sort()
+ lines = {} # {Label:[(x,y)] | x[n] <= x[n+1]}
+ for revision in revisions:
+ for point in revision_data_points[revision]:
+ if (bench_of_interest is not None and
+ not bench_of_interest == point.bench):
+ continue
+
+ if (config_of_interest is not None and
+ not config_of_interest == point.config):
+ continue
+
+ if (time_of_interest is not None and
+ not time_of_interest == point.time_type):
+ continue
+
+ skip = False
+ for key, value in settings.items():
+ if key in point.settings and point.settings[key] != value:
+ skip = True
+ break
+ if skip:
+ continue
+
+ line_name = Label(point.bench
+ , point.config
+ , point.time_type
+ , point.settings)
+
+ if line_name not in lines:
+ lines[line_name] = []
+
+ lines[line_name].append((revision, point.time))
+
+ return lines
+
+def bounds(lines):
+ """Finds the bounding rectangle for the lines.
+
+ {Label:[(x,y)]} -> ((min_x, min_y),(max_x,max_y))"""
+ min_x = bench_util.Max
+ min_y = bench_util.Max
+ max_x = bench_util.Min
+ max_y = bench_util.Min
+
+ for line in lines.itervalues():
+ for x, y in line:
+ min_x = min(min_x, x)
+ min_y = min(min_y, y)
+ max_x = max(max_x, x)
+ max_y = max(max_y, y)
+
+ return ((min_x, min_y), (max_x, max_y))
+
+def create_regressions(lines, start_x, end_x):
+ """Creates regression data from line segments.
+
+ ({Label:[(x,y)] | [n].x <= [n+1].x}, Number, Number)
+ -> {Label:LinearRegression}"""
+ regressions = {} # {Label : LinearRegression}
+
+ for label, line in lines.iteritems():
+ regression_line = [p for p in line if start_x <= p[0] <= end_x]
+
+ if (len(regression_line) < 2):
+ continue
+ regression = bench_util.LinearRegression(regression_line)
+ regressions[label] = regression
+
+ return regressions
+
+def bounds_slope(regressions):
+ """Finds the extreme up and down slopes of a set of linear regressions.
+
+ ({Label:LinearRegression}) -> (max_up_slope, min_down_slope)"""
+ max_up_slope = 0
+ min_down_slope = 0
+ for regression in regressions.itervalues():
+ min_slope = regression.find_min_slope()
+ max_up_slope = max(max_up_slope, min_slope)
+ min_down_slope = min(min_down_slope, min_slope)
+
+ return (max_up_slope, min_down_slope)
+
+def main():
+ """Parses command line and writes output."""
+
+ try:
+ opts, _ = getopt.getopt(sys.argv[1:]
+ , "d:b:c:l:t:s:r:f:x:y:"
+ , "default-setting=")
+ except getopt.GetoptError, err:
+ print str(err)
+ usage()
+ sys.exit(2)
+
+ directory = None
+ config_of_interest = None
+ bench_of_interest = None
+ time_of_interest = None
+ revision_range = '0:'
+ regression_range = '0:'
+ latest_revision = None
+ requested_height = None
+ requested_width = None
+ title = 'Bench graph'
+ settings = {}
+ default_settings = {}
+
+ def parse_range(range):
+ """Takes '<old>[:<new>]' as a string and returns (old, new).
+ Any revision numbers that are dependent on the latest revision number
+ will be filled in based on latest_revision.
+ """
+ old, _, new = range.partition(":")
+ old = int(old)
+ if old < 0:
+ old += latest_revision;
+ if not new:
+ new = latest_revision;
+ new = int(new)
+ if new < 0:
+ new += latest_revision;
+ return (old, new)
+
+ def add_setting(settings, setting):
+ """Takes <key>[=<value>] adds {key:value} or {key:True} to settings."""
+ name, _, value = setting.partition('=')
+ if not value:
+ settings[name] = True
+ else:
+ settings[name] = value
+
+ try:
+ for option, value in opts:
+ if option == "-d":
+ directory = value
+ elif option == "-b":
+ bench_of_interest = value
+ elif option == "-c":
+ config_of_interest = value
+ elif option == "-t":
+ time_of_interest = value
+ elif option == "-s":
+ add_setting(settings, value)
+ elif option == "-r":
+ revision_range = value
+ elif option == "-f":
+ regression_range = value
+ elif option == "-x":
+ requested_width = int(value)
+ elif option == "-y":
+ requested_height = int(value)
+ elif option == "-l":
+ title = value
+ elif option == "--default-setting":
+ add_setting(default_settings, value)
+ else:
+ usage()
+ assert False, "unhandled option"
+ except ValueError:
+ usage()
+ sys.exit(2)
+
+ if directory is None:
+ usage()
+ sys.exit(2)
+
+ latest_revision = get_latest_revision(directory)
+ oldest_revision, newest_revision = parse_range(revision_range)
+ oldest_regression, newest_regression = parse_range(regression_range)
+
+ revision_data_points = parse_dir(directory
+ , default_settings
+ , oldest_revision
+ , newest_revision)
+
+ # Update oldest_revision and newest_revision based on the data we could find
+ all_revision_numbers = revision_data_points.keys()
+ oldest_revision = min(all_revision_numbers)
+ newest_revision = max(all_revision_numbers)
+
+ lines = create_lines(revision_data_points
+ , settings
+ , bench_of_interest
+ , config_of_interest
+ , time_of_interest)
+
+ regressions = create_regressions(lines
+ , oldest_regression
+ , newest_regression)
+
+ output_xhtml(lines, oldest_revision, newest_revision,
+ regressions, requested_width, requested_height, title)
+
+def qa(out):
+ """Stringify input and quote as an xml attribute."""
+ return xml.sax.saxutils.quoteattr(str(out))
+def qe(out):
+ """Stringify input and escape as xml data."""
+ return xml.sax.saxutils.escape(str(out))
+
+def create_select(qualifier, lines, select_id=None):
+ """Output select with options showing lines which qualifier maps to it.
+
+ ((Label) -> str, {Label:_}, str?) -> _"""
+ options = {} #{ option : [Label]}
+ for label in lines.keys():
+ option = qualifier(label)
+ if (option not in options):
+ options[option] = []
+ options[option].append(label)
+ option_list = list(options.keys())
+ option_list.sort()
+ print '<select class="lines"',
+ if select_id is not None:
+ print 'id=%s' % qa(select_id)
+ print 'multiple="true" size="10" onchange="updateSvg();">'
+ for option in option_list:
+ print '<option value=' + qa('[' +
+ reduce(lambda x,y:x+json.dumps(str(y))+',',options[option],"")[0:-1]
+ + ']') + '>'+qe(option)+'</option>'
+ print '</select>'
+
+def output_xhtml(lines, oldest_revision, newest_revision,
+ regressions, requested_width, requested_height, title):
+ """Outputs an svg/xhtml view of the data."""
+ print '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"',
+ print '"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
+ print '<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">'
+ print '<head>'
+ print '<title>%s</title>' % title
+ print '</head>'
+ print '<body>'
+
+ output_svg(lines, regressions, requested_width, requested_height)
+
+ #output the manipulation controls
+ print """
+<script type="text/javascript">//<![CDATA[
+ function getElementsByClass(node, searchClass, tag) {
+ var classElements = new Array();
+ var elements = node.getElementsByTagName(tag);
+ var pattern = new RegExp("^|\\s"+searchClass+"\\s|$");
+ for (var i = 0, elementsFound = 0; i < elements.length; ++i) {
+ if (pattern.test(elements[i].className)) {
+ classElements[elementsFound] = elements[i];
+ ++elementsFound;
+ }
+ }
+ return classElements;
+ }
+ function getAllLines() {
+ var selectElem = document.getElementById('benchSelect');
+ var linesObj = {};
+ for (var i = 0; i < selectElem.options.length; ++i) {
+ var lines = JSON.parse(selectElem.options[i].value);
+ for (var j = 0; j < lines.length; ++j) {
+ linesObj[lines[j]] = true;
+ }
+ }
+ return linesObj;
+ }
+ function getOptions(selectElem) {
+ var linesSelectedObj = {};
+ for (var i = 0; i < selectElem.options.length; ++i) {
+ if (!selectElem.options[i].selected) continue;
+
+ var linesSelected = JSON.parse(selectElem.options[i].value);
+ for (var j = 0; j < linesSelected.length; ++j) {
+ linesSelectedObj[linesSelected[j]] = true;
+ }
+ }
+ return linesSelectedObj;
+ }
+ function objectEmpty(obj) {
+ for (var p in obj) {
+ return false;
+ }
+ return true;
+ }
+ function markSelectedLines(selectElem, allLines) {
+ var linesSelected = getOptions(selectElem);
+ if (!objectEmpty(linesSelected)) {
+ for (var line in allLines) {
+ allLines[line] &= (linesSelected[line] == true);
+ }
+ }
+ }
+ function updateSvg() {
+ var allLines = getAllLines();
+
+ var selects = getElementsByClass(document, 'lines', 'select');
+ for (var i = 0; i < selects.length; ++i) {
+ markSelectedLines(selects[i], allLines);
+ }
+
+ for (var line in allLines) {
+ var svgLine = document.getElementById(line);
+ var display = (allLines[line] ? 'inline' : 'none');
+ svgLine.setAttributeNS(null,'display', display);
+ }
+ }
+
+ function mark(markerId) {
+ for (var line in getAllLines()) {
+ var svgLineGroup = document.getElementById(line);
+ var display = svgLineGroup.getAttributeNS(null,'display');
+ if (display == null || display == "" || display != "none") {
+ var svgLine = document.getElementById(line+'_line');
+ if (markerId == null) {
+ svgLine.removeAttributeNS(null,'marker-mid');
+ } else {
+ svgLine.setAttributeNS(null,'marker-mid', markerId);
+ }
+ }
+ }
+ }
+//]]></script>"""
+
+ print '<table border="0" width="%s">' % requested_width
+ print """
+<form>
+<tr valign="bottom" align="center">
+<td width="1">Bench&nbsp;Type</td>
+<td width="1">Bitmap Config</td>
+<td width="1">Timer&nbsp;Type (Cpu/Gpu/wall)</td>
+<td width="1"><!--buttons--></td>
+<td width="10%"><!--spacing--></td>"""
+
+ print '<td>%s<br></br>revisions r%s - r%s</td>' % (
+ title,
+ bench_util.CreateRevisionLink(oldest_revision),
+ bench_util.CreateRevisionLink(newest_revision))
+ print '</tr><tr valign="top" align="center">'
+ print '<td width="1">'
+ create_select(lambda l: l.bench, lines, 'benchSelect')
+ print '</td><td width="1">'
+ create_select(lambda l: l.config, lines)
+ print '</td><td width="1">'
+ create_select(lambda l: l.time_type, lines)
+
+ all_settings = {}
+ variant_settings = set()
+ for label in lines.keys():
+ for key, value in label.settings.items():
+ if key not in all_settings:
+ all_settings[key] = value
+ elif all_settings[key] != value:
+ variant_settings.add(key)
+
+ for k in variant_settings:
+ create_select(lambda l: l.settings[k], lines)
+
+ print '</td><td width="1"><button type="button"',
+ print 'onclick=%s' % qa("mark('url(#circleMark)'); return false;"),
+ print '>Mark Points</button>'
+ print '<button type="button" onclick="mark(null);">Clear Points</button>'
+
+ print """
+</td>
+<td width="10%"></td>
+<td align="left">
+<p>Brighter red indicates tests that have gotten worse; brighter green
+indicates tests that have gotten better.</p>
+<p>To highlight individual tests, hold down CONTROL and mouse over
+graph lines.</p>
+<p>To highlight revision numbers, hold down SHIFT and mouse over
+the graph area.</p>
+<p>To only show certain tests on the graph, select any combination of
+tests in the selectors at left. (To show all, select all.)</p>
+<p>Use buttons at left to mark/clear points on the lines for selected
+benchmarks.</p>
+</td>
+</tr>
+</form>
+</table>
+</body>
+</html>"""
+
+def compute_size(requested_width, requested_height, rev_width, time_height):
+ """Converts potentially empty requested size into a concrete size.
+
+ (Number?, Number?) -> (Number, Number)"""
+ pic_width = 0
+ pic_height = 0
+ if (requested_width is not None and requested_height is not None):
+ pic_height = requested_height
+ pic_width = requested_width
+
+ elif (requested_width is not None):
+ pic_width = requested_width
+ pic_height = pic_width * (float(time_height) / rev_width)
+
+ elif (requested_height is not None):
+ pic_height = requested_height
+ pic_width = pic_height * (float(rev_width) / time_height)
+
+ else:
+ pic_height = 800
+ pic_width = max(rev_width*3
+ , pic_height * (float(rev_width) / time_height))
+
+ return (pic_width, pic_height)
+
+def output_svg(lines, regressions, requested_width, requested_height):
+ """Outputs an svg view of the data."""
+
+ (global_min_x, _), (global_max_x, global_max_y) = bounds(lines)
+ max_up_slope, min_down_slope = bounds_slope(regressions)
+
+ #output
+ global_min_y = 0
+ x = global_min_x
+ y = global_min_y
+ w = global_max_x - global_min_x
+ h = global_max_y - global_min_y
+ font_size = 16
+ line_width = 2
+
+ pic_width, pic_height = compute_size(requested_width, requested_height
+ , w, h)
+
+ def cw(w1):
+ """Converts a revision difference to display width."""
+ return (pic_width / float(w)) * w1
+ def cx(x):
+ """Converts a revision to a horizontal display position."""
+ return cw(x - global_min_x)
+
+ def ch(h1):
+ """Converts a time difference to a display height."""
+ return -(pic_height / float(h)) * h1
+ def cy(y):
+ """Converts a time to a vertical display position."""
+ return pic_height + ch(y - global_min_y)
+
+ print '<svg',
+ print 'width=%s' % qa(str(pic_width)+'px')
+ print 'height=%s' % qa(str(pic_height)+'px')
+ print 'viewBox="0 0 %s %s"' % (str(pic_width), str(pic_height))
+ print 'onclick=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.shiftKey) { highlightRevision(null); }"
+ " if (event.ctrlKey) { highlight(null); }"
+ " return false;")
+ print 'xmlns="http://www.w3.org/2000/svg"'
+ print 'xmlns:xlink="http://www.w3.org/1999/xlink">'
+
+ print """
+<defs>
+ <marker id="circleMark"
+ viewBox="0 0 2 2" refX="1" refY="1"
+ markerUnits="strokeWidth"
+ markerWidth="2" markerHeight="2"
+ orient="0">
+ <circle cx="1" cy="1" r="1"/>
+ </marker>
+</defs>"""
+
+ #output the revisions
+ print """
+<script type="text/javascript">//<![CDATA[
+ var previousRevision;
+ var previousRevisionFill;
+ var previousRevisionStroke
+ function highlightRevision(id) {
+ if (previousRevision == id) return;
+
+ document.getElementById('revision').firstChild.nodeValue = 'r' + id;
+ document.getElementById('rev_link').setAttribute('xlink:href',
+ 'http://code.google.com/p/skia/source/detail?r=' + id);
+
+ var preRevision = document.getElementById(previousRevision);
+ if (preRevision) {
+ preRevision.setAttributeNS(null,'fill', previousRevisionFill);
+ preRevision.setAttributeNS(null,'stroke', previousRevisionStroke);
+ }
+
+ var revision = document.getElementById(id);
+ previousRevision = id;
+ if (revision) {
+ previousRevisionFill = revision.getAttributeNS(null,'fill');
+ revision.setAttributeNS(null,'fill','rgb(100%, 95%, 95%)');
+
+ previousRevisionStroke = revision.getAttributeNS(null,'stroke');
+ revision.setAttributeNS(null,'stroke','rgb(100%, 90%, 90%)');
+ }
+ }
+//]]></script>"""
+
+ def print_rect(x, y, w, h, revision):
+ """Outputs a revision rectangle in display space,
+ taking arguments in revision space."""
+ disp_y = cy(y)
+ disp_h = ch(h)
+ if disp_h < 0:
+ disp_y += disp_h
+ disp_h = -disp_h
+
+ print '<rect id=%s x=%s y=%s' % (qa(revision), qa(cx(x)), qa(disp_y),),
+ print 'width=%s height=%s' % (qa(cw(w)), qa(disp_h),),
+ print 'fill="white"',
+ print 'stroke="rgb(98%%,98%%,88%%)" stroke-width=%s' % qa(line_width),
+ print 'onmouseover=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.shiftKey) {"
+ " highlightRevision('"+str(revision)+"');"
+ " return false;"
+ " }"),
+ print ' />'
+
+ xes = set()
+ for line in lines.itervalues():
+ for point in line:
+ xes.add(point[0])
+ revisions = list(xes)
+ revisions.sort()
+
+ left = x
+ current_revision = revisions[0]
+ for next_revision in revisions[1:]:
+ width = (((next_revision - current_revision) / 2.0)
+ + (current_revision - left))
+ print_rect(left, y, width, h, current_revision)
+ left += width
+ current_revision = next_revision
+ print_rect(left, y, x+w - left, h, current_revision)
+
+ #output the lines
+ print """
+<script type="text/javascript">//<![CDATA[
+ var previous;
+ var previousColor;
+ var previousOpacity;
+ function highlight(id) {
+ if (previous == id) return;
+
+ document.getElementById('label').firstChild.nodeValue = id;
+
+ var preGroup = document.getElementById(previous);
+ if (preGroup) {
+ var preLine = document.getElementById(previous+'_line');
+ preLine.setAttributeNS(null,'stroke', previousColor);
+ preLine.setAttributeNS(null,'opacity', previousOpacity);
+
+ var preSlope = document.getElementById(previous+'_linear');
+ if (preSlope) {
+ preSlope.setAttributeNS(null,'visibility', 'hidden');
+ }
+ }
+
+ var group = document.getElementById(id);
+ previous = id;
+ if (group) {
+ group.parentNode.appendChild(group);
+
+ var line = document.getElementById(id+'_line');
+ previousColor = line.getAttributeNS(null,'stroke');
+ previousOpacity = line.getAttributeNS(null,'opacity');
+ line.setAttributeNS(null,'stroke', 'blue');
+ line.setAttributeNS(null,'opacity', '1');
+
+ var slope = document.getElementById(id+'_linear');
+ if (slope) {
+ slope.setAttributeNS(null,'visibility', 'visible');
+ }
+ }
+ }
+//]]></script>"""
+ for label, line in lines.items():
+ print '<g id=%s>' % qa(label)
+ r = 128
+ g = 128
+ b = 128
+ a = .10
+ if label in regressions:
+ regression = regressions[label]
+ min_slope = regression.find_min_slope()
+ if min_slope < 0:
+ d = max(0, (min_slope / min_down_slope))
+ g += int(d*128)
+ a += d*0.9
+ elif min_slope > 0:
+ d = max(0, (min_slope / max_up_slope))
+ r += int(d*128)
+ a += d*0.9
+
+ slope = regression.slope
+ intercept = regression.intercept
+ min_x = regression.min_x
+ max_x = regression.max_x
+ print '<polyline id=%s' % qa(str(label)+'_linear'),
+ print 'fill="none" stroke="yellow"',
+ print 'stroke-width=%s' % qa(abs(ch(regression.serror*2))),
+ print 'opacity="0.5" pointer-events="none" visibility="hidden"',
+ print 'points="',
+ print '%s,%s' % (str(cx(min_x)), str(cy(slope*min_x + intercept))),
+ print '%s,%s' % (str(cx(max_x)), str(cy(slope*max_x + intercept))),
+ print '"/>'
+
+ print '<polyline id=%s' % qa(str(label)+'_line'),
+ print 'onmouseover=%s' % qa(
+ "var event = arguments[0] || window.event;"
+ " if (event.ctrlKey) {"
+ " highlight('"+str(label).replace("'", "\\'")+"');"
+ " return false;"
+ " }"),
+ print 'fill="none" stroke="rgb(%s,%s,%s)"' % (str(r), str(g), str(b)),
+ print 'stroke-width=%s' % qa(line_width),
+ print 'opacity=%s' % qa(a),
+ print 'points="',
+ for point in line:
+ print '%s,%s' % (str(cx(point[0])), str(cy(point[1]))),
+ print '"/>'
+
+ print '</g>'
+
+ #output the labels
+ print '<text id="label" x="0" y=%s' % qa(font_size),
+ print 'font-size=%s> </text>' % qa(font_size)
+
+ print '<a id="rev_link" xlink:href="" target="_top">'
+ print '<text id="revision" x="0" y=%s style="' % qa(font_size*2)
+ print 'font-size: %s; ' % qe(font_size)
+ print 'stroke: #0000dd; text-decoration: underline; '
+ print '"> </text></a>'
+
+ print '</svg>'
+
+if __name__ == "__main__":
+ main()
diff --git a/bench/bench_util.py b/bench/bench_util.py
new file mode 100644
index 0000000..e36e6c6
--- /dev/null
+++ b/bench/bench_util.py
@@ -0,0 +1,178 @@
+'''
+Created on May 19, 2011
+
+@author: bungeman
+'''
+
+import re
+import math
+
+class BenchDataPoint:
+ """A single data point produced by bench.
+
+ (str, str, str, float, {str:str})"""
+ def __init__(self, bench, config, time_type, time, settings):
+ self.bench = bench
+ self.config = config
+ self.time_type = time_type
+ self.time = time
+ self.settings = settings
+
+ def __repr__(self):
+ return "BenchDataPoint(%s, %s, %s, %s, %s)" % (
+ str(self.bench),
+ str(self.config),
+ str(self.time_type),
+ str(self.time),
+ str(self.settings),
+ )
+
+class _ExtremeType(object):
+ """Instances of this class compare greater or less than other objects."""
+ def __init__(self, cmpr, rep):
+ object.__init__(self)
+ self._cmpr = cmpr
+ self._rep = rep
+
+ def __cmp__(self, other):
+ if isinstance(other, self.__class__) and other._cmpr == self._cmpr:
+ return 0
+ return self._cmpr
+
+ def __repr__(self):
+ return self._rep
+
+Max = _ExtremeType(1, "Max")
+Min = _ExtremeType(-1, "Min")
+
+def parse(settings, lines):
+ """Parses bench output into a useful data structure.
+
+ ({str:str}, __iter__ -> str) -> [BenchDataPoint]"""
+
+ benches = []
+ current_bench = None
+ setting_re = '([^\s=]+)(?:=(\S+))?'
+ settings_re = 'skia bench:((?:\s+' + setting_re + ')*)'
+ bench_re = 'running bench (?:\[\d+ \d+\] )?\s*(\S+)'
+ time_re = '(?:(\w*)msecs = )?\s*(\d+\.\d+)'
+ config_re = '(\S+): ((?:' + time_re + '\s+)+)'
+
+ for line in lines:
+
+ #see if this line is a settings line
+ settingsMatch = re.search(settings_re, line)
+ if (settingsMatch):
+ settings = dict(settings)
+ for settingMatch in re.finditer(setting_re, settingsMatch.group(1)):
+ if (settingMatch.group(2)):
+ settings[settingMatch.group(1)] = settingMatch.group(2)
+ else:
+ settings[settingMatch.group(1)] = True
+
+ #see if this line starts a new bench
+ new_bench = re.search(bench_re, line)
+ if new_bench:
+ current_bench = new_bench.group(1)
+
+ #add configs on this line to the current bench
+ if current_bench:
+ for new_config in re.finditer(config_re, line):
+ current_config = new_config.group(1)
+ times = new_config.group(2)
+ for new_time in re.finditer(time_re, times):
+ current_time_type = new_time.group(1)
+ current_time = float(new_time.group(2))
+ benches.append(BenchDataPoint(
+ current_bench
+ , current_config
+ , current_time_type
+ , current_time
+ , settings))
+
+ return benches
+
+class LinearRegression:
+ """Linear regression data based on a set of data points.
+
+ ([(Number,Number)])
+ There must be at least two points for this to make sense."""
+ def __init__(self, points):
+ n = len(points)
+ max_x = Min
+ min_x = Max
+
+ Sx = 0.0
+ Sy = 0.0
+ Sxx = 0.0
+ Sxy = 0.0
+ Syy = 0.0
+ for point in points:
+ x = point[0]
+ y = point[1]
+ max_x = max(max_x, x)
+ min_x = min(min_x, x)
+
+ Sx += x
+ Sy += y
+ Sxx += x*x
+ Sxy += x*y
+ Syy += y*y
+
+ B = (n*Sxy - Sx*Sy) / (n*Sxx - Sx*Sx)
+ a = (1.0/n)*(Sy - B*Sx)
+
+ se2 = 0
+ sB2 = 0
+ sa2 = 0
+ if (n >= 3):
+ se2 = (1.0/(n*(n-2)) * (n*Syy - Sy*Sy - B*B*(n*Sxx - Sx*Sx)))
+ sB2 = (n*se2) / (n*Sxx - Sx*Sx)
+ sa2 = sB2 * (1.0/n) * Sxx
+
+
+ self.slope = B
+ self.intercept = a
+ self.serror = math.sqrt(max(0, se2))
+ self.serror_slope = math.sqrt(max(0, sB2))
+ self.serror_intercept = math.sqrt(max(0, sa2))
+ self.max_x = max_x
+ self.min_x = min_x
+
+ def __repr__(self):
+ return "LinearRegression(%s, %s, %s, %s, %s)" % (
+ str(self.slope),
+ str(self.intercept),
+ str(self.serror),
+ str(self.serror_slope),
+ str(self.serror_intercept),
+ )
+
+ def find_min_slope(self):
+ """Finds the minimal slope given one standard deviation."""
+ slope = self.slope
+ intercept = self.intercept
+ error = self.serror
+ regr_start = self.min_x
+ regr_end = self.max_x
+ regr_width = regr_end - regr_start
+
+ if slope < 0:
+ lower_left_y = slope*regr_start + intercept - error
+ upper_right_y = slope*regr_end + intercept + error
+ return min(0, (upper_right_y - lower_left_y) / regr_width)
+
+ elif slope > 0:
+ upper_left_y = slope*regr_start + intercept + error
+ lower_right_y = slope*regr_end + intercept - error
+ return max(0, (lower_right_y - upper_left_y) / regr_width)
+
+ return 0
+
+def CreateRevisionLink(revision_number):
+ """Returns HTML displaying the given revision number and linking to
+ that revision's change page at code.google.com, e.g.
+ http://code.google.com/p/skia/source/detail?r=2056
+ """
+ return '<a href="http://code.google.com/p/skia/source/detail?r=%s">%s</a>'%(
+ revision_number, revision_number)
diff --git a/bench/benchmain.cpp b/bench/benchmain.cpp
index 34f8a1a..024ad0f 100644
--- a/bench/benchmain.cpp
+++ b/bench/benchmain.cpp
@@ -1,18 +1,30 @@
+
+/*
+ * Copyright 2011 Google Inc.
+ *
+ * Use of this source code is governed by a BSD-style license that can be
+ * found in the LICENSE file.
+ */
+
+
+#include "BenchTimer.h"
+
+#include "GrContext.h"
+#include "GrRenderTarget.h"
+
+#include "SkBenchmark.h"
#include "SkCanvas.h"
#include "SkColorPriv.h"
+#include "SkGpuDevice.h"
#include "SkGraphics.h"
#include "SkImageEncoder.h"
+#include "SkNativeGLContext.h"
+#include "SkNullGLContext.h"
#include "SkNWayCanvas.h"
#include "SkPicture.h"
#include "SkString.h"
-#include "GrContext.h"
-#include "SkGpuDevice.h"
-#include "SkEGLContext.h"
-#include "SkBenchmark.h"
-#include "BenchTimer.h"
-
-#ifdef ANDROID
+#ifdef SK_BUILD_FOR_ANDROID
static void log_error(const char msg[]) { SkDebugf("%s", msg); }
static void log_progress(const char msg[]) { SkDebugf("%s", msg); }
#else
@@ -161,8 +173,67 @@ enum Backend {
kPDF_Backend,
};
+class GLHelper {
+public:
+ GLHelper() {
+ }
+
+ bool init(SkGLContext* glCtx, int width, int height) {
+ GrContext* grCtx;
+ GrRenderTarget* rt;
+ if (glCtx->init(width, height)) {
+ GrPlatform3DContext ctx =
+ reinterpret_cast<GrPlatform3DContext>(glCtx->gl());
+ grCtx = GrContext::Create(kOpenGL_Shaders_GrEngine, ctx);
+ if (NULL != grCtx) {
+ GrPlatformRenderTargetDesc desc;
+ desc.fConfig = kSkia8888_PM_GrPixelConfig;
+ desc.fWidth = width;
+ desc.fHeight = height;
+ desc.fStencilBits = 8;
+ desc.fRenderTargetHandle = glCtx->getFBOID();
+ rt = grCtx->createPlatformRenderTarget(desc);
+ if (NULL == rt) {
+ grCtx->unref();
+ return false;
+ }
+ }
+ } else {
+ return false;
+ }
+ glCtx->ref();
+ fGLContext.reset(glCtx);
+ fGrContext.reset(grCtx);
+ fRenderTarget.reset(rt);
+ return true;
+ }
+
+ bool isValid() {
+ return NULL != fGLContext.get();
+ }
+
+ SkGLContext* glContext() {
+ return fGLContext.get();
+ }
+
+ GrRenderTarget* renderTarget() {
+ return fRenderTarget.get();
+ }
+
+ GrContext* grContext() {
+ return fGrContext.get();
+ }
+private:
+ SkAutoTUnref<SkGLContext> fGLContext;
+ SkAutoTUnref<GrContext> fGrContext;
+ SkAutoTUnref<GrRenderTarget> fRenderTarget;
+};
+
+static GLHelper gRealGLHelper;
+static GLHelper gNullGLHelper;
+
static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
- Backend backend, GrContext* context) {
+ Backend backend, GLHelper* glHelper) {
SkDevice* device = NULL;
SkBitmap bitmap;
bitmap.setConfig(config, size.fX, size.fY);
@@ -171,11 +242,11 @@ static SkDevice* make_device(SkBitmap::Config config, const SkIPoint& size,
case kRaster_Backend:
bitmap.allocPixels();
erase(bitmap);
- device = new SkDevice(NULL, bitmap, true);
+ device = new SkDevice(bitmap);
break;
case kGPU_Backend:
- device = new SkGpuDevice(context, bitmap, SkGpuDevice::Current3DApiRenderTarget());
-// device->clear(0xFFFFFFFF);
+ device = new SkGpuDevice(glHelper->grContext(),
+ glHelper->renderTarget());
break;
case kPDF_Backend:
default:
@@ -188,10 +259,12 @@ static const struct {
SkBitmap::Config fConfig;
const char* fName;
Backend fBackend;
+ GLHelper* fGLHelper;
} gConfigs[] = {
- { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend },
- { SkBitmap::kRGB_565_Config, "565", kRaster_Backend },
- { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend },
+ { SkBitmap::kARGB_8888_Config, "8888", kRaster_Backend, NULL },
+ { SkBitmap::kRGB_565_Config, "565", kRaster_Backend, NULL },
+ { SkBitmap::kARGB_8888_Config, "GPU", kGPU_Backend, &gRealGLHelper },
+ { SkBitmap::kARGB_8888_Config, "NULLGPU", kGPU_Backend, &gNullGLHelper },
};
static int findConfig(const char config[]) {
@@ -203,6 +276,36 @@ static int findConfig(const char config[]) {
return -1;
}
+static void determine_gpu_context_size(SkTDict<const char*>& defineDict,
+ int* contextWidth,
+ int* contextHeight) {
+ Iter iter(&defineDict);
+ SkBenchmark* bench;
+ while ((bench = iter.next()) != NULL) {
+ SkIPoint dim = bench->getSize();
+ if (*contextWidth < dim.fX) {
+ *contextWidth = dim.fX;
+ }
+ if (*contextHeight < dim.fY) {
+ *contextHeight = dim.fY;
+ }
+ }
+}
+
+static bool skip_name(const SkTDArray<const char*> array, const char name[]) {
+ if (0 == array.count()) {
+ // no names, so don't skip anything
+ return false;
+ }
+ for (int i = 0; i < array.count(); ++i) {
+ if (strstr(name, array[i])) {
+ // found the name, so don't skip
+ return false;
+ }
+ }
+ return true;
+}
+
int main (int argc, char * const argv[]) {
SkAutoGraphics ag;
@@ -218,12 +321,13 @@ int main (int argc, char * const argv[]) {
bool doScale = false;
bool doRotate = false;
bool doClip = false;
- const char* matchStr = NULL;
bool hasStrokeWidth = false;
float strokeWidth;
+ SkTDArray<const char*> fMatches;
SkString outDir;
SkBitmap::Config outConfig = SkBitmap::kNo_Config;
+ GLHelper* glHelper = NULL;
const char* configName = "";
Backend backend = kRaster_Backend; // for warning
int configCount = SK_ARRAY_COUNT(gConfigs);
@@ -312,7 +416,7 @@ int main (int argc, char * const argv[]) {
} else if (strcmp(*argv, "-match") == 0) {
argv++;
if (argv < stop) {
- matchStr = *argv;
+ *fMatches.append() = *argv;
} else {
log_error("missing arg for -match\n");
return -1;
@@ -325,6 +429,7 @@ int main (int argc, char * const argv[]) {
outConfig = gConfigs[index].fConfig;
configName = gConfigs[index].fName;
backend = gConfigs[index].fBackend;
+ glHelper = gConfigs[index].fGLHelper;
configCount = 1;
} else {
SkString str;
@@ -355,19 +460,63 @@ int main (int argc, char * const argv[]) {
// report our current settings
{
SkString str;
- str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d\n",
+ str.printf("skia bench: alpha=0x%02X antialias=%d filter=%d",
forceAlpha, forceAA, forceFilter);
+ str.appendf(" rotate=%d scale=%d clip=%d",
+ doRotate, doScale, doClip);
+
+ const char * ditherName;
+ switch (forceDither) {
+ case SkTriState::kDefault: ditherName = "default"; break;
+ case SkTriState::kTrue: ditherName = "true"; break;
+ case SkTriState::kFalse: ditherName = "false"; break;
+ default: ditherName = "<invalid>"; break;
+ }
+ str.appendf(" dither=%s", ditherName);
+
+ if (hasStrokeWidth) {
+ str.appendf(" strokeWidth=%f", strokeWidth);
+ } else {
+ str.append(" strokeWidth=none");
+ }
+
+#if defined(SK_SCALAR_IS_FLOAT)
+ str.append(" scalar=float");
+#elif defined(SK_SCALAR_IS_FIXED)
+ str.append(" scalar=fixed");
+#endif
+
+#if defined(SK_BUILD_FOR_WIN32)
+ str.append(" system=WIN32");
+#elif defined(SK_BUILD_FOR_MAC)
+ str.append(" system=MAC");
+#elif defined(SK_BUILD_FOR_ANDROID)
+ str.append(" system=ANDROID");
+#elif defined(SK_BUILD_FOR_UNIX)
+ str.append(" system=UNIX");
+#else
+ str.append(" system=other");
+#endif
+
+#if defined(SK_DEBUG)
+ str.append(" DEBUG");
+#endif
+ str.append("\n");
log_progress(str);
}
-
- GrContext* context = NULL;
- SkEGLContext eglContext;
- if (eglContext.init(1024, 1024)) {
- context = GrContext::CreateGLShaderContext();
- }
-
- BenchTimer timer = BenchTimer();
-
+
+ //Don't do GL when fixed.
+#if !defined(SK_SCALAR_IS_FIXED)
+ int contextWidth = 1024;
+ int contextHeight = 1024;
+ determine_gpu_context_size(defineDict, &contextWidth, &contextHeight);
+ SkAutoTUnref<SkGLContext> realGLCtx(new SkNativeGLContext);
+ SkAutoTUnref<SkGLContext> nullGLCtx(new SkNullGLContext);
+ gRealGLHelper.init(realGLCtx.get(), contextWidth, contextHeight);
+ gNullGLHelper.init(nullGLCtx.get(), contextWidth, contextHeight);
+#endif
+ BenchTimer timer = BenchTimer(gRealGLHelper.glContext());
+
Iter iter(&defineDict);
SkBenchmark* bench;
while ((bench = iter.next()) != NULL) {
@@ -385,7 +534,7 @@ int main (int argc, char * const argv[]) {
}
// only run benchmarks if their name contains matchStr
- if (matchStr && strstr(bench->getName(), matchStr) == NULL) {
+ if (skip_name(fMatches, bench->getName())) {
continue;
}
@@ -401,13 +550,15 @@ int main (int argc, char * const argv[]) {
outConfig = gConfigs[configIndex].fConfig;
configName = gConfigs[configIndex].fName;
backend = gConfigs[configIndex].fBackend;
+ glHelper = gConfigs[configIndex].fGLHelper;
}
-
- if (kGPU_Backend == backend && NULL == context) {
+
+ if (kGPU_Backend == backend &&
+ (NULL == glHelper || !glHelper->isValid())) {
continue;
}
- SkDevice* device = make_device(outConfig, dim, backend, context);
+ SkDevice* device = make_device(outConfig, dim, backend, glHelper);
SkCanvas canvas(device);
device->unref();
@@ -420,15 +571,14 @@ int main (int argc, char * const argv[]) {
if (doRotate) {
performRotate(&canvas, dim.fX, dim.fY);
}
-
- bool gpu = kGPU_Backend == backend && context;
+
//warm up caches if needed
if (repeatDraw > 1) {
SkAutoCanvasRestore acr(&canvas, true);
bench->draw(&canvas);
- if (gpu) {
- context->flush();
- glFinish();
+ if (glHelper) {
+ glHelper->grContext()->flush();
+ SK_GL(*glHelper->glContext(), Finish());
}
}
@@ -436,8 +586,14 @@ int main (int argc, char * const argv[]) {
for (int i = 0; i < repeatDraw; i++) {
SkAutoCanvasRestore acr(&canvas, true);
bench->draw(&canvas);
+ if (glHelper) {
+ glHelper->grContext()->flush();
+ }
}
- timer.end();
+ if (glHelper) {
+ SK_GL(*glHelper->glContext(), Finish());
+ }
+ timer.end();
if (repeatDraw > 1) {
SkString str;
@@ -448,7 +604,7 @@ int main (int argc, char * const argv[]) {
if (timerCpu) {
str.appendf(" cmsecs = %6.2f", timer.fCpu / repeatDraw);
}
- if (timerGpu && gpu && timer.fGpu > 0) {
+ if (timerGpu && glHelper && timer.fGpu > 0) {
str.appendf(" gmsecs = %6.2f", timer.fGpu / repeatDraw);
}
log_progress(str);
@@ -460,6 +616,6 @@ int main (int argc, char * const argv[]) {
}
log_progress("\n");
}
-
+
return 0;
}