SPEC CPU2000. Часть 22: Компиляторы Intel C++/Fortran Compiler 9.0, 64-битный код


Не так давно мы рассмотрели поведение новой версии компиляторов Intel C++/Fortran 9.0 в тестах SPEC CPU 2000. Мы изучали производительность лишь 32-битной (x86) версии кода, генерируемого этими компиляторами — с одной стороны, по той причине, что это наиболее интересно, ибо 32-битные приложения на сегодня по-прежнему составляет большую долю программного обеспечения. С другой стороны — потому что… нам просто долгое время не удавалось получить каких-либо результатов на, казалось бы, родном для Intel EM64T-кода процессоре Pentium 4 670.

Среди процессоров, участников нашего сегодняшнего тестирования всего два — по понятным причинам, с поля боя ушел Pentium M 770, не поддерживающий 64-битные расширения в принципе. Для AMD Athlon 64 FX-57 нам вновь потребовалась «доработка» кода — в данном случае, 64-битного, с которым наша утилита ICC Patcher прекрасно умеет справляться. В случае же Pentium 4 670 нам потребовалась… «модификация» совсем иного рода. Дело в том, что данный процессор, работающий под управлением Windows XP x64 Edition, наотрез отказывался выполнять задачи SPEC CPU2000, откомпилированные под EM64T — не проходило и нескольких минут, независимо от вида задачи и используемых оптимизаций, как система уходила на перезагрузку. Чем была вызвана подобная несовместимость процессора Intel с родным EM64T-кодом, на некоторое время было совершенно непонятно, пока мы не понизили частоту процессора до минимальной — 2.8 ГГц, подозревая, что дело в перегреве (ведь для того, чтобы последний не мог повлиять на результаты тестов в худшую сторону за счет троттлинга, нам приходилось, идя вразрез с принципами Intel, отключать автоматическую защиту процессора от перегрева — Thermal Monitor 1 или 2). На этой частоте все тесты прошли на ура, однако в итоге оказалось, что дело-таки не в перегреве — а просто в… неработоспособности имеющегося у нас инженерного сэмпла Pentium 4 670 на номинальной частоте 3,8 ГГц, причем, заметим — именно в 64-битном режиме. Уже на частоте 3,6 ГГц процессор оказался полностью работоспособен по отношению к EM64T-коду, в связи с чем и участвует в нашем сегодняшнем исследовании под видом «Pentium 4 660».

Чтобы сравнение было осмысленным, мы использовали те же версии компиляторов, что и ранее, при изучении производительности 32-битного кода (хотя с того момента уже были выпущены более новые версии):

  • Intel(R) C++ Compiler for 32-bit applications, Version 9.0 Build 20050624Z Package ID: W_CC_C_9.0.020
  • Intel(R) C++ Compiler for Intel(R) EM64T-based applications, Version 9.0 Build 20050624 Package ID: W_CC_C_9.0.020
  • Intel(R) Fortran Compiler for 32-bit applications, Version 9.0 Build 20050624Z Package ID: W_FC_C_9.0.019
  • Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.0 Build 20050624 Package ID: W_FC_C_9.0.019

Во всех случаях (32/64-битный код с различными вариантами оптимизации), как обычно, использовались одинаковые общие ключи компиляции кода:

PASS1_CFLAGS= -Qipo -O3 -Qprof_gen
PASS2_CFLAGS= -Qipo -O3 -Qprof_use

Что касается специфических вариантов оптимизации кода, их всего три, т.к. остальные варианты EM64T-версией компилятора не допускаются:

  • Без оптимизации (случай, когда никаких ключей вида -Qx* не указано);
  • Оптимизация под SSE2 (-QxW, использование «нового» варианта оптимизации под ядро Northwood, -QxN, для компиляции EM64T-кода по каким-то непонятным причинам не допускается);
  • Оптимизация под SSE3 (-QxP).

Прежде чем перейти к сравнению реальных цифр, отметим также, что прямое сравнение производительности первого варианта кода «без оптимизации» на платформах x86 и x86-86/EM64T, честно говоря, некорректно. Это связано с тем, что в первом случае (x86) данный код использует инструкции FPU, в то время как тот же самый код, откомпилированный под EM64T, использует инструкции SSE/SSE2, ввиду отсутствия поддержки нативного x87 FPU-кода в этой платформе.

Pentium 4 660

Итак, начнем с рассмотрения результатов тестов на процессоре Pentium 4 670, искусственно превращенном в Pentium 4 660 (частота ядра 3.6 ГГц, механизм TM1/TM2 отключен). Для наглядности, ниже по тексту мы приводим только относительные результаты сравнения производительности 64-битного кода с 32-битным. С абсолютными результатами тестов в чистом виде можно ознакомиться в Приложении №1 к настоящей статье.

Целочисленные тесты SPEC CPU2000. Как обычно, можно выделить несколько групп подтестов. Первая из них — это задачи, относящиеся к «64 битам» более-менее равнодушно, т.е. не показывающие большой прирост или, напротив, снижение производительности по сравнению с 32-битным кодом (164.gzip, 175.vpr, 176.gcc). Ко второй группе можно отнести подтесты, показывающие незначительный прирост (примерно 5%) — задачи 255.vortex и 256.bzip2. Более значительный прирост в скорости (от 15 до 33%) наблюдается в задачах 186.crafty, 197.parser и 252.eon. Тем не менее, среди SPECint2000 есть и задача, в которой наблюдается не меньшее (и даже большее — до 40% в случае оптимизации под ядро Prescott и SSE3) падение производительности — это 181.mcf. Наконец, не менее интересную группу составляют задачи, в которых наблюдается либо прирост, либо снижение скорости, в зависимости от варианта оптимизации кода — это 253.perlbmk, 254.gap и 300.twolf.

Общий итог по оценке SPECint_base2000 таков: использование EM64T в целом является выигрышным, но сам выигрыш довольно невелик — от 1.6 до 3.8%.

Гораздо интереснее выглядит сравнение тестов с вещественной арифметикой. Прежде всего, бросается в глаза выигрышность 64-битного варианта кода «без оптимизации» практически во всех случаях (за исключением, разве что, задачи 171.swim). Здесь сказывается именно то обстоятельство, о котором мы писали выше — переход от 32-разрядной к 64-разрядной версии сопровождается переходом от использования 8 регистров FPU, имеющих неудобную стековую организацию, к использованию 16 линейных регистров SSE/SSE2. Т.е. результат получается не «выигрышем от 64 бит в чистом виде». Именно поэтому корректнее сравнивать лишь результаты вариантов -QxW и -QxP, в которых в обоих случаях используются линейные SSE/SSE2-регистры (8 и 16, соответственно).

Практически нечувствительными к «64 битам» (не показывающими ни заметного выигрыша, ни падения производительности) являются довольно много подтестов — 171.swim, 178.galgel, 188.ammp, 179.lucas и 200.sixtrack. Небольшое преимущество в 64-битном режиме показывают задачи 187.facerec (5.7-6.1%), 191.fma3d (4.1-5.6%) и 301.apsi (5.0-5.4%). Производительность остальных задач весьма сильно зависит от варианта оптимизации кода (SSE2 или SSE3). Так, 168.wupwise ощутимо выигрывает только при использовании SSE3 (12.5%), но немного проигрывает в случае SSE2-кода (-2.4%). Для 172.mgrid больший прирост в скорости, напротив, наблюдается именно в SSE2-варианте (27.6%). Задача 177.mesa показывает сопоставимый прирост в обоих случаях (27.1% и 20.8%, соответственно). Однако наиболее шокирующим является поведение подтеста 179.art. Если в случае SSE3 наблюдается более-менее объяснимый прирост в 34.7%, SSE2-вариант ведет себя воистину фантастически, демонстрируя 140.5% увеличение производительности при использовании 64-битного кода. Списать это на случайность невозможно — на Athlon 64 FX-57 также наблюдается весьма значительный выигрыш в скорости. Поэтому остается только предположить, что подобное поведение может быть вызвано тем, что 32-битный компилятор Intel генерирует очень неоптимальный код этой задачи при использовании SSE2-оптимизации. Для последней из рассматриваемых задач SPECfp, 183.equake, нам удалось получить результат лишь в случае SSE2-кода (прирост составил 13.7%). Благополучно скомпилировать 64-битный SSE3-вариант не удалось — скомпилированный на первом проходе код выдавал ошибки на стадии профилирования, независимо от используемого процессора. В связи с этим, к сожалению, не удалось получить и общую оценку SPECfp_base2000 для случая -QxP. В случае же -QxW средний прирост в скорости при переходе к 64-разрядному коду составил 13.7%. Интересно отметить, что практически тот же результат (13.4%) показал и неоптимизированный вариант кода, прямое сравнение производительности 32- и 64-разрядных версий которого, как мы уже говорили выше, не вполне корректно.

Athlon 64 FX-57

Переходим ко второму участнику нашего сравнительного тестирования — процессору Athlon 64 FX-57, поддерживающему все необходимые для осуществления тестов расширения (x86-64, SSE2 и SSE3).

В целочисленных тестах разница между 32- и 64-битным кодом выглядит более выраженной по сравнению с тестами на процессоре Intel. Прежде всего, здесь практически отсутствуют «смешанные» результаты — когда одна и та же задача показывает либо преимущество, либо недостаток в производительности, в зависимости от варианта оптимизации кода (за исключением, разве что, одной-единственной 164.gzip). Не наблюдается также индифферентных результатов (отсутствия заметного выигрыша или проигрыша в скорости) — так, задачи 175.vpr, 176.gcc и 300.twolf показывают большее снижение производительности в 64-разрядном варианте, а 255.vortex и 256.bzip2, напротив, находятся в большем выигрыше от «64 бит», по сравнению с поведением этих задач на Pentium 4. Наибольший выигрыш (пусть и с другими абсолютными показателями и распределением результатов), тем не менее, по-прежнему наблюдается в задачах 186.crafty, 197.parser и 252.eon, а наибольшее снижение производительности демонстрирует 181.mcf. Что самое интересное — все это, вместе взятое, обеспечивает практически нулевую разницу в результатах в целом (по оценке SPECint_base2000) — от 0.3 до -0.6%.

Тесты с вещественной арифметикой также демонстрируют некоторые различия в поведении на 64-разрядных платформах Intel и AMD. Прежде всего, вариант кода «без оптимизации» на платформе AMD уже не выглядит выигрышным во всех случаях — т.е. как бы получается, что использование 8 FPU-регистров со стековой организацией может быть выгоднее, чем использование 16 линейных XMM-регистров. Скорее всего, виноваты не сами «регистры» (в смысле, их количество и задействуемые исполнительные модули процессора), а все же специфика генерации кода — не забываем, что разработчиком изучаемого нами компилятора все же является компания Intel, а не AMD :).

Рассмотрим подробнее варианты -QxW и -QxP, сравнение которых, как мы отмечали выше, выглядит более корректным, ибо представляет собой результат перехода от «32 бит» к «64 битам» в чистом виде. Итак, 168.wupwise показывает более сглаженный результат — от 3.2 до 6.3% прироста (ее поведение на платформе Intel отличалось несколько большей хаотичностью), 171.swim и 200.sixtrack здесь также не получают от «64 бит» практически ничего, 172.mgrid демонстрирует меньший прирост (3.8 — 10.8%), как и 177.mesa (4.8 — 9.0%). 173.applu на платформе AMD, напротив, ведет себя более хаотично (выигрывает 23.8% в случае SSE2-кода, но проигрывает 1.9% при оптимизации под SSE3). 178.galgel показывает больший прирост в варианте SSE2, но также почти не отличается по производительности от 32-битного варианта SSE3. Как мы уже отмечали выше, 179.art в SSE2-варианте также отличается фантастическим приростом скорости — 81.7%, и гораздо менее значительным (16.0%) в случае SSE3-кода. Задача 183.equake, работоспособный код которой нам удалось получить только для SSE2, на платформе AMD демонстрирует 3.6%-ное падение производительности. Тем не менее, есть и задачи, которые получают заметно больший прирост в скорости при переходе к 64-битному коду именно на платформе AMD — это 188.ammp, 189.lucas и 191.fma3d. Две оставшиеся задачи — 187.facerec и 301.aspi — демонстрируют примерно одинаковое увеличение производительности как на платформе Intel, так и AMD.

Наконец, нам осталось рассмотреть общий итог тестов SPECfp_base2000. В случае неоптимизированного кода прирост от «64-разрядности» (пусть и не в чистом виде) составляет всего 5.3% (это неудивительно, т.к. в этой категории присутствует немало тестов, получивших отрицательный результат в 64-разрядном режиме), в случае SSE2-варианта кода (-QxW) величина прироста составляет 11.6%, чем немного недотягивает до платформы Intel (13.7%).

Выводы

Основные выводы, которые можно сделать на основании полученных результатов, следующие.

1. Перевод целочисленного кода в 64-битный режим может быть как выигрышным, так и проигрышным с точки зрения производительности. Как всегда, все зависит от конкретной задачи — где-то можно получить до 30% прироста, а где-то — и до 40% падения в скорости. Тем не менее, результат «в среднем» является все же выигрышным, нежели проигрышным.

2. Задачи, использующие вычисления с плавающей точкой, в большинстве случаев получают преимущества в скорости при переходе от 32-разрядного (x86) к 64-разрядному (x86-64/EM64T) коду. Если проигрыш иногда и наблюдается, его показатель не велик — не превышает и 5%.

3. 64-разрядные процессоры AMD в целом демонстрируют несколько меньший выигрыш при использовании EM64T-кода по сравнению с 64-разрядными процессорами Intel. Разумеется, это ни в коем случае не может говорить об эффективности реализации «64 бит» в том или ином случае, а сообщает лишь о том, что EM64T-версия компиляторов Intel генерирует код, более оптимальный с точки зрения архитектуры P4, нежели K8. Собственно, ничего удивительного в этом нет, и было бы очень странно, если бы все было наоборот :).

Приложения

Приложение 1. Результаты тестов в числах




26 октября 2005 Г.

SPEC CPU2000. 22: Intel C++/Fortran Compiler 9.0, 64-

SPEC CPU2000. 22: Intel C++/Fortran Compiler 9.0, 64-

Intel C++/Fortran 9.0 SPEC CPU 2000. 32- (x86) , — , , , 32- - . — … - , , Intel EM64T- Pentium 4 670.

, — , Pentium M 770, 64- . AMD Athlon 64 FX-57 «» — , 64-, ICC Patcher . Pentium 4 670 … «» . , , Windows XP x64 Edition, SPEC CPU2000, EM64T — , , . Intel EM64T-, , — 2.8 , , ( , , , Intel, — Thermal Monitor 1 2). , , - — … Pentium 4 670 3,8 , , — 64- . 3,6 EM64T-, «Pentium 4 660».

, , , 32- ( ):

  • Intel(R) C++ Compiler for 32-bit applications, Version 9.0 Build 20050624Z Package ID: W_CC_C_9.0.020
  • Intel(R) C++ Compiler for Intel(R) EM64T-based applications, Version 9.0 Build 20050624 Package ID: W_CC_C_9.0.020
  • Intel(R) Fortran Compiler for 32-bit applications, Version 9.0 Build 20050624Z Package ID: W_FC_C_9.0.019
  • Intel(R) Fortran Compiler for Intel(R) EM64T-based applications, Version 9.0 Build 20050624 Package ID: W_FC_C_9.0.019

(32/64- ), , :

PASS1_CFLAGS= -Qipo -O3 -Qprof_gen
PASS2_CFLAGS= -Qipo -O3 -Qprof_use

, , .. EM64T- :

  • (, -Qx* );
  • SSE2 (-QxW, «» Northwood, -QxN, EM64T- - );
  • SSE3 (-QxP).

, , « » x86 x86-86/EM64T, , . , (x86) FPU, , EM64T, SSE/SSE2, x87 FPU- .

Pentium 4 660

, Pentium 4 670, Pentium 4 660 ( 3.6 , TM1/TM2 ). , 64- 32-. 1 .

SPEC CPU2000. , . — , «64 » - , .. , , 32- (164.gzip, 175.vpr, 176.gcc). , ( 5%) — 255.vortex 256.bzip2. ( 15 33%) 186.crafty, 197.parser 252.eon. , SPECint2000 , ( — 40% Prescott SSE3) — 181.mcf. , , , , — 253.perlbmk, 254.gap 300.twolf.

SPECint_base2000 : EM64T , — 1.6 3.8%.

. , 64- « » ( , , 171.swim). , — 32- 64- 8 FPU, , 16 SSE/SSE2. .. « 64 ». -QxW -QxP, SSE/SSE2- (8 16, ).

«64 » ( , ) — 171.swim, 178.galgel, 188.ammp, 179.lucas 200.sixtrack. 64- 187.facerec (5.7-6.1%), 191.fma3d (4.1-5.6%) 301.apsi (5.0-5.4%). (SSE2 SSE3). , 168.wupwise SSE3 (12.5%), SSE2- (-2.4%). 172.mgrid , , SSE2- (27.6%). 177.mesa (27.1% 20.8%, ). 179.art. SSE3 - 34.7%, SSE2- , 140.5% 64- . — Athlon 64 FX-57 . , , 32- Intel SSE2-. SPECfp, 183.equake, SSE2- ( 13.7%). 64- SSE3- — , . , , SPECfp_base2000 -QxP. -QxW 64- 13.7%. , (13.4%) , 32- 64- , , .

Athlon 64 FX-57

— Athlon 64 FX-57, (x86-64, SSE2 SSE3).

32- 64- Intel. , «» — , , ( , , - 164.gzip). ( ) — , 175.vpr, 176.gcc 300.twolf 64- , 255.vortex 256.bzip2, , «64 », Pentium 4. ( ), , - 186.crafty, 197.parser 252.eon, 181.mcf. — , , ( SPECint_base2000) — 0.3 -0.6%.

64- Intel AMD. , « » AMD — .. , 8 FPU- , 16 XMM-. , «» ( , ), — , Intel, AMD :).

-QxW -QxP, , , , «32 » «64 » . , 168.wupwise — 3.2 6.3% ( Intel ), 171.swim 200.sixtrack «64 » , 172.mgrid (3.8 — 10.8%), 177.mesa (4.8 — 9.0%). 173.applu AMD, , ( 23.8% SSE2-, 1.9% SSE3). 178.galgel SSE2, 32- SSE3. , 179.art SSE2- — 81.7%, (16.0%) SSE3-. 183.equake, SSE2, AMD 3.6%- . , , 64- AMD — 188.ammp, 189.lucas 191.fma3d. — 187.facerec 301.aspi — Intel, AMD.

, SPECfp_base2000. «64-» ( ) 5.3% ( , .. , 64- ), SSE2- (-QxW) 11.6%, Intel (13.7%).

, , .

1. 64- , . , — - 30% , - — 40% . , « » , .

2. , , 32- (x86) 64- (x86-64/EM64T) . , — 5%.

3. 64- AMD EM64T- 64- Intel. , «64 » , , EM64T- Intel , P4, K8. , , , :).

1.