jpe*_*lli 49 performance measurement context-switch cpu-cache memcache-stats
我正在用C编写一个小程序,我想测量它的性能.
我想知道它在处理器中运行了多少时间以及它有多少缓存命中+未命中.有关上下文切换和内存使用的信息也很好.
该程序执行时间不到一秒.
我喜欢/ proc/[pid]/stat的信息,但我不知道如何在程序死亡/被杀之后看到它.
有任何想法吗?
编辑:我认为Valgrind增加了很多开销.这就是为什么我想要一个简单的工具,比如/ proc/[pid]/stat,它总是在那里.
max*_*axy 86
使用perf:
perf stat ./yourapp
Run Code Online (Sandbox Code Playgroud)
有关详细信息,请参阅内核wiki perf教程.这使用了CPU的硬件性能计数器,因此开销非常小.
来自wiki的示例:
perf stat -B dd if=/dev/zero of=/dev/null count=1000000
Performance counter stats for 'dd if=/dev/zero of=/dev/null count=1000000':
5,099 cache-misses # 0.005 M/sec (scaled from 66.58%)
235,384 cache-references # 0.246 M/sec (scaled from 66.56%)
9,281,660 branch-misses # 3.858 % (scaled from 33.50%)
240,609,766 branches # 251.559 M/sec (scaled from 33.66%)
1,403,561,257 instructions # 0.679 IPC (scaled from 50.23%)
2,066,201,729 cycles # 2160.227 M/sec (scaled from 66.67%)
217 page-faults # 0.000 M/sec
3 CPU-migrations # 0.000 M/sec
83 context-switches # 0.000 M/sec
956.474238 task-clock-msecs # 0.999 CPUs
0.957617512 seconds time elapsed
Run Code Online (Sandbox Code Playgroud)
不需要在现代的debian系统(使用linux-base软件包)上手动加载内核模块,它应该可以正常工作.使用'perf record -a'/'perf report'组合,您还可以进行全系统分析.任何具有调试符号的应用程序或库都将在报告中显示详细信息.对于可视化,火焰图似乎运行良好.
最好的工具叫做valgrind.它能够进行内存分析,调用图构建等等.
sudo apt get install valgrind
valgrind ./yourapp
Run Code Online (Sandbox Code Playgroud)
但是,要获得程序执行的时间,可以使用time(8)linux实用程序.
time ./yourapp
Run Code Online (Sandbox Code Playgroud)
你也可以使用
/usr/bin/time -v YourProgram.exe
Run Code Online (Sandbox Code Playgroud)
它会显示所有这些信息:
/usr/bin/time -v ls
Command being timed: "ls"
User time (seconds): 0.00
System time (seconds): 0.00
Percent of CPU this job got: 60%
Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
Average shared text size (kbytes): 0
Average unshared data size (kbytes): 0
Average stack size (kbytes): 0
Average total size (kbytes): 0
Maximum resident set size (kbytes): 4080
Average resident set size (kbytes): 0
Major (requiring I/O) page faults: 0
Minor (reclaiming a frame) page faults: 314
Voluntary context switches: 1
Involuntary context switches: 1
Swaps: 0
File system inputs: 0
File system outputs: 0
Socket messages sent: 0
Socket messages received: 0
Signals delivered: 0
Page size (bytes): 4096
Exit status: 0
Run Code Online (Sandbox Code Playgroud)
您还可以使用-f标志格式化输出以满足您的需要.
请务必使用它的完整路径调用此程序,否则它将调用'time'命令,这不是您需要的...
希望这可以帮助!
Linuxperf_event_open系统调用config = PERF_COUNT_HW_INSTRUCTIONS
perf很可能是OP想要的,如/sf/answers/708002781/所示,但为了完整性,我将展示如果您控制源代码,如何从C程序内部执行此操作。
该方法可以更精确地测量程序内的特定感兴趣区域。它还可以获得每个不同缓存级别的单独缓存命中/未命中计数。该系统调用可能与 共享相同的后端perf。
此示例与计算 C 程序中执行的指令数的快速方法基本相同,但使用PERF_TYPE_HW_CACHE. 通过做:
man perf_event_open
Run Code Online (Sandbox Code Playgroud)
你可以看到,在这个例子中我们只计算:
PERF_COUNT_HW_CACHE_L1D)PERF_COUNT_HW_CACHE_OP_READ),而不是写入PERF_COUNT_HW_CACHE_RESULT_MISS),未命中perf_event_open.c
#define _GNU_SOURCE
#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>
#include <inttypes.h>
static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
int cpu, int group_fd, unsigned long flags)
{
int ret;
ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
group_fd, flags);
return ret;
}
int
main(int argc, char **argv)
{
struct perf_event_attr pe;
long long count;
int fd;
char *chars, c;
uint64_t n;
if (argc > 1) {
n = strtoll(argv[1], NULL, 0);
} else {
n = 10000;
}
chars = malloc(n * sizeof(char));
memset(&pe, 0, sizeof(struct perf_event_attr));
pe.type = PERF_TYPE_HW_CACHE;
pe.size = sizeof(struct perf_event_attr);
pe.config = PERF_COUNT_HW_CACHE_L1D |
PERF_COUNT_HW_CACHE_OP_READ << 8 |
PERF_COUNT_HW_CACHE_RESULT_MISS << 16;
pe.disabled = 1;
pe.exclude_kernel = 1;
// Don't count hypervisor events.
pe.exclude_hv = 1;
fd = perf_event_open(&pe, 0, -1, -1, 0);
if (fd == -1) {
fprintf(stderr, "Error opening leader %llx\n", pe.config);
exit(EXIT_FAILURE);
}
/* Write the memory to ensure misses later. */
for (size_t i = 0; i < n; i++) {
chars[i] = 1;
}
ioctl(fd, PERF_EVENT_IOC_RESET, 0);
ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);
/* Read from memory. */
for (size_t i = 0; i < n; i++) {
c = chars[i];
}
ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
read(fd, &count, sizeof(long long));
printf("%lld\n", count);
close(fd);
free(chars);
}
Run Code Online (Sandbox Code Playgroud)
这样,我得到的结果线性增加,如下所示:
./main.out 100000
# 1565
./main.out 1000000
# 15632
./main.out 10000000
# 156641
Run Code Online (Sandbox Code Playgroud)
由此我们可以估计缓存行大小为:100000/1565 ~ 63.9,它几乎与我的计算机上的 64 的精确值完全匹配,getconf LEVEL1_DCACHE_LINESIZE所以我猜它是有效的。
在 Ubuntu 20.04 amd64、GCC 9.3.0、Linux 内核 5.4.0、Intel Core i7-7820HQ CPU 上进行测试。