Как обрабатывать кэширование во время работы в C ++ в Linux

0

Я должен использовать функцию clock_gettime() для оценки и профилирования других операций, а также для домашней работы, поэтому я не могу использовать профилировщик и писать собственный код.

То, как я это делаю, выглядит следующим образом:

clock_gettime(CLOCK_PROCESS_CPUTIME_ID,&begin);

for(int i=0;i<=n;i++)
    clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);

cout<<(end.tv_nsec-begin.tv_nsec)/n; //time per clock_gettime()

Проблема заключается в том, что при n = 100 выход равен: 370,63 нс, когда n = 100000, выход: 330 нс, когда n = 1000000, выход: 260 нс, n = 10000000, выход: 55 нс,.... продолжает уменьшать,

Я понимаю, что это происходит из-за кэширования команд, но я не знаю, как справиться с этим при профилировании. Потому что, например, когда я оцениваю время вызова функции с помощью gettime, как узнать, сколько времени используется для использования в gettime?

Будет ли хорошая оценка всех этих ценностей взвешенной? (Я могу запустить операцию, я хочу, чтобы такое же количество раз, принять взвешенное значение этого, вычесть взвешенное среднее времени gettime и получить хорошую оценку операции независимо от кеширования?)

Любые предложения приветствуются.

Заранее спасибо.

Теги:
caching
profiling
timing

1 ответ

0
Лучший ответ

Когда вы вычисляете разницу во времени: (end.tv_nsec-begin.tv_nsec)/n

Вы учитываете только наносекундную часть прошедшего времени. Вы также должны учитывать секунды, так как поле tv_nsec отражает только дробную часть секунды:

int64_t end_ns = ((int64_t)end.tv_sec * 1000000000) + end.tv_nsec;
int64_t begin_ns = ((int64_t)begin.tv_sec * 1000000000) + begin.tv_nsec;
int64_t elapsed_ns = end_ns - begin_ns;

На самом деле, с вашим текущим кодом вы иногда должны получать отрицательные результаты, когда часть наносекунд end обернута вокруг и меньше, чем begin наносекундной части.

Исправьте это, и вы сможете наблюдать гораздо более последовательные результаты.


Измените: ради полноты, здесь код, который я использовал для своих тестов, который дает мне очень последовательные результаты (от 280 до 300 нс на звонок, любое количество итераций, которые я использую):

int main() {
  const int loops = 100000000;

  struct timespec begin;
  struct timespec end;
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &begin);

  for(int i = 0; i < loops; i++)
      clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);
  clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &end);

  int64_t end_ns = ((int64_t)end.tv_sec * 1000000000) + end.tv_nsec;
  int64_t begin_ns = ((int64_t)begin.tv_sec * 1000000000) + begin.tv_nsec;
  int64_t elapsed_ns = end_ns - begin_ns;
  int64_t ns_per_call = elapsed_ns / loops;
  std::cout << ns_per_call << std::endl;
}
  • 0
    Поле наносекунд не будет обтекать, размер int_64: 2 ^ 64-1, что составляет около 1,8 x 10 ^ 19. Таким образом, количество секунд, по истечении которых наносекунды будут округляться, составит (1,8x10 ^ 19) / (10 ^ 9) ~ 10 ^ 10 секунд. Никаких проблем там нет. Спасибо, что напомнили мне о том, что вы приняли во внимание секунды, это было ошибкой. Я предполагал, что поля секунд и наносекунд независимы.
  • 0
    Кстати, результаты теперь выглядят так: n = 100, время: 374 нс, n = 10000, время: 363 нс, n = 100 000, время: 241 нс, n = 10 000 000, время: 153 нс, n = 1 00 000, время: 135 нс , увеличиваясь дальше он остается около 135 (полностью кешируется?)
Показать ещё 13 комментариев

Ещё вопросы

Сообщество Overcoder
Наверх
Меню