OLD | NEW |
(Empty) | |
| 1 /* |
| 2 american fuzzy lop - free CPU gizmo |
| 3 ----------------------------------- |
| 4 |
| 5 Written and maintained by Michal Zalewski <lcamtuf@google.com> |
| 6 |
| 7 Copyright 2015, 2016 Google Inc. All rights reserved. |
| 8 |
| 9 Licensed under the Apache License, Version 2.0 (the "License"); |
| 10 you may not use this file except in compliance with the License. |
| 11 You may obtain a copy of the License at: |
| 12 |
| 13 http://www.apache.org/licenses/LICENSE-2.0 |
| 14 |
| 15 This tool provides a fairly accurate measurement of CPU preemption rate. |
| 16 It is meant to complement the quick-and-dirty load average widget shown |
| 17 in the afl-fuzz UI. See docs/parallel_fuzzing.txt for more info. |
| 18 |
| 19 For some work loads, the tool may actually suggest running more instances |
| 20 than you have CPU cores. This can happen if the tested program is spending |
| 21 a portion of its run time waiting for I/O, rather than being 100% |
| 22 CPU-bound. |
| 23 |
| 24 The idea for the getrusage()-based approach comes from Jakub Wilk. |
| 25 |
| 26 */ |
| 27 |
| 28 #define AFL_MAIN |
| 29 #define _GNU_SOURCE |
| 30 |
| 31 #include <stdio.h> |
| 32 #include <stdlib.h> |
| 33 #include <unistd.h> |
| 34 #include <string.h> |
| 35 #include <sched.h> |
| 36 |
| 37 #include <sys/time.h> |
| 38 #include <sys/times.h> |
| 39 #include <sys/resource.h> |
| 40 #include <sys/wait.h> |
| 41 |
| 42 #include "types.h" |
| 43 #include "debug.h" |
| 44 |
| 45 #ifdef __linux__ |
| 46 # define HAVE_AFFINITY 1 |
| 47 #endif /* __linux__ */ |
| 48 |
| 49 |
| 50 /* Get unix time in microseconds. */ |
| 51 |
| 52 static u64 get_cur_time_us(void) { |
| 53 |
| 54 struct timeval tv; |
| 55 struct timezone tz; |
| 56 |
| 57 gettimeofday(&tv, &tz); |
| 58 |
| 59 return (tv.tv_sec * 1000000ULL) + tv.tv_usec; |
| 60 |
| 61 } |
| 62 |
| 63 |
| 64 /* Get CPU usage in microseconds. */ |
| 65 |
| 66 static u64 get_cpu_usage_us(void) { |
| 67 |
| 68 struct rusage u; |
| 69 |
| 70 getrusage(RUSAGE_SELF, &u); |
| 71 |
| 72 return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec + |
| 73 (u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec; |
| 74 |
| 75 } |
| 76 |
| 77 |
| 78 /* Measure preemption rate. */ |
| 79 |
| 80 static u32 measure_preemption(u32 target_ms) { |
| 81 |
| 82 static volatile u32 v1, v2; |
| 83 |
| 84 u64 st_t, en_t, st_c, en_c, real_delta, slice_delta; |
| 85 s32 loop_repeats = 0; |
| 86 |
| 87 st_t = get_cur_time_us(); |
| 88 st_c = get_cpu_usage_us(); |
| 89 |
| 90 repeat_loop: |
| 91 |
| 92 v1 = CTEST_BUSY_CYCLES; |
| 93 |
| 94 while (v1--) v2++; |
| 95 sched_yield(); |
| 96 |
| 97 en_t = get_cur_time_us(); |
| 98 |
| 99 if (en_t - st_t < target_ms * 1000) { |
| 100 loop_repeats++; |
| 101 goto repeat_loop; |
| 102 } |
| 103 |
| 104 /* Let's see what percentage of this time we actually had a chance to |
| 105 run, and how much time was spent in the penalty box. */ |
| 106 |
| 107 en_c = get_cpu_usage_us(); |
| 108 |
| 109 real_delta = (en_t - st_t) / 1000; |
| 110 slice_delta = (en_c - st_c) / 1000; |
| 111 |
| 112 return real_delta * 100 / slice_delta; |
| 113 |
| 114 } |
| 115 |
| 116 |
| 117 /* Do the benchmark thing. */ |
| 118 |
| 119 int main(int argc, char** argv) { |
| 120 |
| 121 #ifdef HAVE_AFFINITY |
| 122 |
| 123 u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), |
| 124 idle_cpus = 0, maybe_cpus = 0, i; |
| 125 |
| 126 SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); |
| 127 |
| 128 ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...", |
| 129 ((double)CTEST_CORE_TRG_MS) / 1000); |
| 130 |
| 131 for (i = 0; i < cpu_cnt; i++) { |
| 132 |
| 133 s32 fr = fork(); |
| 134 |
| 135 if (fr < 0) PFATAL("fork failed"); |
| 136 |
| 137 if (!fr) { |
| 138 |
| 139 cpu_set_t c; |
| 140 u32 util_perc; |
| 141 |
| 142 CPU_ZERO(&c); |
| 143 CPU_SET(i, &c); |
| 144 |
| 145 if (sched_setaffinity(0, sizeof(c), &c)) |
| 146 PFATAL("sched_setaffinity failed"); |
| 147 |
| 148 util_perc = measure_preemption(CTEST_CORE_TRG_MS); |
| 149 |
| 150 if (util_perc < 110) { |
| 151 |
| 152 SAYF(" Core #%u: " cLGN "AVAILABLE\n" cRST, i); |
| 153 exit(0); |
| 154 |
| 155 } else if (util_perc < 250) { |
| 156 |
| 157 SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc); |
| 158 exit(1); |
| 159 |
| 160 } |
| 161 |
| 162 SAYF(" Core #%u: " cLRD "OVERBOOKED " cRST "(%u%%)\n" cRST, i, |
| 163 util_perc); |
| 164 exit(2); |
| 165 |
| 166 } |
| 167 |
| 168 } |
| 169 |
| 170 for (i = 0; i < cpu_cnt; i++) { |
| 171 |
| 172 int ret; |
| 173 if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed"); |
| 174 |
| 175 if (WEXITSTATUS(ret) == 0) idle_cpus++; |
| 176 if (WEXITSTATUS(ret) <= 1) maybe_cpus++; |
| 177 |
| 178 } |
| 179 |
| 180 SAYF(cGRA "\n>>> "); |
| 181 |
| 182 if (idle_cpus) { |
| 183 |
| 184 if (maybe_cpus == idle_cpus) { |
| 185 |
| 186 SAYF(cLGN "PASS: " cRST "You can run more processes on %u core%s.", |
| 187 idle_cpus, idle_cpus > 1 ? "s" : ""); |
| 188 |
| 189 } else { |
| 190 |
| 191 SAYF(cLGN "PASS: " cRST "You can run more processes on %u to %u core%s.", |
| 192 idle_cpus, maybe_cpus, maybe_cpus > 1 ? "s" : ""); |
| 193 |
| 194 } |
| 195 |
| 196 SAYF(cGRA " <<<" cRST "\n\n"); |
| 197 return 0; |
| 198 |
| 199 } |
| 200 |
| 201 if (maybe_cpus) { |
| 202 |
| 203 SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.", |
| 204 maybe_cpus, maybe_cpus > 1 ? "s" : ""); |
| 205 SAYF(cGRA " <<<" cRST "\n\n"); |
| 206 return 1; |
| 207 |
| 208 } |
| 209 |
| 210 SAYF(cLRD "FAIL: " cRST "All cores are overbooked."); |
| 211 SAYF(cGRA " <<<" cRST "\n\n"); |
| 212 return 2; |
| 213 |
| 214 #else |
| 215 |
| 216 u32 util_perc; |
| 217 |
| 218 SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n"); |
| 219 |
| 220 /* Run a busy loop for CTEST_TARGET_MS. */ |
| 221 |
| 222 ACTF("Measuring gross preemption rate (this will take %0.02f sec)...", |
| 223 ((double)CTEST_TARGET_MS) / 1000); |
| 224 |
| 225 util_perc = measure_preemption(CTEST_TARGET_MS); |
| 226 |
| 227 /* Deliver the final verdict. */ |
| 228 |
| 229 SAYF(cGRA "\n>>> "); |
| 230 |
| 231 if (util_perc < 105) { |
| 232 |
| 233 SAYF(cLGN "PASS: " cRST "You can probably run additional processes."); |
| 234 |
| 235 } else if (util_perc < 130) { |
| 236 |
| 237 SAYF(cYEL "CAUTION: " cRST "Your CPU may be somewhat overbooked (%u%%).", |
| 238 util_perc); |
| 239 |
| 240 } else { |
| 241 |
| 242 SAYF(cLRD "FAIL: " cRST "Your CPU is overbooked (%u%%).", util_perc); |
| 243 |
| 244 } |
| 245 |
| 246 SAYF(cGRA " <<<" cRST "\n\n"); |
| 247 |
| 248 return (util_perc > 105) + (util_perc > 130); |
| 249 |
| 250 #endif /* ^HAVE_AFFINITY */ |
| 251 |
| 252 } |
OLD | NEW |