Измерять время для выполнения одной инструкции

Есть ли способ использовать C или ассемблер или, возможно, даже С#, чтобы получить точную оценку того, сколько времени требуется для выполнения инструкции ADD?

Ответ 1

Да, вроде, но он нетривиальный и дает результаты, которые почти бессмысленны, по крайней мере, на наиболее разумно современных процессорах.

На относительно медленных процессорах (например, через оригинальный Pentium в линейке Intel, по-прежнему верен на большинстве небольших встроенных процессоров), вы можете просто посмотреть в лист данных процессора, и он (обычно) скажет вам, сколько тактов ждать. Быстро, просто и легко.

На современной настольной машине (например, Pentium Pro или новее) жизнь не так проста. Эти процессоры могут выполнять сразу несколько инструкций и выполнять их не по порядку, если между ними нет никаких зависимостей. Это означает, что вся концепция времени, проведенного одной инструкцией, становится почти бессмысленной. Время выполнения одной команды может и будет зависеть от инструкций, которые ее окружают.

Тем не менее, если вы действительно этого захотите, вы можете (обычно - в зависимости от процессора) что-то измерить, хотя он может быть достаточно серьезным вопросом, насколько это действительно будет означать. Даже получение такого результата, что только близко к бессмысленному, а не совершенно бессмысленному, не является тривиальным. Например, на чипе Intel или AMD вы можете использовать RDTSC для самого измерения времени. Это, к сожалению, может быть выполнено не по порядку, как описано выше. Чтобы получить значимые результаты, вам необходимо окружить его инструкцией, которая не может быть выполнена не в порядке ( "инструкция сериализации" ). Наиболее распространенным вариантом для этого является CPUID, так как это одна из нескольких инструкций сериализации, доступных для "пользовательского режима" (т.е. Кольца 3). Это добавляет немного завихрения, хотя: как документировано Intel, первые несколько раз процессор выполняет CPUID, это может занять больше времени, чем в последующие моменты времени. Таким образом, они рекомендуют выполнить его три раза, прежде чем использовать его для сериализации вашего времени. Поэтому общая последовательность работает примерно так:

.align 16
CPUID
CPUID
CPUID
RDTSC
; sequence under test
Add eax, ebx
; end of sequence under test
CPUID
RDTSC

Затем вы сравниваете это с результатом от того же, но с удаленной последовательностью. Разумеется, это оставляет совершенно определенные подробности - как минимум вам нужно:

  1. правильно установите регистры перед каждым CPUID
  2. сохранить значение в EAX: EDX после первого RDTSC
  3. вычесть результат из второго RDTSC с первого

Также обратите внимание на введенную мной директиву "align" - выравнивание команд может и повлиять на время, особенно если задействован цикл.

Ответ 2

Постройте цикл, который выполняет 10 миллионов раз, без ничего в теле цикла и времени. Храните это время в качестве накладных расходов, необходимых для цикла.

Затем выполните тот же цикл снова, на этот раз с тестируемым кодом в теле. Время для этого цикла, минус накладные расходы (из случая с пустым циклом), - это время из-за 10 миллионов повторений вашего тестируемого кода. Итак, разделите на количество итераций.

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

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

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

Ответ 3

Хорошо, проблема, с которой вам придется столкнуться, если вы используете ОС, такую ​​как Windows, Linux, Unix, MacOS, AmigaOS и все остальные, что на заднем плане есть много процессов, которые уже работают на вашем компьютере представление. Единственный реальный способ вычисления фактического времени команды - разобрать материнскую плату и протестировать каждый компонент с помощью внешнего оборудования. Это зависит от того, хотите ли вы это сделать сами или просто выяснить, насколько быстро выполняется типичная ревизия вашего процессора. Такие компании, как Intel и Motorola, тщательно тестируют свои чипы перед выпуском, и эти результаты доступны для общественности. Все, что вам нужно сделать, это спросить их, и они отправят вам бесплатный CD-ROM (это может быть педантизм с DVD-версией) с содержащимися в нем результатами. Вы можете сделать это сами, но будьте осторожны, особенно процессоры Intel содержат много избыточных инструкций, которые больше не желательны, не говоря уже о необходимости. Это займет много времени, но я могу абсолютно понять, как это сделать. PS. Если его чисто для того, чтобы помочь подтолкнуть ваше собственное машинное оборудование к его теоретическому максимуму в личном проекте, который вы делаете в ответ на Just Jeff выше, отлично подходит для создания аккуратных средних значений скорости обучения в реальных условиях.

Ответ 4

Нет, но вы можете рассчитать его на основе количества тактовых циклов, которые требует команда add, умноженная на тактовую частоту CPU. Различные типы аргументов для ADD могут приводить к большему или меньшему количеству циклов, но для данного списка аргументов команда всегда принимает такое же количество циклов.

Итак, почему вас это волнует?