出于好奇,我编写了几个不同版本的矩阵乘法,并对其运行cachegrind.在下面的结果中,我想知道哪些部分是L1,L2,L3未命中和引用以及它们的真正含义是什么?下面是我的矩阵乘法代码,万一有人需要.
#define SLOWEST
==6933== Cachegrind, a cache and branch-prediction profiler
==6933== Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote et al.
==6933== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info
==6933== Command: ./a.out 500
==6933==
--6933-- warning: L3 cache found, using its data for the LL simulation.
--6933-- warning: pretending that LL cache has associativity 24 instead of actual 16
Multiplied matrix A and B in 60.7487 seconds.
==6933==
==6933== I refs: 6,039,791,314
==6933== I1 misses: 1,611 …Run Code Online (Sandbox Code Playgroud) 最近Herb Sutter就"现代C++:你需要知道什么"发表了精彩演讲.本次演讲的主题是效率以及数据位置和访问内存的重要性.他还解释了内存(数组/向量)的线性访问如何被CPU所喜爱.他从另一个经典参考"Bob Nystrom的游戏表演"中就此主题举了一个例子.
阅读这些文章后,我得知有两种类型的缓存会影响程序性能:
Cachegrind工具还测量我们程序的缓存类型检测信息.许多文章/博客已经解释了第一点,以及如何实现良好的数据缓存效率(数据位置).
但是我没有获得关于主题指令缓存的更多信息以及我们应该在我们的程序中采取什么样的方法来实现更好的性能?根据我的理解,我们(程序员)对哪条指令或执行的命令没有多少控制权.
如果小型c ++程序解释了这个计数器(.ie指令缓存)将如何随着我们的编写程序风格而变化,那将是非常好的.程序员应遵循哪些最佳实践来达到更好的性能?
我的意思是,如果我们的程序(矢量与列表)以类似的方式解释第二点,我们可以理解数据缓存主题.这个问题的主要目的是尽可能地理解这个主题.
我正在使用Cachegrind,Callgrind和Gem5进行一些实验.我注意到一些访问被计为cachegrind的读取,如callgrind的写入以及gem5的读取和写入.
我们来看一个非常简单的例子:
int main() {
int i, l;
for (i = 0; i < 1000; i++) {
l++;
l++;
l++;
l++;
l++;
l++;
l++;
l++;
l++;
l++;
... (100 times)
}
}
Run Code Online (Sandbox Code Playgroud)
我编译:
gcc ex.c --static -o ex
所以基本上,根据asm文件,addl $1, -8(%rbp)执行100,000次.由于它既是读取也是写入,我期待100k读取和100k写入.但是,cachegrind只将它们计为read,而callgrind只计为write.
% valgrind --tool=cachegrind --I1=512,8,64 --D1=512,8,64
--L2=16384,8,64 ./ex
==15356== Cachegrind, a cache and branch-prediction profiler
==15356== Copyright (C) 2002-2012, and GNU GPL'd, by Nicholas Nethercote et al.
==15356== Using Valgrind-3.8.1 and LibVEX; rerun with -h for copyright info …Run Code Online (Sandbox Code Playgroud) 当我尝试使用wincachegrind并获取cachegrind文件时,它返回
找不到通话目标.
cachegrind.out行号:68
谁知道怎么解决这个问题?
更新,这是错误的屏幕截图:
我目前正试图在我的一个C程序中理解一些非常奇怪的行为.显然,在它结尾处添加或删除看似无关紧要的行会大大影响程序其余部分的性能.
我的程序看起来有点像这样:
int large_buffer[10000];
void compute(FILE * input) {
for(int i=0; i<100; i++) {
do_lots_of_stuff();
printf(".");
fflush(stdout);
}
}
int main() {
FILE *input = fopen("input.txt", "r");
compute(input);
fclose(input); // <--- everything gets 2x slower if I comment this out (!)
return 0;
}
Run Code Online (Sandbox Code Playgroud)
理论上,fclose(input)主函数末尾的那一行应该无关紧要,因为OS无论如何都应该在程序结束时自动关闭文件.但是我观察到当我将fclose语句包含在内时,我的程序需要2.5秒才能运行.差异2倍!这不是由于程序开始或结束时的延迟:在.使用fclose语句的版本中打印输出的速度明显更快.
我怀疑这可能与某些内存对齐或缓存未命中问题有关.如果我用另一个函数(如ftell)替换fclose,它也需要5s来运行,如果我减小large_bufferto <= 8000元素的大小,那么它总是在2.5秒内运行,无论fclose语句是否存在.
但我真的希望能够100%确定这种奇怪行为背后的罪魁祸首.是否有可能在某种分析器或其他工具下运行我的程序,这些工具会给我这些信息?到目前为止,我尝试运行两个版本,valgrind --tool=cachegrind但它报告了我的程序的两个版本的相同数量的缓存未命中(0%).
编辑1:运行我的程序的两个版本后,我perf stat -d -d -d得到以下结果:
Performance counter stats for './no-fclose examples/bench.o':
5625.535086 task-clock (msec) # 1.000 CPUs utilized
38 context-switches …Run Code Online (Sandbox Code Playgroud) 受SQLite的启发,我正在寻找使用valgrind的"cachegrind"工具来进行可重现的性能基准测试.它输出的数字比我发现的任何其他计时方法稳定得多,但它们仍然不具有确定性.举个例子,这是一个简单的C程序:
int main() {
volatile int x;
while (x < 1000000) {
x++;
}
}
Run Code Online (Sandbox Code Playgroud)
如果我编译它并在cachegrind下运行它,我得到以下结果:
$ gcc -O2 x.c -o x
$ valgrind --tool=cachegrind ./x
==11949== Cachegrind, a cache and branch-prediction profiler
==11949== Copyright (C) 2002-2015, and GNU GPL'd, by Nicholas Nethercote et al.
==11949== Using Valgrind-3.11.0.SVN and LibVEX; rerun with -h for copyright info
==11949== Command: ./x
==11949==
--11949-- warning: L3 cache found, using its data for the LL simulation.
==11949==
==11949== I refs: 11,158,333
==11949== I1 …Run Code Online (Sandbox Code Playgroud) 我打算使用缓存友好的方法将2个矩阵相乘(这将导致更少的未命中)
我发现这可以通过缓存友好的转置函数来完成.
但我无法找到这个算法.我可以知道如何实现这一目标吗?
我目前正在学习Linux下的各种分析和性能实用程序,特别是valgrind/cachegrind.
我有以下玩具程序:
#include <iostream>
#include <vector>
int
main() {
const unsigned int COUNT = 1000000;
std::vector<double> v;
for(int i=0;i<COUNT;i++) {
v.push_back(i);
}
double counter = 0;
for(int i=0;i<COUNT;i+=8) {
counter += v[i+0];
counter += v[i+1];
counter += v[i+2];
counter += v[i+3];
counter += v[i+4];
counter += v[i+5];
counter += v[i+6];
counter += v[i+7];
}
std::cout << counter << std::endl;
}
Run Code Online (Sandbox Code Playgroud)
用这个程序编译g++ -O2 -g main.cpp并运行valgrind --tool=cachegrind ./a.out,然后cg_annotate cachegrind.out.31694 --auto=yes产生以下结果:
--------------------------------------------------------------------------------
-- Auto-annotated source: /home/andrej/Data/projects/pokusy/dod.cpp
-------------------------------------------------------------------------------- …Run Code Online (Sandbox Code Playgroud) 我是用于程序分析的cachegrind的长期用户,最近又再次查看了官方文档: https: //valgrind.org/docs/manual/cg-manual.html
其中多次引用了 2000 年代中期的 CPU 模型、实现决策和仿真模型,并且还声明“现代”处理器上的某些行为发生了变化:
LL 高速缓存通常会复制 L1 高速缓存的所有条目[...]这是奔腾芯片上的标准,但 AMD Opterons、Athlons 和 Durons 使用专用的 LL 高速缓存[...]
Cachegrind 模拟了 2004 年左右主流桌面/服务器处理器的典型分支预测器。
较新的处理器具有更好的分支预测器 [...] Cachegrind 的预测器设计故意保守,以便代表大量已安装的处理器,这些处理器早于更复杂的间接分支预测器的广泛部署。特别是,最新型号的 Pentium 4s (Prescott)、Pentium M、Core 和 Core 2 具有比 Cachegrind 建模更复杂的间接分支预测器。
现在我想知道
任何见解都将不胜感激!
profiling valgrind cpu-architecture branch-prediction cachegrind
假设我选择perf的事件instructions,LLC-load-misses,LLC-store-misses.进一步假设我测试一个prog 改变其输入的程序.是valgrind应该给我相同的输入和相同的计数器"相同"功能的结果吗?也就是说,如果一个值perf上升,那个值valgrind应该总是相同吗?valgrind在分析我的代码时,我应该注意模拟是否有任何影响?
编辑:BTW,在人们烧烤我没有试验自己之前,我不得不说我(有点)有,问题是我有一个Sandybridge处理器,并且perf有一个"错误"阻止我测量LLC-*事件.有一个补丁,但我不想重新编译我的内核......
我正在使用 Cachegrind 来检索没有 libc 编译的静态程序的缓存未命中次数(只是_start调用我的主函数和 asm 中的退出系统调用)。该程序是完全确定性的,指令和内存引用不会从一次运行到另一次运行发生变化。缓存与LRU完全关联作为替换策略。
然而,我注意到失误的数量有时会发生变化。更具体地说,在我转到不同的目录之前,未命中的次数始终相同:
% cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./adpcm
...
==31352== I refs: 216,145,010
...
==31352== D refs: 130,481,003 (95,186,001 rd + 35,295,002 wr)
==31352== D1 misses: 240,004 ( 150,000 rd + 90,004 wr)
==31352== LLd misses: 31 ( 11 rd + 20 wr)
Run Code Online (Sandbox Code Playgroud)
如果我一次又一次地执行相同的命令,我将继续得到相同的结果。但是如果我从不同的目录运行这个程序:
% cd ..
% cache=8 && valgrind --tool=cachegrind --I1=$((cache * 64)),$cache,64 --D1=$((cache * 64)),$cache,64 --L2=262144,4096,64 ./malardalen2/adpcm
...
==31531== I refs: 216,145,010 …Run Code Online (Sandbox Code Playgroud) cachegrind ×11
profiling ×4
valgrind ×4
c ×3
c++ ×3
caching ×2
cpu-cache ×2
performance ×2
assembly ×1
benchmarking ×1
c++11 ×1
c++14 ×1
callgrind ×1
gem5 ×1
linux-kernel ×1
memory ×1
optimization ×1
perf ×1
wincache ×1
windows ×1