hb-subset-threads.cc 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #include <cassert>
  2. #include <cstdio>
  3. #include <cstdlib>
  4. #include <cstring>
  5. #include <thread>
  6. #include <condition_variable>
  7. #include <vector>
  8. #ifdef HAVE_CONFIG_H
  9. #include "config.h"
  10. #endif
  11. #include "hb-subset.h"
  12. enum operation_t
  13. {
  14. subset_codepoints,
  15. subset_glyphs
  16. };
  17. #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
  18. struct test_input_t
  19. {
  20. const char *font_path;
  21. const unsigned max_subset_size;
  22. } default_tests[] =
  23. {
  24. {SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf", 4000},
  25. {SUBSET_FONT_BASE_PATH "Amiri-Regular.ttf", 4000},
  26. {SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf", 1000},
  27. {SUBSET_FONT_BASE_PATH "NotoSansDevanagari-Regular.ttf", 1000},
  28. {SUBSET_FONT_BASE_PATH "Mplus1p-Regular.ttf", 10000},
  29. {SUBSET_FONT_BASE_PATH "SourceHanSans-Regular_subset.otf", 10000},
  30. {SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf", 2000},
  31. };
  32. static test_input_t *tests = default_tests;
  33. static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
  34. // https://en.cppreference.com/w/cpp/thread/condition_variable/wait
  35. static std::condition_variable cv;
  36. static std::mutex cv_m;
  37. static bool ready = false;
  38. static unsigned num_repetitions = 1;
  39. static unsigned num_threads = 3;
  40. static void AddCodepoints(const hb_set_t* codepoints_in_font,
  41. unsigned subset_size,
  42. hb_subset_input_t* input)
  43. {
  44. auto *unicodes = hb_subset_input_unicode_set (input);
  45. hb_codepoint_t cp = HB_SET_VALUE_INVALID;
  46. for (unsigned i = 0; i < subset_size; i++) {
  47. if (!hb_set_next (codepoints_in_font, &cp)) return;
  48. hb_set_add (unicodes, cp);
  49. }
  50. }
  51. static void AddGlyphs(unsigned num_glyphs_in_font,
  52. unsigned subset_size,
  53. hb_subset_input_t* input)
  54. {
  55. auto *glyphs = hb_subset_input_glyph_set (input);
  56. for (unsigned i = 0; i < subset_size && i < num_glyphs_in_font; i++) {
  57. hb_set_add (glyphs, i);
  58. }
  59. }
  60. static void subset (operation_t operation,
  61. const test_input_t &test_input,
  62. hb_face_t *face)
  63. {
  64. // Wait till all threads are ready.
  65. {
  66. std::unique_lock<std::mutex> lk (cv_m);
  67. cv.wait(lk, [] {return ready;});
  68. }
  69. unsigned subset_size = test_input.max_subset_size;
  70. hb_subset_input_t* input = hb_subset_input_create_or_fail ();
  71. assert (input);
  72. switch (operation)
  73. {
  74. case subset_codepoints:
  75. {
  76. hb_set_t* all_codepoints = hb_set_create ();
  77. hb_face_collect_unicodes (face, all_codepoints);
  78. AddCodepoints(all_codepoints, subset_size, input);
  79. hb_set_destroy (all_codepoints);
  80. }
  81. break;
  82. case subset_glyphs:
  83. {
  84. unsigned num_glyphs = hb_face_get_glyph_count (face);
  85. AddGlyphs(num_glyphs, subset_size, input);
  86. }
  87. break;
  88. }
  89. for (unsigned i = 0; i < num_repetitions; i++)
  90. {
  91. hb_face_t* subset = hb_subset_or_fail (face, input);
  92. assert (subset);
  93. hb_face_destroy (subset);
  94. }
  95. hb_subset_input_destroy (input);
  96. }
  97. static void test_operation (operation_t operation,
  98. const char *operation_name,
  99. const test_input_t &test_input)
  100. {
  101. char name[1024] = "subset";
  102. const char *p;
  103. strcat (name, "/");
  104. p = strrchr (test_input.font_path, '/');
  105. strcat (name, p ? p + 1 : test_input.font_path);
  106. strcat (name, "/");
  107. strcat (name, operation_name);
  108. printf ("Testing %s\n", name);
  109. hb_face_t *face;
  110. {
  111. hb_blob_t *blob = hb_blob_create_from_file_or_fail (test_input.font_path);
  112. assert (blob);
  113. face = hb_face_create (blob, 0);
  114. hb_blob_destroy (blob);
  115. }
  116. std::vector<std::thread> threads;
  117. for (unsigned i = 0; i < num_threads; i++)
  118. threads.push_back (std::thread (subset, operation, test_input, face));
  119. {
  120. std::unique_lock<std::mutex> lk (cv_m);
  121. ready = true;
  122. }
  123. cv.notify_all();
  124. for (unsigned i = 0; i < num_threads; i++)
  125. threads[i].join ();
  126. hb_face_destroy (face);
  127. }
  128. int main(int argc, char** argv)
  129. {
  130. if (argc > 1)
  131. num_threads = atoi (argv[1]);
  132. if (argc > 2)
  133. num_repetitions = atoi (argv[2]);
  134. if (argc > 4)
  135. {
  136. num_tests = argc - 3;
  137. tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
  138. for (unsigned i = 0; i < num_tests; i++)
  139. {
  140. tests[i].font_path = argv[3 + i];
  141. }
  142. }
  143. printf ("Num threads %u; num repetitions %u\n", num_threads, num_repetitions);
  144. for (unsigned i = 0; i < num_tests; i++)
  145. {
  146. auto& test_input = tests[i];
  147. test_operation (subset_codepoints, "codepoints", test_input);
  148. test_operation (subset_glyphs, "glyphs", test_input);
  149. }
  150. if (tests != default_tests)
  151. free (tests);
  152. }