dispatch_priority.c 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222
  1. /*
  2. * Copyright (c) 2008-2011 Apple Inc. All rights reserved.
  3. *
  4. * @APPLE_APACHE_LICENSE_HEADER_START@
  5. *
  6. * Licensed under the Apache License, Version 2.0 (the "License");
  7. * you may not use this file except in compliance with the License.
  8. * You may obtain a copy of the License at
  9. *
  10. * http://www.apache.org/licenses/LICENSE-2.0
  11. *
  12. * Unless required by applicable law or agreed to in writing, software
  13. * distributed under the License is distributed on an "AS IS" BASIS,
  14. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  15. * See the License for the specific language governing permissions and
  16. * limitations under the License.
  17. *
  18. * @APPLE_APACHE_LICENSE_HEADER_END@
  19. */
  20. #include <stdio.h>
  21. #include <dispatch/dispatch.h>
  22. #include <dispatch/private.h>
  23. #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
  24. #include <unistd.h>
  25. #ifdef __ANDROID__
  26. #include <linux/sysctl.h>
  27. #else
  28. #if !defined(__linux__)
  29. #include <sys/sysctl.h>
  30. #endif
  31. #endif /* __ANDROID__ */
  32. #endif
  33. #include <stdlib.h>
  34. #include <assert.h>
  35. #ifdef __APPLE__
  36. #include <TargetConditionals.h>
  37. #endif
  38. #include <sys/types.h>
  39. #include <bsdtests.h>
  40. #include "dispatch_test.h"
  41. static volatile int done;
  42. #ifdef DISPATCH_QUEUE_PRIORITY_BACKGROUND // <rdar://problem/7439794>
  43. #define USE_BACKGROUND_PRIORITY 1
  44. #else
  45. #define DISPATCH_QUEUE_PRIORITY_BACKGROUND INT16_MIN
  46. #endif
  47. #define QUEUE_PRIORITY_PTHREAD INT_MAX
  48. #if DISPATCH_API_VERSION < 20100518 // <rdar://problem/7790099>
  49. #define DISPATCH_QUEUE_CONCURRENT NULL
  50. #endif
  51. #if TARGET_OS_EMBEDDED
  52. #define LOOP_COUNT 5000000
  53. const int importance = 24; // priority 55
  54. #else
  55. #define LOOP_COUNT 100000000
  56. const int importance = 4; // priority 35
  57. #endif
  58. char *labels[] = { "BACKGROUND", "LOW", "DEFAULT", "HIGH", };
  59. int levels[] = {
  60. DISPATCH_QUEUE_PRIORITY_BACKGROUND, DISPATCH_QUEUE_PRIORITY_LOW,
  61. DISPATCH_QUEUE_PRIORITY_DEFAULT, DISPATCH_QUEUE_PRIORITY_HIGH,
  62. };
  63. #define PRIORITIES (sizeof(levels)/sizeof(*levels))
  64. static union {
  65. long count;
  66. char padding[64];
  67. } counts[PRIORITIES];
  68. static volatile long iterations;
  69. static long total;
  70. static size_t prio0, priorities = PRIORITIES;
  71. static int
  72. n_blocks(void)
  73. {
  74. static dispatch_once_t pred;
  75. static int n;
  76. dispatch_once(&pred, ^{
  77. #ifdef __linux__
  78. n = (int)sysconf(_SC_NPROCESSORS_CONF);
  79. #elif defined(_WIN32)
  80. SYSTEM_INFO si;
  81. GetSystemInfo(&si);
  82. n = (int)si.dwNumberOfProcessors;
  83. #else
  84. size_t l = sizeof(n);
  85. int rc = sysctlbyname("hw.ncpu", &n, &l, NULL, 0);
  86. assert(rc == 0);
  87. #endif
  88. n *= 32;
  89. });
  90. return n;
  91. }
  92. static void
  93. histogram(void)
  94. {
  95. long completed = 0;
  96. size_t x, y, i;
  97. printf("\n");
  98. for (y = prio0; y < prio0 + priorities; ++y) {
  99. printf("%s: %ld\n", labels[y], counts[y].count);
  100. completed += counts[y].count;
  101. double fraction = (double)counts[y].count / (double)n_blocks();
  102. double value = fraction * (double)80;
  103. for (x = 0; x < 80; ++x) {
  104. printf("%s", (value > x) ? "*" : " ");
  105. }
  106. printf("\n");
  107. }
  108. test_long("blocks completed", completed, total);
  109. for (i = prio0; i < prio0 + priorities; i++) {
  110. if (levels[i] == DISPATCH_QUEUE_PRIORITY_HIGH) {
  111. test_long_less_than_or_equal("high priority precedence",
  112. counts[i-2].count, counts[i].count);
  113. }
  114. #if USE_BACKGROUND_PRIORITY
  115. if (levels[i] == DISPATCH_QUEUE_PRIORITY_BACKGROUND) {
  116. test_long_less_than_or_equal("background priority precedence",
  117. counts[i].count, counts[i+2].count);
  118. }
  119. #endif
  120. }
  121. }
  122. static void
  123. cpubusy(void* context)
  124. {
  125. if (done) return;
  126. size_t idx;
  127. for (idx = 0; idx < LOOP_COUNT; ++idx) {
  128. if (done) break;
  129. }
  130. volatile long *count = context;
  131. long iterdone = __sync_sub_and_fetch(&iterations, 1);
  132. if (iterdone >= 0) {
  133. __sync_add_and_fetch(count, 1);
  134. if (!iterdone) {
  135. __sync_add_and_fetch(&done, 1);
  136. usleep(100000);
  137. histogram();
  138. dispatch_time_t delay = DISPATCH_TIME_NOW;
  139. dispatch_after(delay, dispatch_get_main_queue(), ^{
  140. test_stop();
  141. });
  142. }
  143. }
  144. }
  145. static void
  146. submit_work(dispatch_queue_t queue, void* context)
  147. {
  148. int i;
  149. for (i = n_blocks(); i; --i) {
  150. dispatch_async_f(queue, context, cpubusy);
  151. }
  152. }
  153. int
  154. main(int argc __attribute__((unused)), char* argv[] __attribute__((unused)))
  155. {
  156. dispatch_queue_t q[PRIORITIES];
  157. size_t i;
  158. #if !USE_BACKGROUND_PRIORITY
  159. prio0++;
  160. priorities--;
  161. #endif
  162. iterations = total = ((int)priorities * n_blocks()) / 2;
  163. #if USE_SET_TARGET_QUEUE
  164. dispatch_test_start("Dispatch Priority (Set Target Queue)");
  165. #else
  166. dispatch_test_start("Dispatch Priority");
  167. #endif
  168. for (i = prio0; i < prio0 + priorities; i++) {
  169. dispatch_queue_t rq = dispatch_get_global_queue(levels[i], 0);
  170. #if USE_SET_TARGET_QUEUE
  171. q[i] = dispatch_queue_create(labels[i], DISPATCH_QUEUE_CONCURRENT);
  172. test_ptr_notnull("q[i]", q[i]);
  173. assert(q[i]);
  174. dispatch_suspend(q[i]);
  175. dispatch_set_target_queue(q[i], rq);
  176. if (DISPATCH_QUEUE_CONCURRENT != NULL) {
  177. dispatch_queue_set_width(q[i], LONG_MAX);
  178. }
  179. dispatch_release(rq);
  180. #else
  181. q[i] = rq;
  182. #endif
  183. }
  184. for (i = prio0; i < prio0 + priorities; i++) {
  185. submit_work(q[i], &counts[i].count);
  186. }
  187. for (i = prio0; i < prio0 + priorities; i++) {
  188. dispatch_resume(q[i]);
  189. dispatch_release(q[i]);
  190. }
  191. dispatch_main();
  192. return 0;
  193. }