Почему эти счетчики команд ls так сильно различаются? (ptrace против perf против qemu)

Я хочу подсчитать общее количество инструкций, выполненных при запуске /bin/ls. Я использовал 3 метода, результаты которых сильно различаются, и я не знаю, почему.

<сильный>1. Подсчет инструкций с помощью ptrace

Я написал фрагмент кода, который вызывает экземпляр ls и проходит через него с помощью ptrace:

#include <stdio.h>
#include <sys/ptrace.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <sys/user.h>
#include <sys/reg.h>    
#include <sys/syscall.h>

int main()
{   
    pid_t child;
    child = fork(); //create child
    
    if(child == 0) {
        ptrace(PTRACE_TRACEME, 0, NULL, NULL);
        char* child_argv[] = {"/bin/ls", NULL};
        execv("/bin/ls", child_argv);
    }
    else {
        int status;
        long long ins_count = 0;
        while(1)
        {
            //stop tracing if child terminated successfully
            wait(&status);
            if(WIFEXITED(status))
                break;

                ins_count++;
                ptrace(PTRACE_SINGLESTEP, child, NULL, NULL);
        }

    printf("\n%lld Instructions executed.\n", ins_count);

    }
    
    return 0;
}

Запуск этого кода дает мне 516 678 выполненных инструкций.

<сильный>2. Пошаговое выполнение QEMU

Я смоделировал ls, используя qemu в пошаговом режиме, и записал все входящие инструкции в файл журнала с помощью следующей команды: qemu-x86_64 -singlestep -D logfile -d in_asm /bin/ls

По данным qemul ls выполняет 16 836 инструкций.

<сильный>3. производительность

sudo perf stat ls

Эта команда дала мне 8.162.180 выполненных инструкций.

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


person Sbardila    schedule 13.11.2020    source источник
comment
Ваша собственная программа будет считать инструкции ld-linux.so, но не инструкции системных вызовов (syscall считается как одна инструкция). Я предполагаю (я не знаю), что perf будет считать инструкции в ядре Linux (поэтому одна syscall - это тысячи инструкций), а qemu не считает ld-linux.so.   -  person Martin Rosenau    schedule 13.11.2020
comment
спасибо! так что, если мой код пропускает инструкции ld-linux.so, я должен получить тот же счет, что и qemu?   -  person Sbardila    schedule 14.11.2020


Ответы (1)


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

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

person Kuba hasn't forgotten Monica    schedule 13.11.2020
comment
Моя цель — использовать те же инструкции, что и qemu. Qemu может сбрасывать регистры во время повторения инструкций программы, я хочу сделать то же самое с моим кодом ptrace, повторять те же инструкции, что и qemu, и сбрасывать регистры для сравнения. К сожалению, документации по qemu не так много, и я не достаточно опытен, чтобы понять это, взглянув на исходный код qemu. - person Sbardila; 14.11.2020
comment
Тогда вам нужно использовать qemu. Период. Вы не сможете сделать это с помощью ptrace — почему вы думаете, что сможете? Это невозможно. qemu может эмулировать вплоть до уровня виртуальной машины, то есть он эмулирует весь ПК и будет эмулировать ядро, поэтому он имеет представление обо всех уровнях выполнения. Его можно использовать только для частичной эмуляции, например. для запуска кода ARM linux на процессоре Intel, но он должен быть настроен таким образом, и вы ничего не знаете о точной настройке. ptrace не проникает в код ядра, вот и все. - person Kuba hasn't forgotten Monica; 16.11.2020
comment
Конкретный ответ в случае части QEMU: журнал «in_asm» вообще не подсчитывает общее количество выполненных инструкций! -- см. более подробное объяснение в моем ответе на stackoverflow.com /вопросы/64847254/ - person Peter Maydell; 17.11.2020