158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger/*
258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger * Copyright 2013 Google Inc.
358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger *
458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger * Use of this source code is governed by a BSD-style license that can be
558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger * found in the LICENSE file.
658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger */
758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkBenchmark.h"
958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkCanvas.h"
1058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkFontHost.h"
1158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkPaint.h"
1258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkString.h"
1358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "SkTemplates.h"
1458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
1558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#include "gUniqueGlyphIDs.h"
1658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#define gUniqueGlyphIDs_Sentinel    0xFFFF
1758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
1858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic int count_glyphs(const uint16_t start[]) {
1958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    const uint16_t* curr = start;
2058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    while (*curr != gUniqueGlyphIDs_Sentinel) {
2158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        curr += 1;
2258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
2358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    return curr - start;
2458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
2558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
2658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerclass FontCacheBench : public SkBenchmark {
2758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    enum {
2858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        N = SkBENCHLOOP(50)
2958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    };
3058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
3158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerpublic:
3258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    FontCacheBench(void* param) : INHERITED(param) {}
3358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
3458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerprotected:
3558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    virtual const char* onGetName() SK_OVERRIDE {
3658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        return "fontcache";
3758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
3858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
3958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
4058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        SkPaint paint;
4158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        this->setupPaint(&paint);
4258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
4358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
4458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        const uint16_t* array = gUniqueGlyphIDs;
4558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        while (*array != gUniqueGlyphIDs_Sentinel) {
4658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            size_t count = count_glyphs(array);
4758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            for (int i = 0; i < N; ++i) {
4858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                paint.measureText(array, count * sizeof(uint16_t));
4958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            }
5058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            array += count + 1;    // skip the sentinel
5158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        }
5258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
5358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
5458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerprivate:
5558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    typedef SkBenchmark INHERITED;
5658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger};
5758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
5858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
5958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
6058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic uint32_t rotr(uint32_t value, unsigned bits) {
6158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    return (value >> bits) | (value << (32 - bits));
6258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
6358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
6458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergertypedef uint32_t (*HasherProc)(uint32_t);
6558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
6658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic uint32_t hasher0(uint32_t value) {
6758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    value = value ^ (value >> 16);
6858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    return value ^ (value >> 8);
6958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
7058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
7158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic uint32_t hasher2(uint32_t h) {
7258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h ^= h >> 16;
7358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h *= 0x85ebca6b;
7458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h ^= h >> 13;
7558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h *= 0xc2b2ae35;
7658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h ^= h >> 16;
7758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
7858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    h ^= (h >> 8);
7958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    return h;
8058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
8158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
8258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic const struct {
8358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    const char* fName;
8458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    HasherProc  fHasher;
8558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger} gRec[] = {
8658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    { "hasher0",  hasher0 },
8758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    { "hasher2",  hasher2 },
8858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger};
8958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
9058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#define kMaxHashBits   12
9158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger#define kMaxHashCount  (1 << kMaxHashBits)
9258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
9358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic int count_collisions(const uint16_t array[], int count, HasherProc proc,
9458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                            unsigned hashMask) {
9558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    char table[kMaxHashCount];
9658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    sk_bzero(table, sizeof(table));
9758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
9858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    int collisions = 0;
9958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    for (int i = 0; i < count; ++i) {
10058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        int index = proc(array[i]) & hashMask;
10158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        collisions += table[index];
10258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        table[index] = 1;
10358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
10458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    return collisions;
10558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
10658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
10758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerstatic void dump_array(const uint16_t array[], int count) {
10858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    for (int i = 0; i < count; ++i) {
10958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        SkDebugf(" %d,", array[i]);
11058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
11158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    SkDebugf("\n");
11258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger}
11358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
11458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerclass FontCacheEfficiency : public SkBenchmark {
11558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerpublic:
11658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    FontCacheEfficiency(void* param) : INHERITED(param) {
11758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        if (false) dump_array(NULL, 0);
11858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        if (false) rotr(0, 0);
11958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
12058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
12158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerprotected:
12258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    virtual const char* onGetName() SK_OVERRIDE {
12358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        return "fontefficiency";
12458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
12558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
12658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    virtual void onDraw(SkCanvas* canvas) SK_OVERRIDE {
12758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        static bool gDone;
12858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        if (gDone) {
12958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            return;
13058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        }
13158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        gDone = true;
13258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
13358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        for (int hashBits = 6; hashBits <= 12; hashBits += 1) {
13458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            int hashMask = ((1 << hashBits) - 1);
13558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            for (int limit = 32; limit <= 1024; limit <<= 1) {
13658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                for (size_t i = 0; i < SK_ARRAY_COUNT(gRec); ++i) {
13758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    int collisions = 0;
13858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    int glyphs = 0;
13958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    const uint16_t* array = gUniqueGlyphIDs;
14058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    while (*array != gUniqueGlyphIDs_Sentinel) {
14158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        int count = SkMin32(count_glyphs(array), limit);
14258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        collisions += count_collisions(array, count, gRec[i].fHasher, hashMask);
14358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        glyphs += count;
14458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                        array += count + 1;    // skip the sentinel
14558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    }
14658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                    SkDebugf("hashBits [%d] limit [%d] collisions [%d / %d = %1.2g%%] using %s\n", hashBits, limit, collisions, glyphs,
14758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                             collisions * 100.0 / glyphs, gRec[i].fName);
14858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger                }
14958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger            }
15058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger        }
15158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    }
15258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
15358190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenbergerprivate:
15458190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger    typedef SkBenchmark INHERITED;
15558190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger};
15658190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
15758190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger///////////////////////////////////////////////////////////////////////////////
15858190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
15958190644c30e1c4aa8e527f3503c58f841e0fcf3Derek SollenbergerDEF_BENCH( return new FontCacheBench(p); )
16058190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger
16158190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger// undefine this to run the efficiency test
16258190644c30e1c4aa8e527f3503c58f841e0fcf3Derek Sollenberger//DEF_BENCH( return new FontCacheEfficiency(p); )
163