我正在对使用Cachegrind对已排序的项目进行操作的两个搜索算法的缓存行为进行基准测试。我在向量中有n个项,而另一个向量包含所有有效索引。我在第二个向量上使用std :: random_shuffle,然后对第一个向量中的项执行n次成功查找。我正在进行基准测试的功能大致如下:
template <typename Iterator>
void lookup_in_random_order(Iterator begin, Iterator end)
{
const std::size_t N = std::distance(begin, end);
std::vector<std::size_t> idx(N);
std::iota(idx.begin(), idx.end(), 0);
std::srand(std::time(0));
std::random_shuffle(idx.begin(), idx.end());
// Warm the cache -- I don't care about measuring this loop.
for(std::size_t i = 0; i < N; ++i)
my_search(begin, end, idx[i]);
std::random_shuffle(idx.begin(), idx.end());
// This one I would care about!
for(std::size_t i = 0; i < N; ++i)
{
int s = idx[i];
// Especially this line, of course.
my_search(begin, end, s);
}
}
我使用g ++编译代码(使用-g和-O2)。我运行Cachegrind然后运行cg_annotate。我得到以下内容:
Ir I1mr ILmr Dr D1mr DLmr Dw D1mw DLmw
. . . . . . . . . template <typename Iterator>
17 2 2 0 0 0 6 0 0 void lookup_in_random_order(Iterator begin, Iterator end)
. . . . . . . . . {
. . . . . . . . . const std::size_t N = std::distance(begin, end);
. . . . . . . . . std::vector<std::size_t> idx(N);
. . . . . . . . . std::iota(idx.begin(), idx.end(), 0);
. . . . . . . . .
4 0 0 0 0 0 2 1 1 std::srand(std::time(0));
. . . . . . . . . std::random_shuffle(idx.begin(), idx.end());
. . . . . . . . .
3,145,729 0 0 0 0 0 0 0 0 for(std::size_t i = 0; i < N; ++i)
. . . . . . . . . my_search(begin, end, idx[i]);
. . . . . . . . .
. . . . . . . . . std::random_shuffle(idx.begin(), idx.end());
. . . . . . . . .
3,145,729 1 1 0 0 0 0 0 0 for(std::size_t i = 0; i < N; ++i)
. . . . . . . . . {
1,048,575 0 0 1,048,575 132,865 131,065 0 0 0 int s = idx[i];
. . . . . . . . . my_search(begin, end, s);
. . . . . . . . . }
7 0 0 6 1 1 0 0 0 }
出于某种原因,某些线条(尤其是最有趣的线条)由点组成。现在,Cachegrind manual表示“不适用于某一行的事件由点表示。这对于区分不可能发生的事件和可以发生但不能发生的事件非常有用。”
应如何解释?我的第一个想法是,编译器可能会优化我的搜索。我认为这不可能,因为程序确实花了很多时间运行。尽管如此,我还是尝试在没有-O2标志的情况下进行编译,从某种意义上来说它似乎工作了,现在调用my_search的每一行记录了一些数字(不再有点数!)。但是,由于显而易见的原因,这似乎不是正确的方法。
一般来说,有没有一种方法可以告诉Cachegrind“特别注意这一行,我非常感兴趣它会导致多少缓存未命中”?
答案 0 :(得分:1)
我的猜测是,对于O2,它允许编译器自动内联你看到点的函数。当调用消失时,Cachegrind将看不到内联函数调用。尝试“-fno-inline”(Compiler options)
当然,无论是否有内联,您都可能拥有不同的缓存性能数据。