18af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com/*
28af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com * Copyright 2013 Google Inc.
38af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com *
48af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com * Use of this source code is governed by a BSD-style license that can be
58af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com * found in the LICENSE file.
68af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com */
78af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
8f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina#include "Benchmark.h"
98af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com#include "SkCanvas.h"
1067a3271f0de9ccc32d559b042b862528272047ccmtklein#include "SkChecksum.h"
118af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com#include "SkPaint.h"
128af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com#include "SkString.h"
138af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com#include "SkTemplates.h"
148af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
15664621a19e7ca5236ae4fce19e3ffd97f047b64dreed@google.com#include "gUniqueGlyphIDs.h"
16c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com#define gUniqueGlyphIDs_Sentinel    0xFFFF
178af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
18c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic int count_glyphs(const uint16_t start[]) {
19c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    const uint16_t* curr = start;
20c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    while (*curr != gUniqueGlyphIDs_Sentinel) {
21c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        curr += 1;
228af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com    }
238b169311b59ab84e8ca6f3630a1e960cc1be751erobertphillips@google.com    return static_cast<int>(curr - start);
24c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com}
258af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
26f168b86d7fafc5c20c87bebc6fd393cb17e120catfarinaclass FontCacheBench : public Benchmark {
27c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.compublic:
28410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com    FontCacheBench()  {}
29a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
308af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.comprotected:
3136352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* onGetName() override {
328af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com        return "fontcache";
338af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com    }
34a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
352880df2609eba09b555ca37be04b6ad89290c765Tom Hudson    void onDraw(int loops, SkCanvas* canvas) override {
368af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com        SkPaint paint;
378af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com        this->setupPaint(&paint);
388af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
39a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
402fef6d2bda33b348133843e22c1009504c6fc209reed@google.com        const uint16_t* array = gUniqueGlyphIDs;
41c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        while (*array != gUniqueGlyphIDs_Sentinel) {
428b169311b59ab84e8ca6f3630a1e960cc1be751erobertphillips@google.com            int count = count_glyphs(array);
433361471a3504ecd0351ff70f4c42d8d6fee963d4commit-bot@chromium.org            for (int i = 0; i < loops; ++i) {
44c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                paint.measureText(array, count * sizeof(uint16_t));
458af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com            }
46c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com            array += count + 1;    // skip the sentinel
478af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com        }
488af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com    }
49a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
50c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comprivate:
51f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina    typedef Benchmark INHERITED;
52c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com};
53c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
54c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com///////////////////////////////////////////////////////////////////////////////
55c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
56c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic uint32_t rotr(uint32_t value, unsigned bits) {
57c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    return (value >> bits) | (value << (32 - bits));
58c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com}
59c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
60c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comtypedef uint32_t (*HasherProc)(uint32_t);
61c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
62c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic uint32_t hasher0(uint32_t value) {
63c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    value = value ^ (value >> 16);
64c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    return value ^ (value >> 8);
65c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com}
66c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
67c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic const struct {
68c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    const char* fName;
69c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    HasherProc  fHasher;
70c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com} gRec[] = {
71c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    { "hasher0",  hasher0 },
7267a3271f0de9ccc32d559b042b862528272047ccmtklein    { "hasher2",  SkChecksum::Mix },
73c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com};
74c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
75c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com#define kMaxHashBits   12
76c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com#define kMaxHashCount  (1 << kMaxHashBits)
77c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
78c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic int count_collisions(const uint16_t array[], int count, HasherProc proc,
79c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                            unsigned hashMask) {
80c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    char table[kMaxHashCount];
81c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    sk_bzero(table, sizeof(table));
82a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
83c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    int collisions = 0;
84c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    for (int i = 0; i < count; ++i) {
85c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        int index = proc(array[i]) & hashMask;
86c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        collisions += table[index];
87c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        table[index] = 1;
88c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    }
89c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    return collisions;
90c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com}
91c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
92c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comstatic void dump_array(const uint16_t array[], int count) {
93c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    for (int i = 0; i < count; ++i) {
94c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        SkDebugf(" %d,", array[i]);
95c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    }
96c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    SkDebugf("\n");
97c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com}
98c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
99f168b86d7fafc5c20c87bebc6fd393cb17e120catfarinaclass FontCacheEfficiency : public Benchmark {
100c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.compublic:
101410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com    FontCacheEfficiency()  {
1022880df2609eba09b555ca37be04b6ad89290c765Tom Hudson        if (false) dump_array(nullptr, 0);
103c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        if (false) rotr(0, 0);
104c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    }
105a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
106c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.comprotected:
10736352bf5e38f45a70ee4f4fc132a38048d38206dmtklein    const char* onGetName() override {
108c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        return "fontefficiency";
109c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    }
110a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
1112880df2609eba09b555ca37be04b6ad89290c765Tom Hudson    void onDraw(int loops, SkCanvas* canvas) override {
112c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        static bool gDone;
113c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        if (gDone) {
114c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com            return;
115c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        }
116c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        gDone = true;
1178af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
118c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        for (int hashBits = 6; hashBits <= 12; hashBits += 1) {
119c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com            int hashMask = ((1 << hashBits) - 1);
120c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com            for (int limit = 32; limit <= 1024; limit <<= 1) {
121c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
122c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    int collisions = 0;
123c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    int glyphs = 0;
124c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    const uint16_t* array = gUniqueGlyphIDs;
125c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    while (*array != gUniqueGlyphIDs_Sentinel) {
126c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                        int count = SkMin32(count_glyphs(array), limit);
127c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                        collisions += count_collisions(array, count, gRec[i].fHasher, hashMask);
128c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                        glyphs += count;
129c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                        array += count + 1;    // skip the sentinel
130c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    }
131c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                    SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs,
132c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                             collisions * 100.0 / glyphs, gRec[i].fName);
133c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com                }
134c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com            }
135c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com        }
136c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com    }
137a707fd53f779843cf9354db27589bb0ef6cb1a0bskia.committer@gmail.com
1388af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.comprivate:
139f168b86d7fafc5c20c87bebc6fd393cb17e120catfarina    typedef Benchmark INHERITED;
1408af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com};
1418af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
1428af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com///////////////////////////////////////////////////////////////////////////////
1438af0371fe22e166daae1eec3cc75f1a0e69228bereed@google.com
144410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.comDEF_BENCH( return new FontCacheBench(); )
145c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com
146c26523067a42b7033b0be9150c1f79eb9cae4ce8reed@google.com// undefine this to run the efficiency test
147410e6e80f00a6c660675c80904807a041c7b7d2amtklein@google.com//DEF_BENCH( return new FontCacheEfficiency(); )
148