dispatch_vm.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. /*
  2. * Copyright (c) 2010-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 <sys/event.h>
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
  24. #include <unistd.h>
  25. #endif
  26. #ifdef __APPLE__
  27. #include <libkern/OSAtomic.h>
  28. #endif
  29. #include <assert.h>
  30. #ifdef __ANDROID__
  31. #include <linux/sysctl.h>
  32. #else
  33. #if !defined(__linux__)
  34. #include <sys/sysctl.h>
  35. #endif
  36. #endif /* __ANDROID__ */
  37. #include <stdarg.h>
  38. #include <time.h>
  39. #include <dispatch/dispatch.h>
  40. #include <dispatch/private.h>
  41. #include <bsdtests.h>
  42. #include "dispatch_test.h"
  43. #if defined(DISPATCH_SOURCE_TYPE_VM) && defined(NOTE_VM_PRESSURE)
  44. #if TARGET_OS_EMBEDDED
  45. #define ALLOC_SIZE ((size_t)(1024*1024*1ul)) // 1MB
  46. #define NOTIFICATIONS 1
  47. #else
  48. #define ALLOC_SIZE ((size_t)(1024*1024*20ul)) // 20MB
  49. #define NOTIFICATIONS 2
  50. #endif
  51. #define pg2mb(p) ((p) * ALLOC_SIZE/(1024*1024))
  52. #ifdef __LP64__
  53. #define MAXMEM ((size_t)SIZE_MAX)
  54. #else
  55. #define MAXMEM ((size_t)(3200ul*1024*1024)) // 3200MB
  56. #endif
  57. static char **pages;
  58. static volatile int32_t handler_call_count;
  59. static volatile int32_t page_count;
  60. static int32_t max_page_count;
  61. static dispatch_source_t vm_source;
  62. static dispatch_queue_t vm_queue;
  63. static time_t initial;
  64. static int interval = 16;
  65. #define log_msg(msg, ...) \
  66. do { \
  67. fprintf(stderr, "[%2ds] " msg, (int)(time(NULL) - initial), ##__VA_ARGS__);\
  68. } while (0)
  69. static bool
  70. dispatch_test_check_evfilt_vm(void)
  71. {
  72. int kq = kqueue();
  73. assert(kq != -1);
  74. struct kevent ke = {
  75. .filter = EVFILT_VM,
  76. .flags = EV_ADD|EV_ENABLE|EV_RECEIPT,
  77. .fflags = NOTE_VM_PRESSURE,
  78. };
  79. int r = kevent(kq, &ke, 1, &ke, 1, NULL);
  80. close(kq);
  81. return !(r > 0 && ke.flags & EV_ERROR && ke.data == ENOTSUP);
  82. }
  83. static void
  84. cleanup(void)
  85. {
  86. dispatch_source_cancel(vm_source);
  87. dispatch_release(vm_source);
  88. dispatch_release(vm_queue);
  89. int32_t pc = 0, i;
  90. for (i = 0; i < max_page_count; ++i) {
  91. if (pages[i]) {
  92. pc++;
  93. free(pages[i]);
  94. }
  95. }
  96. if (pc) {
  97. log_msg("Freed %ldMB\n", pg2mb(pc));
  98. }
  99. free(pages);
  100. test_stop();
  101. }
  102. int
  103. main(void)
  104. {
  105. dispatch_test_start("Dispatch VM Pressure test"); // rdar://problem/7000945
  106. if (!dispatch_test_check_evfilt_vm()) {
  107. test_skip("EVFILT_VM not supported");
  108. test_stop();
  109. return 0;
  110. }
  111. initial = time(NULL);
  112. uint64_t memsize;
  113. #ifdef __linux__
  114. memsize = sysconf(_SC_PAGESIZE) * sysconf(_SC_PHYS_PAGES);
  115. #else
  116. size_t s = sizeof(memsize);
  117. int rc = sysctlbyname("hw.memsize", &memsize, &s, NULL, 0);
  118. assert(rc == 0);
  119. #endif
  120. max_page_count = MIN(memsize, MAXMEM) / ALLOC_SIZE;
  121. pages = calloc(max_page_count, sizeof(char*));
  122. vm_queue = dispatch_queue_create("VM Pressure", NULL);
  123. vm_source = dispatch_source_create(DISPATCH_SOURCE_TYPE_VM, 0,
  124. DISPATCH_VM_PRESSURE, vm_queue);
  125. dispatch_source_set_event_handler(vm_source, ^{
  126. if (!page_count) {
  127. // Too much memory pressure already to start the test
  128. test_skip("Memory pressure at start of test");
  129. cleanup();
  130. }
  131. if (OSAtomicIncrement32Barrier(&handler_call_count) != NOTIFICATIONS) {
  132. log_msg("Ignoring vm pressure notification\n");
  133. interval = 1;
  134. return;
  135. }
  136. test_long("dispatch_source_get_data()",
  137. dispatch_source_get_data(vm_source), NOTE_VM_PRESSURE);
  138. int32_t i, pc = page_count + 1;
  139. for (i = 0; i < pc && pages[i]; ++i) {
  140. free(pages[i]);
  141. pages[i] = NULL;
  142. }
  143. log_msg("Freed %ldMB\n", pg2mb(i));
  144. });
  145. dispatch_resume(vm_source);
  146. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 1 * NSEC_PER_SEC),
  147. dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
  148. while (handler_call_count < NOTIFICATIONS &&
  149. page_count < max_page_count) {
  150. void *p = valloc(ALLOC_SIZE);
  151. if (!p) {
  152. break;
  153. }
  154. bzero(p, ALLOC_SIZE);
  155. pages[page_count] = p;
  156. if (!(OSAtomicIncrement32Barrier(&page_count) % interval)) {
  157. log_msg("Allocated %ldMB\n", pg2mb(page_count));
  158. usleep(200000);
  159. }
  160. }
  161. if (page_count % interval) {
  162. log_msg("Allocated %ldMB\n", pg2mb(page_count));
  163. }
  164. if (handler_call_count < NOTIFICATIONS) {
  165. // Cannot allocate enough memory for test (e.g. on 32 bit)
  166. test_skip("Cannot allocate enough memory for test");
  167. dispatch_async(vm_queue, ^{cleanup();});
  168. return;
  169. }
  170. dispatch_after(dispatch_time(DISPATCH_TIME_NOW, 2 * NSEC_PER_SEC),
  171. vm_queue, ^{
  172. test_long_greater_than_or_equal("VM Pressure fired",
  173. handler_call_count, NOTIFICATIONS);
  174. test_long_less_than("VM Pressure stopped firing",
  175. handler_call_count, 4);
  176. cleanup();
  177. });
  178. });
  179. dispatch_main();
  180. return 0;
  181. }
  182. #else //DISPATCH_SOURCE_TYPE_VM
  183. int
  184. main(void)
  185. {
  186. dispatch_test_start("Dispatch VM Pressure test"
  187. " - No DISPATCH_SOURCE_TYPE_VM");
  188. test_stop();
  189. return 0;
  190. }
  191. #endif //DISPATCH_SOURCE_TYPE_VM