Chi*_*kus 3 c performancecounter cpu-cycles perf
我尝试通过简短的 C 代码片段来计算单个进程的 CPU 周期。MWE 是cpucycles.c。
\n\ncpucycles.c(主要基于手册页示例)
\n\n#include <stdlib.h>\n#include <stdio.h>\n#include <unistd.h>\n#include <string.h>\n#include <sys/ioctl.h>\n#include <linux/perf_event.h>\n#include <asm/unistd.h>\n\nstatic long\nperf_event_open(struct perf_event_attr *hw_event, pid_t pid,\n int cpu, int group_fd, unsigned long flags)\n{\n int ret;\n ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,\n group_fd, flags);\n return ret;\n}\n\nlong long\ncpu_cycles(pid_t pid, unsigned int microseconds)\n{\n struct perf_event_attr pe;\n long long count;\n int fd;\n\n memset(&pe, 0, sizeof(struct perf_event_attr));\n pe.type = PERF_TYPE_HARDWARE;\n pe.size = sizeof(struct perf_event_attr);\n pe.config = PERF_COUNT_HW_CPU_CYCLES;\n pe.disabled = 1;\n pe.exclude_kernel = 1;\n pe.exclude_hv = 1;\n\n fd = perf_event_open(&pe, pid, -1, -1, 0);\n if (fd == -1) {\n return -1;\n }\n\n ioctl(fd, PERF_EVENT_IOC_RESET, 0);\n ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);\n usleep(microseconds);\n ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);\n read(fd, &count, sizeof(long long));\n\n close(fd);\n return count;\n}\n\nint main(int argc, char **argv)\n{\n printf("CPU cycles: %lld\\n", cpu_cycles(atoi(argv[1]), atoi(argv[2])));\n return 0;\n}\nRun Code Online (Sandbox Code Playgroud)\n\n接下来,我编译它,设置 perf_event 访问权限,启动一个完全使用 CPU 的进程,并通过perf我的cpucycles.
$ gcc -o cpucycles cpucycles.c\n$ echo 1 | sudo tee /proc/sys/kernel/perf_event_paranoid\n$ cat /dev/urandom > /dev/null &\n[1] 3214\n$ perf stat -e cycles -p 3214 -x, sleep 1\n3072358388,,cycles,1000577415,100,00,,,,\n$ ./cpucycles 3214 1000000\nCPU cycles: 287953\nRun Code Online (Sandbox Code Playgroud)\n\n显然,只有 \xc2\xb4perf\xc2\xb4 中的 \xc2\xb43072358388\xc2\xb4 CPU 周期对于我的 3 GHz CPU 是正确的。为什么我的 \xc2\xb4cpucycles\xc2\xb4 返回如此可笑的小值?
\n设置 时,您在分析中排除了内核pe.exclude_kernel = 1;。
我刚刚验证了,通过将该标志设置为 0,我会得到大数字,将其设置为 1 我会得到小数字。
cat /dev/urandom > /dev/null几乎所有的CPU时间都花在内核中。用户态位将是对缓冲区的读取和从该缓冲区的写入,而在这种情况下,所有繁重的工作都由内核完成。