dongloong 3 months ago
parent fc527fee69
commit 2fc8b00adc

File diff suppressed because it is too large Load Diff

@ -1,35 +1,29 @@
/*
Copyright 2015 Google LLC All rights reserved.
/*
2015 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at:
Apache License, 2.0
使
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
/*
american fuzzy lop - free CPU gizmo
/*
- CPU
-----------------------------------
Written and maintained by Michal Zalewski <lcamtuf@google.com>
Michal Zalewski <lcamtuf@google.com>
This tool provides a fairly accurate measurement of CPU preemption rate.
It is meant to complement the quick-and-dirty load average widget shown
in the afl-fuzz UI. See docs/parallel_fuzzing.txt for more info.
CPU
afl-fuzz UIdocs/parallel_fuzzing.txt
For some work loads, the tool may actually suggest running more instances
than you have CPU cores. This can happen if the tested program is spending
a portion of its run time waiting for I/O, rather than being 100%
CPU-bound.
CPUI/O100% CPU
The idea for the getrusage()-based approach comes from Jakub Wilk.
getrusage()Jakub Wilk
*/
#define AFL_MAIN
@ -51,161 +45,191 @@
#include "debug.h"
#ifdef __linux__
# define HAVE_AFFINITY 1 // 如果是Linux系统支持CPU亲和性
# define HAVE_AFFINITY 1
#endif /* __linux__ */
/* 获取当前时间,单位:微秒 */
static u64 get_cur_time_us(void) {
/*
Unix
*/
static u64 get_cur_time_us(void) {
// 定义一个timeval结构体变量tv用于存储当前时间
struct timeval tv;
// 定义一个timezone结构体变量tz用于存储时区信息
struct timezone tz;
gettimeofday(&tv, &tz); // 获取当前的系统时间
// 使用gettimeofday函数获取当前时间并存储到tv和tz中
gettimeofday(&tv, &tz);
return (tv.tv_sec * 1000000ULL) + tv.tv_usec; // 将秒转换为微秒并返回
// 将秒转换为微秒,并加上微秒部分,返回当前时间的微秒值
return (tv.tv_sec * 1000000ULL) + tv.tv_usec;
}
/*
CPU使
*/
/* 获取当前进程的CPU使用时间单位微秒 */
static u64 get_cpu_usage_us(void) {
// 定义一个rusage结构体变量u用于存储资源使用情况
struct rusage u;
getrusage(RUSAGE_SELF, &u); // 获取当前进程的资源使用情况
// 使用getrusage函数获取当前进程的资源使用情况并存储到u中
getrusage(RUSAGE_SELF, &u);
return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec + // 用户态CPU时间
(u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec; // 内核态CPU时间
// 计算用户态和核心态的总使用时间(微秒),并返回
return (u.ru_utime.tv_sec * 1000000ULL) + u.ru_utime.tv_usec +
(u.ru_stime.tv_sec * 1000000ULL) + u.ru_stime.tv_usec;
}
/* 测量预占率target_ms为目标时间单位毫秒 */
static u32 measure_preemption(u32 target_ms) {
/*
*/
static u32 measure_preemption(u32 target_ms) {
// 定义两个易失性变量,用于循环测试
static volatile u32 v1, v2;
u64 st_t, en_t, st_c, en_c, real, slice;
// 定义变量用于存储开始和结束的时间微秒以及CPU使用时间
u64 st_t, en_t, st_c, en_c, real_delta, slice_delta;
// 定义循环重复次数
s32 loop_repeats = 0;
st_t = get_cur_time_us(); // 获取开始时间
st_c = get_cpu_usage_us(); // 获取开始时的CPU使用时间
// 获取当前时间(微秒)
st_t = get_cur_time_us();
// 获取当前CPU使用时间微秒
st_c = get_cpu_usage_us();
repeat_loop:
// 设置v1为一个忙循环的计数
v1 = CTEST_BUSY_CYCLES;
v1 = CTEST_BUSY_CYCLES; // 模拟的忙循环次数
// 执行忙循环同时v2自增
while (v1--) v2++;
// 调用sched_yield()让出CPU
sched_yield();
while (v1--) v2++; // 执行忙循环
sched_yield(); // 强制当前进程让出CPU
// 再次获取当前时间(微秒)
en_t = get_cur_time_us();
en_t = get_cur_time_us(); // 获取结束时间
// 如果目标时间未达到,则继续重复循环
// 如果当前时间与开始时间的差小于目标时间(毫秒转换为微秒),则增加循环次数并继续循环
if (en_t - st_t < target_ms * 1000) {
loop_repeats++;
goto repeat_loop;
}
en_c = get_cpu_usage_us(); // 获取结束时的CPU使用时间
/* 让我们看看这段时间里我们实际上有多少百分比的机会运行,
*/
// 获取当前CPU使用时间微秒
en_c = get_cpu_usage_us();
// 计算实际经过时间和CPU时间的差值单位毫秒
real = (en_t - st_t) / 1000;
slice = (en_c - st_c) / 1000;
// 计算实际时间差毫秒和CPU使用时间差毫秒
real_delta = (en_t - st_t) / 1000;
slice_delta = (en_c - st_c) / 1000;
// 返回CPU预占率单位百分比
return real * 100 / slice;
// 返回实际时间差占CPU使用时间差的百分比即抢占率
return real_delta * 100 / slice_delta;
}
/*
*/
/* 主程序 */
int main(int argc, char** argv) {
#ifdef HAVE_AFFINITY // 如果支持CPU亲和性
#ifdef HAVE_AFFINITY
u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN), // 获取系统中CPU核心数
// 获取在线的CPU核心数
u32 cpu_cnt = sysconf(_SC_NPROCESSORS_ONLN),
// 初始化空闲CPU和可能可用CPU的计数器
idle_cpus = 0, maybe_cpus = 0, i;
// 打印欢迎信息和版本号
SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
// 打印测量每个核心抢占率所需的时间
ACTF("Measuring per-core preemption rate (this will take %0.02f sec)...",
((double)CTEST_CORE_TRG_MS) / 1000); // 输出提示信息,显示测量时间
((double)CTEST_CORE_TRG_MS) / 1000);
for (i = 0; i < cpu_cnt; i++) { // 遍历每个CPU核心
// 遍历每个CPU核心
for (i = 0; i < cpu_cnt; i++) {
s32 fr = fork(); // 创建子进程
// 创建子进程
s32 fr = fork();
// 如果fork失败则打印错误信息并退出
if (fr < 0) PFATAL("fork failed");
if (!fr) { // 子进程执行以下代码
// 如果是子进程,则执行以下操作
if (!fr) {
// 定义CPU集合
cpu_set_t c;
// 定义CPU使用率百分比
u32 util_perc;
CPU_ZERO(&c); // 清空CPU集合
CPU_SET(i, &c); // 将当前核心i加入CPU集合
// 初始化CPU集合
CPU_ZERO(&c);
// 将当前核心加入CPU集合
CPU_SET(i, &c);
if (sched_setaffinity(0, sizeof(c), &c)) // 设置当前进程的CPU亲和性
// 如果设置CPU亲和性失败则打印错误信息并退出
if (sched_setaffinity(0, sizeof(c), &c))
PFATAL("sched_setaffinity failed for cpu %d", i);
util_perc = measure_preemption(CTEST_CORE_TRG_MS); // 测量当前核心的预占率
// 测量抢占率
util_perc = measure_preemption(CTEST_CORE_TRG_MS);
// 根据预占率判断当前核心的负载状态
// 如果使用率低于110%,则标记为核心可用,并退出
if (util_perc < 110) {
SAYF(" Core #%u: " cLGN "AVAILABLE " cRST "(%u%%)\n", i, util_perc);
exit(0); // 退出子进程
SAYF(" Core #%u: " cLGN "AVAILABLE" cRST "(%u%%)\n", i, util_perc);
exit(0);
} else if (util_perc < 250) {
SAYF(" Core #%u: " cYEL "CAUTION " cRST "(%u%%)\n", i, util_perc);
exit(1); // 退出子进程
// 如果使用率低于250%,则标记为核心需要谨慎,并退出
SAYF(" Core #%u: " cYEL "CAUTION" cRST "(%u%%)\n", i, util_perc);
exit(1);
}
SAYF(" Core #%u: " cLRD "OVERBOOKED " cRST "(%u%%)\n" cRST, i, util_perc);
exit(2); // 退出子进程
// 如果使用率高于250%,则标记为核心过载,并退出
SAYF(" Core #%u: " cLRD "OVERBOOKED" cRST "(%u%%)\n" cRST, i,
util_perc);
exit(2);
}
}
// 等待所有子进程完成
// 等待子进程结束,并统计空闲和可能可用的核心数
for (i = 0; i < cpu_cnt; i++) {
int ret;
if (waitpid(-1, &ret, 0) < 0) PFATAL("waitpid failed");
if (WEXITSTATUS(ret) == 0) idle_cpus++; // 统计空闲的CPU核心
if (WEXITSTATUS(ret) <= 1) maybe_cpus++; // 统计可能可用的CPU核心
if (WEXITSTATUS(ret) == 0) idle_cpus++;
if (WEXITSTATUS(ret) <= 1) maybe_cpus++;
}
// 根据空闲和可能可用的核心数打印结果
SAYF(cGRA "\n>>> ");
if (idle_cpus) { // 如果有空闲的CPU核心
if (maybe_c
if (idle_cpus) {
if (maybe_cpus == idle_cpus) {
SAYF(cLGN "PASS: " cRST "You can run more processes on %u core%s.",
idle_cpus, idle_cpus > 1 ? "s" : "");
} else {
SAYF(cLGN "PASS: " cRST "You can run more processes on %u to %u core%s.",
idle_cpus, maybe_cpus, maybe_cpus > 1 ? "s" : "");
}
SAYF(cGRA " <<<" cRST "\n\n");
return 0;
}
if (maybe_cpus) {
SAYF(cYEL "CAUTION: " cRST "You may still have %u core%s available.",
maybe_cpus, maybe_cpus > 1 ? "s" : "");
SAYF(cGRA " <<<" cRST "\n\n");
return 1;
}
SAYF(cLRD "FAIL: " cRST "All cores are overbooked.");
@ -214,38 +238,35 @@ int main(int argc, char** argv) {
#else
// 如果没有CPU亲和性支持则执行总体抢占率的测量
u32 util_perc;
SAYF(cCYA "afl-gotcpu " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
/* Run a busy loop for CTEST_TARGET_MS. */
/* 运行一个忙循环持续CTEST_TARGET_MS毫秒。 */
ACTF("Measuring gross preemption rate (this will take %0.02f sec)...",
((double)CTEST_TARGET_MS) / 1000);
// 测量抢占率
util_perc = measure_preemption(CTEST_TARGET_MS);
/* Deliver the final verdict. */
/* 输出最终结果。 */
SAYF(cGRA "\n>>> ");
if (util_perc < 105) {
SAYF(cLGN "PASS: " cRST "You can probably run additional processes.");
} else if (util_perc < 130) {
SAYF(cYEL "CAUTION: " cRST "Your CPU may be somewhat overbooked (%u%%).",
util_perc);
} else {
SAYF(cLRD "FAIL: " cRST "Your CPU is overbooked (%u%%).", util_perc);
}
SAYF(cGRA " <<<" cRST "\n\n");
// 返回结果代码
return (util_perc > 105) + (util_perc > 130);
#endif /* ^HAVE_AFFINITY */

Loading…
Cancel
Save