hb-subset-threads.cc 4.5 KB

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