Измерение времени для выполнения простых инструкций - PullRequest
2 голосов
/ 11 марта 2012

Я пытаюсь измерить количество циклов, которое требуется моему ЦП для выполнения определенной инструкции (один, который должен занимать один цикл ЦП), и выходные данные должны быть в длинах циклов (время, которое требуется ЦП для выполнения одногоцикл).Итак, прежде всего, мой процессор имеет частоту 2,1 ГГц, так что это означает, что одна единица длины цикла на моем компьютере равна 1/2100, верно?Также - я использую getTimeOfDay для измерения времени в микросекундах и вычисляю среднее значение в 1 000 000 итераций.Поэтому, если я не ошибаюсь, мой желаемый результат должен быть результатом * 2100 (чтобы получить его в циклах).Я прав?Спасибо!

PS Не знаю, имеет ли это значение, но я пишу в cpp

Ответы [ 3 ]

3 голосов
/ 11 марта 2012

Я полагаю, что некоторые из вас были дезинформированы о некоторых вещах.

В современных терминах тактовая частота представляет собой указание скорости, а не фактический показатель скорости, поэтому нет разумного способа оценить, сколько времени может занять одна инструкция.

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

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

РазрешениеgetTimeOfDay не настолько точен, чтобы оценить продолжительность времени, необходимого для измерения отдельных инструкций, даже счетчиков тактов ЦП (TSC на x86) недостаточно.

Кроме того, ваша операционная система является основным источником ошибок при оценке таких таймингов, переключение контекста, управление питанием, загрузка машины и прерывания оказывают огромное влияние.Но даже в настоящей жесткой операционной системе реального времени (QNX или VxWorks) такие измерения по-прежнему сложны и требуют времени и инструментов, а также опыта для интерпретации результатов.В операционной системе общего назначения (Windows или базовый Linux) у вас практически нет надежды на получение точных измерений)

Затраты на вычисления и ошибки чтения и сохранения количества циклов ЦП также, как правило,Карликовое время, необходимое для одной инструкции.Как минимум, я предлагаю вам рассмотреть возможность объединения нескольких сотен или тысяч инструкций вместе.

На детерминированных архитектурах (1 цикл = 1 инструкция) без кэшей, таких как микросхема PIC, вы можете делать именно то, что вы предлагаете, используятактовый множитель, но даже для проверки ваших измерений вам, вероятно, потребуется логический анализатор (т. е. вам нужно сделать это аппаратно).

Короче говоря, это чрезвычайно сложная проблема.

1 голос
/ 11 марта 2012

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

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

Ключ к увеличению количества образцов.

Так что вместо того, чтобы делать что-то вроде:

start = tik();
instruction();
end = tok();
time = end - start;

сделать

start = tik();
for ( 1..10000 )
   instruction();
end = tok();
time = (end - start) / 10000;

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

1 голос
/ 11 марта 2012

CPU содержит счетчик циклов, который вы можете прочитать с помощью встроенной сборки:

static inline uint64_t get_cycles()
{
    uint64_t n;
    __asm__ __volatile__ ("rdtsc" : "=A"(n));
    return n;
}

Если вы измеряете количество циклов для 1, 2 и 3 миллионов итераций вашей операции, вы должны иметь возможность интерполировать стоимость одного, но обязательно также измерять «пустые» циклы, чтобы убрать стоимость цикла :

{
    unsigned int n, m = get_cycles();
    for (unsigned int n = 0; n != 1000000; ++n)
    {
        // (compiler barrier)
    }
    n = get_cycles();

    // cost of loop: n - m
}

{
    unsigned int n, m = get_cycles();
    for (unsigned int n = 0; n != 1000000; ++n)
    {
        my_operation();
    }
    n = get_cycles();

    // cost of 1000000 operations: n - m - cost of loop
}

// repeat for 2000000, 3000000.
...