Быстрый способ подсчета количества инструкций, выполненных в программе на Си

Существует ли простой способ быстро подсчитать количество выполненных инструкций (x86-инструкций - сколько и сколько каждой) при выполнении программы на C?

я использую gcc version 4.7.1 (GCC) на x86_64 GNU/Linux машина.

2 ответа

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

Этот системный вызов Linux представляет собой кросс-архитектурную оболочку для событий производительности.

Вот пример, адаптированный из man perf_event_open страница:

perf_event_open.c

#include <asm/unistd.h>
#include <linux/perf_event.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/ioctl.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;

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

    memset(&pe, 0, sizeof(struct perf_event_attr));
    pe.type = PERF_TYPE_HARDWARE;
    pe.size = sizeof(struct perf_event_attr);
    pe.config = PERF_COUNT_HW_INSTRUCTIONS;
    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);
    }

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

    /* Loop n times, should be good enough for -O0. */
    __asm__ (
        "1:;\n"
        "sub $1, %[n];\n"
        "jne 1b;\n"
        : [n] "+r" (n)
        :
        :
    );

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

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

    close(fd);
}

Скомпилируйте и запустите:

g++ -ggdb3 -O0 -std=c++11 -Wall -Wextra -pedantic -o perf_event_open.out perf_event_open.c
./perf_event_open.out

Вывод:

Used 20016 instructions

Итак, мы видим, что результат довольно близок к ожидаемому значению 20000: 10k * две инструкции на цикл в __asm__ блок (sub, jne).

Если я изменю аргумент, даже до низких значений, таких как 100:

./perf_event_open.out 100

это дает:

Used 216 instructions

поддерживая эту постоянную + 16 инструкций, поэтому кажется, что точность довольно высока, эти 16 должны быть просто ioctl инструкции по установке после нашего маленького цикла.

Теперь вас также могут заинтересовать:

Другие интересные события, которые можно измерить с помощью этого системного вызова:

Протестировано на Ubuntu 20.04 amd64, GCC 9.3.0, ядре Linux 5.4.0, процессоре Intel Core i7-7820HQ.

Вы можете использовать инструмент бинарных инструментов ' Pin' от Intel. Я бы не использовал симулятор для такой тривиальной задачи (симуляторы часто бывают очень медленными). Pin делает большую часть того, что вы можете делать с симулятором без предварительной модификации двоичного файла и с нормальным исполнением, например, со скоростью (в зависимости от используемого вами инструмента pin).

Для подсчета количества инструкций с помощью Pin:

  1. Загрузите последнюю версию (или 3.10, если этот ответ устареет) отсюда.
  2. Распакуйте все и перейдите в каталог: cd pin-root/source/tools/ManualExample/
  3. Сделайте все инструменты в каталоге: make all
  4. Запустите инструмент inscount0.so с помощью команды: ../../../pin -t obj-intel64/inscount0.so -- your-binary-here
  5. Получить количество команд в файле inscount.out, cat inscount.out,

Вывод будет что-то вроде:

➜ ../../../pin -t obj-intel64/inscount0.so -- /bin/ls
buffer_linux.cpp       itrace.cpp
buffer_windows.cpp     little_malloc.c
countreps.cpp          makefile
detach.cpp         makefile.rules
divide_by_zero_unix.c  malloc_mt.cpp
isampling.cpp          w_malloctrace.cpp
➜ cat inscount.out
Count 716372

Вероятно, дубликат этого вопроса

Я говорю, вероятно, потому что вы просили инструкции ассемблера, но этот вопрос касается профилирования кода на уровне C.

Однако мой вопрос к вам: почему вы хотите профилировать фактические машинные инструкции? Как первая проблема, это будет отличаться между различными компиляторами и их настройками оптимизации. Как более практичный вопрос, что вы могли бы сделать с этой информацией? Если вы находитесь в процессе поиска / оптимизации узких мест, профилировщик кода - это то, что вы ищете.

Я мог бы пропустить что-то важное здесь, хотя.

Вы можете легко посчитать количество выполненных команд, используя аппаратный счетчик производительности (HPC). Для доступа к HPC вам необходим интерфейс к нему. Я рекомендовал вам использовать API производительности PAPI.

Хотя это и не "быстро" в зависимости от программы, на этот вопрос, возможно, ответили. Здесь Марк Плотник предлагает использовать gdb чтобы посмотреть изменения регистра счетчика вашей программы:

# instructioncount.gdb
set pagination off
set $count=0
while ($pc != 0xyourstoppingaddress)
    stepi
    set $count++
end
print $count
quit

Затем начните gdb в вашей программе:

gdb --batch --command instructioncount.gdb --args ./yourexecutable with its arguments

Чтобы получить конечный адрес 0xyourstoppingaddress Вы можете использовать следующий скрипт:

# stopaddress.gdb
break main
run
info frame
quit

который ставит точку останова на функцию main и дает:

$ gdb --batch --command stopaddress.gdb --args ./yourexecutable with its arguments
...
Stack level 0, frame at 0x7fffffffdf70:
 rip = 0x40089d in main (main_aes.c:33); saved rip 0x7ffff7a66d20
 source language c.
 Arglist at 0x7fffffffdf60, args: argc=3, argv=0x7fffffffe048
...

Здесь важно saved rip 0x7ffff7a66d20 часть. На моем процессоре rip указатель инструкции, а saved rip это "обратный адрес", как указано pepero в этом ответе.

Так что в этом случае адрес остановки 0x7ffff7a66d20, который является обратным адресом main функция. То есть конец выполнения программы.

Другие вопросы по тегам