linux — измеряет циклы процессора кода C ++

Моя цель — измерить эффект (разных) кешей с помощью простого кода. Я следую за этой статьей, в частности, на страницах 20 и 21:
https://people.freebsd.org/~lstewart/articles/cpumemory.pdf

Я работаю над 64-битным Linux. Кэш-память L1d — 32 КБ, L2 — 256 КБ, а L3 — 25 МБ.

Это мой код (я компилирую этот код с помощью g ++ без флагов):

#include <iostream>

// ***********************************
// This is for measuring CPU clocks
#if defined(__i386__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned long long int x;
__asm__ volatile (".byte 0x0f, 0x31" : "=A" (x));
return x;
}
#elif defined(__x86_64__)
static __inline__ unsigned long long rdtsc(void)
{
unsigned hi, lo;
__asm__ __volatile__ ("rdtsc" : "=a"(lo), "=d"(hi));
return ( (unsigned long long)lo)|( ((unsigned long long)hi)<<32 );
}
#endif
// ***********************************static const int ARRAY_SIZE = 100;

struct MyStruct {
struct MyStruct *n;
};

int main() {
MyStruct myS[ARRAY_SIZE];
unsigned long long cpu_checkpoint_start, cpu_checkpoint_finish;

//  Initializing the array of structs, each element pointing to the next
for (int i=0; i < ARRAY_SIZE - 1; i++){
myS[i].n = &myS[i + 1];
for (int j = 0; j < NPAD; j++)
myS[i].pad[j] = (long int) i;
}
myS[ARRAY_SIZE - 1].n = NULL;   // the last one
for (int j = 0; j < NPAD; j++)
myS[ARRAY_SIZE - 1].pad[j] = (long int) (ARRAY_SIZE - 1);

// Filling the cache
MyStruct *current = &myS[0];
while ((current = current->n) != NULL)
;

// Sequential access
current = &myS[0];

// For CPU usage in terms of clocks (ticks)
cpu_start = rdtsc();

while ((current = current->n) != NULL)
;

cpu_finish = rdtsc();

unsigned long long avg_cpu_clocks = (cpu_finish - cpu_start) / ARRAY_SIZE;

std::cout << "Avg CPU Clocks:   " << avg_cpu_clocks << std::endl;
return 0;
}

У меня две проблемы:

1- Я изменил ARRAY_SIZE от 1 до 1 000 000 (поэтому размер моего массива колеблется от 2 до 2 МБ), но средняя тактовая частота процессора всегда равна 10.

Согласно этому PDF (рис. 3-10 на стр. 21), я ожидал получить 3-5 тактов, когда массив может полностью уместиться в L1, и получить более высокие числа (9 циклов), когда он превышает размер L1.

2- Если я увеличу ARRAY_SIZE свыше 1 000 000, я получу ошибку сегментации (дамп ядра), что связано с переполнением стека. У меня вопрос, используется ли динамическое распределение (MyStruct *myS = new MyStruct[ARRAY_SIZE]) не влечет за собой снижения производительности.

1

Решение

Даже если метод, который вы использовали для измерения выполнения, ненадежен, полученный вами результат (4 цикла) имеет смысл, и вот почему. Измеряемая петля содержит три инструкции (mov, test, branch). Из-за предсказания ветвлений мы можем притвориться, что у нас есть только последовательность команд mov / test. Из-за суперскалярного выполнения выполнение команды mov может перекрываться с выполнением команды test некоторой предыдущей итерации. Следовательно, mov определяет время выполнения. Задержка получения данных из кэша L1 в большинстве последних процессоров Intel составляет 4 цикла. Таким образом, это должно занять около 4 циклов на элемент, предполагая, что он существует в кэше L1. Тем не менее, только предположение, но это зависит от микроархитектуры, причина того, что количество элементов в массиве, кажется, не влияет на время, состоит в том, что аппаратные средства предварительной выборки L1 и L2 скрывают большую часть затрат на выборку данных с более низких уровней памяти. система эффективно делает размер строки кэша L1 бесконечным.

Если вы хотите оценить преимущества кэшей, а не аппаратную предварительную выборку, вы должны отключить предварительную проверку. Способ сделать это зависит от процессора и может быть невозможен.

Intel рекомендует использовать инструкцию rdtscp для измерения времени выполнения. При правильном использовании он может дать измерения более точные, чем clock_gettime или любая другая функция.

По поводу вашего второго вопроса. Вы должны выделить массив из кучи. Для этой конкретной программы это не повлечет за собой дополнительного снижения производительности.

3

Другие решения


По вопросам рекламы ammmcru@yandex.ru
Adblock
detector