Сколько циклов процессора требуется для каждой инструкции сборки?

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

Вот пример, в приведенном ниже коде mov / lock – 1 цикл процессора, а xchg – 3 цикла процессора.

// This part is Platform dependent! #ifdef WIN32 inline int CPP_SpinLock::TestAndSet(int* pTargetAddress, int nValue) { __asm { mov edx, dword ptr [pTargetAddress] mov eax, nValue lock xchg eax, dword ptr [edx] } // mov = 1 CPU cycle // lock = 1 CPU cycle // xchg = 3 CPU cycles } #endif // WIN32 

BTW: вот URL для кода, который я опубликовал: http://www.codeproject.com/KB/threads/spinlocks.aspx

5 Solutions collect form web for “Сколько циклов процессора требуется для каждой инструкции сборки?”

В случае конвейерной обработки, обработки без обработки, микрокодов, многоядерных процессоров и т. Д. Нет гарантии, что конкретный раздел кода сборки будет принимать ровно x циклов процессора / тактового цикла / любых циклов.

Если такая ссылка существует, она сможет обеспечить широкие обобщения с учетом конкретной архитектуры, и в зависимости от того, как реализован микрокод, вы можете обнаружить, что Pentium M отличается от Core 2 Duo, который отличается от двухъядерного ядра AMD , и т.д.

Обратите внимание, что эта статья была обновлена ​​в 2000 году и написана ранее. Даже Pentium 4 сложно настроить на время инструкций – PIII, PII, а исходный pentium был проще, а ссылки на них, вероятно, были основаны на тех более ранних процессорах, у которых была более четкая синхронизация инструкций.

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

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

Точные задержки для процессоров Intell и AMD перечислены в таблицах инструкций Agner Fog . См. Также Справочное руководство по оптимизации архитектуры Intel® 64 и IA-32 , а также латентность команд и пропускную способность процессоров AMD и Intel x86 (от ответа Can-Berk Güder, который только что был удален). AMD также имеет pdf-руководства на своем собственном веб-сайте с их официальными ценностями.

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

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

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

Редактировать В Руководстве по оптимизации Intel в таблице C-13: первый столбец – это тип инструкции, тогда для каждого CPUID имеется несколько столбцов для задержки. Идентификатор CPUID указывает, к какому семейству процессоров относятся числа и объясняются в другом месте документа. Задержка определяет, сколько циклов требуется до того, как результат будет доступен, так что это номер, который вы ищете.

Столбцы пропускной способности показывают, сколько из этого типа инструкций может быть выполнено за цикл.

Выглядя в xhg в этой таблице, мы видим, что в зависимости от семейства процессоров он занимает 1-3 цикла, а mov принимает 0,5-1. Это для регистро-регистральных форм инструкций, а не для lock xchg с памятью, которая намного медленнее. И что еще более важно, чрезвычайно высокая латентность и влияние на окружающий код (гораздо медленнее, когда есть конкуренция с другим kernelм), поэтому смотреть только на лучшее дело – ошибка. (Я не искал, что такое каждый идентификатор CPUID, но я предполагаю, что .5 предназначены для Pentium 4, которые запускали некоторые компоненты чипа с двойной скоростью, что позволяло ему делать что-то в половине циклов)

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

Измерение и подсчет ЦП-циклов больше не имеет смысла на x86.

Прежде всего, спросите себя, за какой процессор вы рассчитываете циклы? Core-2? Athlon? Pentium-M? Атом? Все эти процессоры выполняют код x86, но все они имеют разные времена выполнения. Исполнение даже варьируется между разными степпингами одного и того же CPU.

Последним x86, где подсчет циклов имел смысл, был Pentium-Pro.

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

Таким образом, время для команды зависит не только от самой команды, но и от окружающего кода.

В любом случае: вы можете оценить использование пропускной способности и латентность инструкций для разных процессоров. Соответствующую информацию можно найти на сайтах Intel и AMD.

Agner Fog имеет очень хорошее резюме на своем веб-сайте. См. Таблицы инструкций для задержек, пропускной способности и счета uop. См. PDF-документ microarchictecture, чтобы узнать, как их интерпретировать.

http://www.agner.org/optimize

Но учтите, что xchg -memory не имеет outlookируемой производительности, даже если вы посмотрите только на одну модель процессора. Даже в случае отсутствия конкуренции, когда кеш-линия уже горячая в кеше L1D, наличие полного барьера памяти будет означать, что влияние сильно зависит от нагрузок и хранилищ к другим адресам в окружающем коде.


Btw – так как ваш примерный код является базовым строительным блоком без привязки к базе данных: считаете ли вы использование встроенных функций компилятора? На win32 вы можете включить intrin.h и использовать такие функции, как _InterlockedExchange.

Это даст вам лучшее время выполнения, потому что компилятор может выполнить инструкции. Inline-ассемблер всегда заставляет компилятор отключать оптимизацию вокруг asm-кода.

Современные процессоры – это сложные животные, использующие конвейерную обработку , суперскалярное выполнение и исполнение вне порядка среди других методов, которые затрудняют анализ производительности … но не невозможно !

Хотя вы больше не можете просто добавлять латентности streamа инструкций для получения общей продолжительности работы, вы можете получить (часто) высокоточный анализ поведения какого-либо fragmentа кода (особенно цикла), как описано ниже, и в другие связанные ресурсы.

Время проведения инструкций

Во-первых, вам нужны фактические тайминги. Они различаются по архитектуре процессора, но лучшим ресурсом в настоящее время для таймингов x86 являются таблицы инструкций Agner Fog. Эти таблицы содержат не менее тридцати разных микроархитексов, которые представляют собой минимальное / типичное время, которое команда берет с входных данных, готовых к выпуску. По словам Агнера:

Задержка: это задержка, которую команда генерирует в цепочке зависимостей. Номера – это минимальные значения. Недостатки кэша, несоосность и исключения могут значительно увеличить количество часов. Если включена гиперпоточность, использование одних и тех же исполнительных блоков в другом streamе приводит к снижению производительности. Денормальные числа, NAN и бесконечность не увеличивают латентность. Используемый единица времени – это тактовые циклы, а не опорные тактовые циклы, заданные счетчиком временных меток.

Так, например, инструкция add имеет латентность одного цикла, поэтому ряд зависимых команд добавления, как показано, будет иметь латентность 1 цикл на каждый add :

 add eax, eax add eax, eax add eax, eax add eax, eax # total latency of 4 cycles for these 4 adds 

Обратите внимание, что это не означает, что инструкции add выполняются только по 1 циклу. Например, если инструкции добавления не зависели, возможно, что на современных чипах все 4 команды добавления могут выполняться независимо в одном и том же цикле:

 add eax, eax add ebx, ebx add ecx, ecx add edx, edx # these 4 instructions might all execute, in parallel in a single cycle 

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

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

Для add это указано как 0.25 что означает, что до 4 add инструкции могут выполнять каждый цикл (давая обратную пропускную способность 1/4 1 / 4 = 0.25 ).

Обратный номер пропускной способности также дает подсказку о возможности конвейерной обработки инструкции. Например, на последних чипах x86 общие формы команды imul имеют задержку в 3 цикла, и внутри нее может обрабатываться только один исполнительный блок (в отличие от add которое обычно имеет четыре блока с возможностью добавления). Тем не менее, наблюдаемая пропускная способность для длинной серии независимых команд imul составляет 1 / цикл, а не 1 каждые 3 цикла, как вы могли ожидать, учитывая задержку в 3 раза. Причина в том, что модуль imul конвейерен: он может запускать новый imul каждом цикле , даже если предыдущее умножение не завершено.

Это означает, что ряд независимых команд imul может работать до 1 за цикл, но ряд зависимых команд imul будет выполняться только по 1 каждые 3 цикла (так как следующий imul не может запускаться до тех пор, пока не будет imul результат от предыдущего ).

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

Детальный анализ

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

Кроме того, существуют другие ограничения, не отмеченные вышеприведенными числами, такие как тот факт, что некоторые команды конкурируют за одни и те же ресурсы в ЦП и ограничения в других частях конвейера CPU (например, декодирование команд), что может привести к снижению общая пропускная способность, чем вы рассчитывали, просто глядя на задержку и пропускную способность. Помимо этого, у вас есть факторы «вне ALU», такие как доступ к памяти и предсказание ветвей: целые темы для себя – вы можете в основном моделировать их, но это требует работы. Например, вот недавняя публикация, в которой в ответ подробно рассматриваются наиболее важные факторы.

Покрытие всех деталей увеличило бы размер этого уже долгого ответа в 10 или более раз, поэтому я просто укажу вам на лучшие ресурсы. Agner Fog имеет руководство по оптимизации, которое подробно описывает точный анализ цикла с помощью дюжины инструкций. См. « 12.7 Пример анализа узких мест в векторных циклах», который начинается на стр. 95 в текущей версии PDF.

Основная идея заключается в том, что вы создаете таблицу с одной строкой на каждую команду и отмечаете используемые ресурсы выполнения. Это позволяет увидеть узкие места пропускной способности. Кроме того, вам необходимо изучить цикл для переносимых зависимостей, чтобы убедиться, что ограничение ограничено пропускной способностью (см. « 12.16 Анализ зависимостей» для сложного случая).

Если вы не хотите делать это вручную, Intel выпустила анализатор кода архитектуры Intel , который является инструментом, который автоматизирует этот анализ. В настоящее время он не обновляется за пределами Skylake, но результаты по-прежнему в значительной степени разумны для Kaby Lake, поскольку микроархитектура не сильно изменилась, и поэтому тайминги остаются сопоставимыми. Этот ответ содержит много подробностей и предоставляет пример вывода, а руководство пользователя не является плохим (хотя оно устарело и относится к новейшим версиям).

Другие источники

Agner обычно предоставляет тайминги для новых архитектур вскоре после их выпуска, но вы также можете проверить instlatx64 для аналогично организованных таймингов в результатах InstLatX86 и InstLatX64 . Результаты охватывают множество интересных старых фишек, и новые фишки обычно появляются довольно быстро. Результаты в основном согласуются с Agner’s, за некоторыми исключениями здесь и там. Вы также можете найти латентность памяти и другие значения на этой странице.

Вы даже можете получить результаты синхронизации непосредственно от Intel в своих руководствах по оптимизации IA32 и Intel 64 в Приложении C: «ИНСТРУКЦИЯ ПО ЛИТЕРАТУРЕ И ЧЕРЕЗ» . Лично я предпочитаю версию Agner, потому что они более полные, часто прибывают до обновления руководства Intel, и их проще использовать, поскольку они предоставляют электронную таблицу и PDF-версию.

Наконец, wiki-хранилище x86 имеет множество ресурсов для оптимизации x86, включая ссылки на другие примеры того, как делать точный анализ последовательности кодов.

Если вы хотите глубже изучить тип «анализа streamа данных», описанный выше, я бы рекомендовал A Whirlwind Introduction to Data Flow Graphs .

lock xchg eax, dword ptr [edx]

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

Таким образом, оптимальная производительность возвращается к настройке ваших критических регионов.

Обратите внимание на одно kernel, которое вы можете выбрать, удалив блокировку, но она необходима для многоядерных процессоров.

Давайте будем гением компьютера.