afl-gotcpu.c 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. /*
  2. american fuzzy lop - free CPU gizmo
  3. -----------------------------------
  4. Written and maintained by Michal Zalewski <lcamtuf@google.com>
  5. Copyright 2015, 2016 Google Inc. All rights reserved.
  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. http://www.apache.org/licenses/LICENSE-2.0
  10. This tool provides a fairly accurate measurement of CPU preemption rate.
  11. It is meant to complement the quick-and-dirty load average widget shown
  12. in the afl-fuzz UI. See docs/parallel_fuzzing.txt for more info.
  13. For some work loads, the tool may actually suggest running more instances
  14. than you have CPU cores. This can happen if the tested program is spending
  15. a portion of its run time waiting for I/O, rather than being 100%
  16. CPU-bound.
  17. The idea for the getrusage()-based approach comes from Jakub Wilk.
  18. */
  19. #define AFL_MAIN
  20. #define _GNU_SOURCE
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <unistd.h>
  24. #include <string.h>
  25. #include <sched.h>
  26. #include <sys/time.h>
  27. #include <sys/times.h>
  28. #include <sys/resource.h>
  29. #include <sys/wait.h>
  30. #include "types.h"
  31. #include "debug.h"
  32. #ifdef __linux__
  33. # define HAVE_AFFINITY 1
  34. #endif /* __linux__ */
  35. /* Get unix time in microseconds. */
  36. static u64 get_cur_time_us(void) {
  37. struct timeval tv;
  38. struct timezone tz;
  39. gettimeofday(&tv, &tz);
  40. return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
  41. }
  42. /* Get CPU usage in microseconds. */
  43. static u64 get_cpu_usage_us(void) {
  44. struct rusage u;
  45. getrusage(RUSAGE_SELF, &u);
  46. return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec +
  47. (u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec;
  48. }
  49. /* Measure preemption rate. */
  50. static u32 measure_preemption(u32 target_ms) {
  51. static volatile u32 v1, v2;
  52. u64 st_t, en_t, st_c, en_c, real_delta, slice_delta;
  53. s32 loop_repeats = 0;
  54. st_t = get_cur_time_us();
  55. st_c = get_cpu_usage_us();
  56. repeat_loop:
  57. v1 = CTEST_BUSY_CYCLES;
  58. while (v1--) v2++;
  59. sched_yield();
  60. en_t = get_cur_time_us();
  61. if (en_t - st_t < target_ms * 1000) {
  62. loop_repeats++;
  63. goto repeat_loop;
  64. }
  65. /* Let's see what percentage of this time we actually had a chance to
  66. run, and how much time was spent in the penalty box. */
  67. en_c = get_cpu_usage_us();
  68. real_delta = (en_t - st_t) / 1000;
  69. slice_delta = (en_c - st_c) / 1000;
  70. return real_delta * 100 / slice_delta;
  71. }
  72. /* Do the benchmark thing. */
  73. int main(int argc, char** argv) {
  74. #ifdef HAVE_AFFINITY
  75. u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN),
  76. idle_cpus = 0, maybe_cpus = 0, i;
  77. SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
  78. ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...",
  79. ((double)CTEST_CORE_TRG_MS) / 1000);
  80. for (i = 0; i < cpu_cnt; i++) {
  81. s32 fr = fork();
  82. if (fr < 0) PFATAL("fork failed");
  83. if (!fr) {
  84. cpu_set_t c;
  85. u32 util_perc;
  86. CPU_ZERO(&c);
  87. CPU_SET(i, &c);
  88. if (sched_setaffinity(0, sizeof(c), &c))
  89. PFATAL("sched_setaffinity failed");
  90. util_perc = measure_preemption(CTEST_CORE_TRG_MS);
  91. if (util_perc < 110) {
  92. SAYF(" Core #%u: " cLGN "AVAILABLE\n" cRST, i);
  93. exit(0);
  94. } else if (util_perc < 250) {
  95. SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc);
  96. exit(1);
  97. }
  98. SAYF(" Core #%u: " cLRD "OVERBOOKED " cRST "(%u%%)\n" cRST, i,
  99. util_perc);
  100. exit(2);
  101. }
  102. }
  103. for (i = 0; i < cpu_cnt; i++) {
  104. int ret;
  105. if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed");
  106. if (WEXITSTATUS(ret) == 0) idle_cpus++;
  107. if (WEXITSTATUS(ret) <= 1) maybe_cpus++;
  108. }
  109. SAYF(cGRA "\n>>> ");
  110. if (idle_cpus) {
  111. if (maybe_cpus == idle_cpus) {
  112. SAYF(cLGN "PASS: " cRST "You can run more processes on %u core%s.",
  113. idle_cpus, idle_cpus > 1 ? "s" : "");
  114. } else {
  115. SAYF(cLGN "PASS: " cRST "You can run more processes on %u to %u core%s.",
  116. idle_cpus, maybe_cpus, maybe_cpus > 1 ? "s" : "");
  117. }
  118. SAYF(cGRA " <<<" cRST "\n\n");
  119. return 0;
  120. }
  121. if (maybe_cpus) {
  122. SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.",
  123. maybe_cpus, maybe_cpus > 1 ? "s" : "");
  124. SAYF(cGRA " <<<" cRST "\n\n");
  125. return 1;
  126. }
  127. SAYF(cLRD "FAIL: " cRST "All cores are overbooked.");
  128. SAYF(cGRA " <<<" cRST "\n\n");
  129. return 2;
  130. #else
  131. u32 util_perc;
  132. SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
  133. /* Run a busy loop for CTEST_TARGET_MS. */
  134. ACTF("Measuring gross preemption rate (this will take %0.02f sec)...",
  135. ((double)CTEST_TARGET_MS) / 1000);
  136. util_perc = measure_preemption(CTEST_TARGET_MS);
  137. /* Deliver the final verdict. */
  138. SAYF(cGRA "\n>>> ");
  139. if (util_perc < 105) {
  140. SAYF(cLGN "PASS: " cRST "You can probably run additional processes.");
  141. } else if (util_perc < 130) {
  142. SAYF(cYEL "CAUTION: " cRST "Your CPU may be somewhat overbooked (%u%%).",
  143. util_perc);
  144. } else {
  145. SAYF(cLRD "FAIL: " cRST "Your CPU is overbooked (%u%%).", util_perc);
  146. }
  147. SAYF(cGRA " <<<" cRST "\n\n");
  148. return (util_perc > 105) + (util_perc > 130);
  149. #endif /* ^HAVE_AFFINITY */
  150. }