FontCacheBench.cpp 5.6 KB

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