TL: DR: переадресация хранилища семейства Sandybridge имеет меньшую задержку, если перезагрузка не выполняется сразу. Добавление бесполезного кода может ускорить цикл режима отладки, поскольку узкие места задержки, переносимой циклом, в -O0
антиоптимизированном коде почти всегда связаны с сохранение / перезагрузка некоторых переменных C.
Другие примеры замедления в действии: гиперпоточность, вызов пустой функции, доступ к переменным через указатели.
Все это не имеет отношения к оптимизированному коду. Время от времени могут возникать узкие места, связанные с задержкой переадресации магазина, но добавление бесполезных осложнений в код не ускорит его.
Вы тестируете отладочную сборку, которая в основном бесполезно. У них другие узкие места, чем у оптимизированного кода, а не равномерное замедление.
Но очевидно, что существует реальная причина того, что отладочная сборка одной версии работает медленнее, чем отладочная сборка другой версии. (Предполагая, что вы измерили правильно, и это было не просто изменение частоты процессора (турбо / энергосбережение), приводящее к разнице во времени настенных часов.)
Если вы хотите вникнуть в детали анализа производительности x86, мы можем попытаться объяснить, почему asm работает именно так, как в первую очередь, и почему asm из дополнительного оператора C (который с -O0
компилируется в дополнительные инструкции asm) может сделать это быстрее в целом. Это кое-что расскажет нам о влиянии asm на производительность, но ничего полезного об оптимизации C.
Вы не показали весь внутренний цикл, только часть тела цикла, но gcc -O0
довольно предсказуемо. Каждый оператор C компилируется отдельно от всех остальных, при этом все переменные C переливаются / перезагружаются между блоками для каждого оператора. Это позволяет вам изменять переменные с помощью отладчика в пошаговом режиме или даже переходить к другой строке в функции, при этом код все еще работает. Стоимость компиляции таким образом катастрофична. Например, у вашего цикла нет побочных эффектов (ни один из результатов не используется), поэтому весь тройной вложенный цикл может и будет компилироваться с нулевыми инструкциями в реальной сборке, выполняясь бесконечно быстрее. Или, что более реалистично, запускать 1 цикл на итерацию вместо ~ 6, даже без оптимизации или серьезных преобразований.
Узким местом, вероятно, является зависящая от цикла зависимость от k
с сохранением / перезагрузкой и add
для увеличения. Задержка переадресации магазина обычно составляет около 5 циклов на большинстве процессоров. И, таким образом, ваш внутренний цикл ограничен запуском один раз за ~ 6 циклов, задержка назначения памяти add
.
Если вы используете процессор Intel, задержка сохранения / перезагрузки может быть меньше (лучше), если перезагрузка не может быть выполнена сразу. Наличие большего количества независимых загрузок / хранилищ между зависимой парой может объяснить это в вашем случае. См. Цикл с вызовом функции быстрее, чем пустой цикл.
Таким образом, при увеличении объема работы в цикле тот addl $1, -12(%rbp)
, который может поддерживать пропускную способность одного за 6 циклов при последовательном запуске, вместо этого может создать узкое место только из одной итерации за 4 или 5 циклов.
Согласно измерениям из сообщения в блоге 2013 г., так что да, это наиболее вероятное объяснение и для вашего Broadwell i5-5257U. Похоже, что этот эффект происходит на всех процессорах семейства Intel Sandybridge.
Без дополнительной информации о вашем тестовом оборудовании, версии компилятора (или источнике asm для внутреннего цикла), и абсолютных и / или относительных показателях производительности для обеих версий, это мое лучшее без особых усилий угадать объяснение. Бенчмаркинг / профилирование gcc -O0
в моей системе Skylake недостаточно интересно, чтобы попробовать это самому. В следующий раз включите временные числа.
Задержка при сохранении / перезагрузке для всей работы, которая не является частью цепочки зависимостей, переносимой по циклу, не имеет значения, важна только пропускная способность. Очередь магазина в современных вышедших из строя ЦП действительно обеспечивает переименование памяти, устраняя запись после -запись и опасность записи после чтения из-за повторного использования одной и той же стековой памяти для p
записи, а затем чтения и записи в другом месте. (Для получения информации см. https://en.wikipedia.org/wiki/Memory_disambiguation#Avoiding_AWde_WAR_and_den_WAR_ подробнее об опасностях для памяти и этот вопрос и ответ, чтобы узнать больше о задержке и пропускной способности и повторном использовании одного и того же переименования регистров / регистров)
Множественные итерации внутреннего цикла могут выполняться одновременно, потому что буфер порядка памяти отслеживает, из какого хранилища каждая загрузка должна принимать данные, не требуя предыдущего хранилища в том же месте для фиксации в L1D и выхода из него. очередь магазина. (См. Руководство Intel по оптимизации и PDF-файл с микроархитектурой Agner Fog для получения дополнительной информации о внутреннем устройстве микроархитектуры ЦП.)
Означает ли это, что добавление бесполезных операторов ускорит работу реальных программ? (с включенной оптимизацией)
В общем, нет. Компиляторы хранят переменные цикла в регистрах для самых внутренних циклов. А при включенной оптимизации бесполезные операторы будут оптимизированы.
Настраивать исходный код для gcc -O0
бесполезно. Измеряйте с помощью -O3
или любых других параметров, которые используются в сценариях сборки по умолчанию для вашего проекта.
Кроме того, это ускорение переадресации магазина характерно для семейства Intel Sandybridge, и вы не увидите его на других микроархитектурах, таких как Ryzen, если только они не имеют аналогичного эффекта задержки пересылки магазина.
Задержка переадресации магазина может быть проблемой в реальном (оптимизированном) выводе компилятора, особенно если вы не использовали оптимизацию времени компоновки (LTO), чтобы крошечные функции были встроены, особенно функции, которые передают или возвращают что угодно по ссылке (поэтому оно должно проходить через память, а не через регистры). Для устранения проблемы могут потребоваться хаки вроде volatile
, если вы действительно хотите обойти это на процессорах Intel и, возможно, усугубить ситуацию на некоторых других процессорах. См. обсуждение в комментариях а>
person
Peter Cordes
schedule
09.03.2018
gcc
только генерировать сборку, которая обычно более читабельна, чем дизассемблер (термин «декомпилировать», ИМХО, неверен), который вы предоставили. - person Ulrich Eckhardt   schedule 09.03.2018k
. Если вы используете Skylake, может задерживаться фактически будет ниже (лучше), когда между зависимой парой больше (включая другие магазины / грузы).. - person Peter Cordes   schedule 09.03.2018p
(иq
) после циклов, иначе компилятор может вообще не сгенерировать код для этих циклов. - person Some programmer dude   schedule 09.03.2018-O2
. - person Some programmer dude   schedule 09.03.2018