Самый простой инструмент для измерения попаданий / промахов в кеш-программе C и времени процессора в Linux?

Я пишу небольшую программу на C и хочу измерить ее производительность.

Я хочу увидеть, сколько времени он работает в процессоре и сколько попаданий в кеш + промахов он сделал. Было бы неплохо иметь информацию о переключениях контекста и использовании памяти.

Программа выполняется менее чем за секунду.

Мне нравится информация о / proc / [pid] / stat, но я не знаю, как ее увидеть после того, как программа умерла / была убита.

Любые идеи?

РЕДАКТИРОВАТЬ: Я думаю, что Valgrind добавляет много накладных расходов. Вот почему мне нужен простой инструмент, например / proc / [pid] / stat, который всегда есть.


person jperelli    schedule 10.04.2012    source источник


Ответы (4)


Используйте perf:

perf stat ./yourapp

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

Пример из вики:

perf stat -B dd if=/dev/zero of=/dev/null count=1000000

Performance counter stats for 'dd if=/dev/zero of=/dev/null count=1000000':

        5,099 cache-misses             #      0.005 M/sec (scaled from 66.58%)
      235,384 cache-references         #      0.246 M/sec (scaled from 66.56%)
    9,281,660 branch-misses            #      3.858 %     (scaled from 33.50%)
  240,609,766 branches                 #    251.559 M/sec (scaled from 33.66%)
1,403,561,257 instructions             #      0.679 IPC   (scaled from 50.23%)
2,066,201,729 cycles                   #   2160.227 M/sec (scaled from 66.67%)
          217 page-faults              #      0.000 M/sec
            3 CPU-migrations           #      0.000 M/sec
           83 context-switches         #      0.000 M/sec
   956.474238 task-clock-msecs         #      0.999 CPUs

   0.957617512  seconds time elapsed

Нет необходимости загружать модуль ядра вручную, в современной системе Debian (с пакетом linux-base) он должен просто работать. С помощью комбинации perf record -a / perf report вы также можете выполнять профилирование всей системы. Любое приложение или библиотека, в которых есть символы отладки, будут отображаться в отчете вместе с подробностями.

Для визуализации хорошо подходят графики пламени. (Обновление 2020: пользовательский интерфейс hotspot имеет интегрированные графики пламени.)

person maxy    schedule 11.04.2012

Лучший инструмент для вас - valgrind. Он способен профилировать память, строить графы вызовов и многое другое.

sudo apt get install valgrind
valgrind ./yourapp

Однако, чтобы узнать время выполнения вашей программы, вы можете использовать time(8) утилиту linux.

time ./yourapp
person iehrlich    schedule 10.04.2012
comment
может valgrind измерить кеш или только основную память? - person jperelli; 10.04.2012
comment
Насколько мне известно, valgrind может измерять все уровни кеширования, по крайней мере, L1 и L2. - person iehrlich; 10.04.2012
comment
В Valgrind есть модуль cachegrind, который измеряет кэш. - person Some programmer dude; 10.04.2012
comment
У меня нет мануала для man 8 time. Что такое время (8), это функция C? Мне нужно время использования ЦП, а не общее время выполнения. И я думаю, что Valgrind добавляет много накладных расходов. Вот почему мне нужен простой инструмент, например / proc / [pid] / stat, который всегда есть. - person jperelli; 10.04.2012
comment
Полезно отметить, что /usr/bin/time != time. В bash time - это встроенное ключевое слово оболочки. - person jperelli; 08.11.2013
comment
Также стоит отметить, что cachegrind имитирует кеш, тогда как инструмент perf измеряет на основе реального кеша. - person Alfredo Gimenez; 23.11.2015

Вы также можете использовать

/usr/bin/time -v YourProgram.exe

Он покажет вам всю эту информацию:

/usr/bin/time -v ls
    Command being timed: "ls"
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 60%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 4080
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 314
    Voluntary context switches: 1
    Involuntary context switches: 1
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

Вы также можете использовать флаг -f для форматирования вывода в соответствии с вашими потребностями.

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

Надеюсь это поможет!

person Javi Ortiz    schedule 22.02.2013
comment
Полезно отметить, что /usr/bin/time != time. В bash time - это встроенное ключевое слово оболочки. - person jperelli; 08.11.2013
comment
Но где промахи кеша? - person devoured elysium; 08.05.2015
comment
Ответ не имеет ничего общего с промахами в кэше. - person Jingguo Yao; 13.08.2016

Системный вызов perf_event_open Linux с config = PERF_COUNT_HW_INSTRUCTIONS

perf, вероятно, то, что хочет OP, как показано на https://stackoverflow.com/a/10114325/895245, но только для полноты , Я собираюсь показать, как это сделать изнутри программы C, если вы управляете исходным кодом.

Этот метод может позволить более точные измерения конкретной интересующей области в программе. Он также может получать отдельные счетчики попаданий / промахов в кеш для каждого уровня кеш-памяти. Этот системный вызов, вероятно, использует тот же бэкэнд, что и perf.

Этот пример в основном совпадает с Быстрый способ подсчета количества инструкций, выполненных в программе на языке C, но с PERF_TYPE_HW_CACHE. При выполнении:

man perf_event_open

вы можете видеть, что в этих примерах мы учитываем только:

  • Кэш данных L1 (PERF_COUNT_HW_CACHE_L1D)
  • читает (PERF_COUNT_HW_CACHE_OP_READ), а не записывает предварительную выборку
  • промахи (PERF_COUNT_HW_CACHE_RESULT_MISS), а не попадания

perf_event_open.c

#define _GNU_SOURCE
#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/syscall.h>
#include <unistd.h>

#include <inttypes.h>

static long
perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
                int cpu, int group_fd, unsigned long flags)
{
    int ret;

    ret = syscall(__NR_perf_event_open, hw_event, pid, cpu,
                    group_fd, flags);
    return ret;
}

int
main(int argc, char **argv)
{
    struct perf_event_attr pe;
    long long count;
    int fd;
    char *chars, c;

    uint64_t n;
    if (argc > 1) {
        n = strtoll(argv[1], NULL, 0);
    } else {
        n = 10000;
    }

    chars = malloc(n * sizeof(char));

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HW_CACHE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_CACHE_L1D |
                PERF_COUNT_HW_CACHE_OP_READ << 8 |
                PERF_COUNT_HW_CACHE_RESULT_MISS << 16;
    pe.disabled = 1;
    pe.exclude_kernel = 1;
    // Don't count hypervisor events.
    pe.exclude_hv = 1;

    fd = perf_event_open(&pe, 0, -1, -1, 0);
    if (fd == -1) {
        fprintf(stderr, "Error opening leader %llx\n", pe.config);
        exit(EXIT_FAILURE);
    }

    /* Write the memory to ensure misses later. */
    for (size_t i = 0; i < n; i++) {
        chars[i] = 1;
    }

    ioctl(fd, PERF_EVENT_IOC_RESET, 0);
    ioctl(fd, PERF_EVENT_IOC_ENABLE, 0);

    /* Read from memory. */
    for (size_t i = 0; i < n; i++) {
        c = chars[i];
    }

    ioctl(fd, PERF_EVENT_IOC_DISABLE, 0);
    read(fd, &count, sizeof(long long));

    printf("%lld\n", count);

    close(fd);
    free(chars);
}

При этом я получаю линейно растущие результаты, например:

./main.out 100000
# 1565
./main.out 1000000
# 15632
./main.out 10000000
# 156641

Исходя из этого, мы можем оценить размер строки кэша: 100000/1565 ~ 63,9, что почти точно соответствует точному значению 64 согласно getconf LEVEL1_DCACHE_LINESIZE на моем компьютере, так что я думаю, он работает.

person Ciro Santilli 新疆再教育营六四事件ۍ    schedule 18.11.2020