2012-03-18 2 views
0

Я сравниваю поведение кэша двух алгоритмов поиска, которые работают с отсортированным диапазоном элементов с Cachegrind. У меня есть n элементов в векторе и другой вектор, который содержит все допустимые индексы. Я использую std :: random_shuffle для второго вектора и выполняю n успешных поисков по элементам в первом векторе. Функция Я бенчмаркинг выглядит примерно следующим образом:Могу ли я «заставить» Cachegrind анализировать операцию (или линию)?

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 и -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, что «посмотрите на эту строку, особенно, мне очень интересно, сколько упущений кеша она вызывает»?

ответ

1

Мое предположение заключается в том, что с O2 он позволяет компилятору выполнять автоматическую инкрустацию функций, где вы видите точки. Cachegrind не увидит встроенные вызовы функций, поскольку вызовы исчезли. Попробуйте «-fno-inline» (Compiler options)

Конечно, вы, вероятно, будете иметь разные номера производительности кеша с и без вложения.

+0

А, конечно, кажется хорошей идеей. Более того, я попробовал компиляцию с помощью «-g -O3 -fno-inline» и, быстро взглянув, кажется, работает. Я попробую еще несколько тестов, прежде чем принимать ответ. Благодаря тонну! – mrm