1fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot/*
2fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Copyright 2013 Google Inc.
3fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot *
4fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * Use of this source code is governed by a BSD-style license that can be
5fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot * found in the LICENSE file.
6fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot */
7fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
8fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "Benchmark.h"
9fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkCanvas.h"
10fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkChecksum.h"
11fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkPaint.h"
12fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkString.h"
13fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "SkTemplates.h"
14fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
15fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#include "gUniqueGlyphIDs.h"
16fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define gUniqueGlyphIDs_Sentinel    0xFFFF
17fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
18fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int count_glyphs(const uint16_t start[]) {
19fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const uint16_t* curr = start;
20fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    while (*curr != gUniqueGlyphIDs_Sentinel) {
21fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        curr += 1;
22fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
23fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return static_cast<int>(curr - start);
24fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
25fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
26fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass FontCacheBench : public Benchmark {
27fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
28fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FontCacheBench()  {}
29fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
30fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
31fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* onGetName() override {
32fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return "fontcache";
33fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
34fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
35fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onDraw(int loops, SkCanvas* canvas) override {
36fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkPaint paint;
37fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        this->setupPaint(&paint);
38fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
39fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
40fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        const uint16_t* array = gUniqueGlyphIDs;
41fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        while (*array != gUniqueGlyphIDs_Sentinel) {
42fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int count = count_glyphs(array);
43fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int i = 0; i < loops; ++i) {
44fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                paint.measureText(array, count * sizeof(uint16_t));
45fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
46fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            array += count + 1;    // skip the sentinel
47fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
48fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
49fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
50fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
51fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef Benchmark INHERITED;
52fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
53fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
54fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
55fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
56fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic uint32_t rotr(uint32_t value, unsigned bits) {
57fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return (value >> bits) | (value << (32 - bits));
58fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
59fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
60fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robottypedef uint32_t (*HasherProc)(uint32_t);
61fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
62fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic uint32_t hasher0(uint32_t value) {
63fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    value = value ^ (value >> 16);
64fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return value ^ (value >> 8);
65fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
66fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
67fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic const struct {
68fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* fName;
69fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    HasherProc  fHasher;
70fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot} gRec[] = {
71fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    { "hasher0",  hasher0 },
72fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    { "hasher2",  SkChecksum::Mix },
73fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
74fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
75fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define kMaxHashBits   12
76fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot#define kMaxHashCount  (1 << kMaxHashBits)
77fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
78fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic int count_collisions(const uint16_t array[], int count, HasherProc proc,
79fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                            unsigned hashMask) {
80fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    char table[kMaxHashCount];
81fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    sk_bzero(table, sizeof(table));
82fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
83fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    int collisions = 0;
84fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; ++i) {
85fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        int index = proc(array[i]) & hashMask;
86fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        collisions += table[index];
87fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        table[index] = 1;
88fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
89fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    return collisions;
90fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
91fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
92fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotstatic void dump_array(const uint16_t array[], int count) {
93fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    for (int i = 0; i < count; ++i) {
94fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        SkDebugf(" %d,", array[i]);
95fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
96fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    SkDebugf("\n");
97fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot}
98fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
99fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotclass FontCacheEfficiency : public Benchmark {
100fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotpublic:
101fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    FontCacheEfficiency()  {
102fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (false) dump_array(nullptr, 0);
103fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (false) rotr(0, 0);
104fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
105fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
106fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprotected:
107fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    const char* onGetName() override {
108fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        return "fontefficiency";
109fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
110fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
111fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    void onDraw(int loops, SkCanvas* canvas) override {
112fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        static bool gDone;
113fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        if (gDone) {
114fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            return;
115fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
116fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        gDone = true;
117fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
118fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        for (int hashBits = 6; hashBits <= 12; hashBits += 1) {
119fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            int hashMask = ((1 << hashBits) - 1);
120fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            for (int limit = 32; limit <= 1024; limit <<= 1) {
121fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
122fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    int collisions = 0;
123fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    int glyphs = 0;
124fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    const uint16_t* array = gUniqueGlyphIDs;
125fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    while (*array != gUniqueGlyphIDs_Sentinel) {
126fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        int count = SkMin32(count_glyphs(array), limit);
127fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        collisions += count_collisions(array, count, gRec[i].fHasher, hashMask);
128fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        glyphs += count;
129fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                        array += count + 1;    // skip the sentinel
130fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    }
131fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                    SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs,
132fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                             collisions * 100.0 / glyphs, gRec[i].fName);
133fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot                }
134fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot            }
135fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot        }
136fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    }
137fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
138fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robotprivate:
139fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot    typedef Benchmark INHERITED;
140fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot};
141fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
142fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot///////////////////////////////////////////////////////////////////////////////
143fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
144fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team RobotDEF_BENCH( return new FontCacheBench(); )
145fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot
146fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot// undefine this to run the efficiency test
147fe17456d5e528078ce69b5f15cf7adf1fab963fandroid-build-team Robot//DEF_BENCH( return new FontCacheEfficiency(); )
148