Кто сегодня самый шустрый
www.optim.ru
Новые участники
Мы протестировали еще три компилятора, а именно: GNU C++ 2.95.3-7 (вернее его порт на Windows - mingw), Borland C++ 5.5 и VC.Net (v 7.0) beta 2.
Компилятор GNU C++ (далее gcc) тестировался нами и в других версиях (меньших чем 2.95.3-7). Причем он каждый раз показывал несколько различающиеся результаты, но так как серьезное отличие оказалось в и без того спорном тесте Borland C++ 5.5 (далее bcc) - это последняя версия компилятора C++ от фирмы Borland. Это добротный компилятор, довольно точно соответствующий стандарту. Интерес к нему подогревается еще и тем, что Borland C++ 5.5 стал свободно распространяемым.
VC.Net (v 7.0) beta 2 (далее VC7) - это еще бета версия, но его результаты уже позволяют говорить о том, что алгоритмы оптимизации в новой версии заметно улучшились. Не все тесты стали выполняться быстрее, но некоторые (подсчет p , и строковый тест) - несомненно.
Итак перейдем к самим тестам. Единственный, кто не стал утруждать себя оптимизацией - bcc. Но его результат оказался одним из худших уступив последнее место только явному VB.
VC7 оптимизировал как вызов, так и цикл, в котором этот вызов делался. Причем такое поведение наблюдалось как в режиме с автоматической inline-подстановкой, так и без этого режима. По всей видимости, в компилятор был напрямую добавлен алгоритм оптимизации, выкидывающий пустые вызовы, а в отсутствие вызова цикл стал пустым и тоже был выкинут. С одной стороны, это хорошо, так как теперь заглушки, оставленные в коде, больше не будут занимать процессорного времени. Но с точки зрения нашего теста это плохо, так как его целью является проверка оптимальности генерируемого кода, производящего вызов метода. Так что VC7 в этом тесте можно поставить баранку, даже несмотря на столь замечательные результаты.
Gcc прекрасно справился с этим тестом, хотя ни в одном из вариантов не смог полностью соптимизировать весь цикл. По уму, для зачета нужно брать результат, полученный без опций компилятора, заставляющих его раскручивать циклы. Это связано с тем, что цикл в нашем случае - это не зло, а способ заставить компилятор выполнять код достаточное количество раз, чтобы занимаемое процессом время можно было измерить. Учитывая, что компилятор все равно не смог полностью соптимизировать цикл, результаты тестов с раскруткой циклов становятся бесполезными. Однако мы решили оставить его, хотя бы ради справедливости. Так что вы можете сами принять для себя решение, как оценивать gcc.
Еще раз напомним, что не стоит обращать особого внимания на синтетические тесты, ибо выигрыш в данном тесте зачастую достигается не оптимальностью вызова метода, а другими оптимизациями (раскрутка цикла, inline-подстановки...), и тем, что время, затрачиваемое на вызов, относительно невелико. Удивительно то, что это время оказалось на треть больше, чем у Delphi, также продукта этой фирмы. Видимо недаром бытует мнение, что Borland невзлюбил C++.
VC7 стал победителем этого теста в общем зачете, улучшив время, показанное своим предшественником на 2 сотых секунды :). Такую победу можно было бы и не считать победой, если бы VC7 не показал того же времени в режиме без автоматической inline-подстановки (в этом режиме VC6 показал заметно худший результат, 6.49 секунды, хотя стал в прошлый раз лидером).
Bcc в очередной раз показал время, хотя и немногим, но худшее, чем Delphi. Что же, это некритичное отставание, как это было в случае с VB6, но все равно обидно.
Для gcc этот тест был, пожалуй, наиболее неудачным. Gcc умудрился отстать даже от Java. Причем не помог ему даже вариант компиляции с полной раскруткой циклов - разница в скорости была незначительной (18.78 секунд в обычном режиме и 18.66 в режиме с полной раскруткой циклов). Назвать эту разницу серьезной (особенно на фоне столь серьезного отставания) нельзя. Видимо, повсеместное использование COM, как известно, основанного на виртуальных вызовах, заставило разработчиков традиционных для Windows компиляторов с большим усердием заниматься оптимизацией вызовов виртуальных методов.
Результаты данного теста похожи на предыдущий, с той лишь разницей, что VC7 не смог полностью оптимизировать тест в режиме с автоматической inline-подстановкой. Это странно, так как мы видели, что VC7 не задумываясь выбрасывает лишние вызовы и применяет оптимизацию к результатам подстановки. В конце концов, если обращение к члену класса заменить на обращение к глобальной переменной, то VC7 спокойно выбросит цикл, заменив его константным вычислением и подставив его результат в переменную. Короче говоря, Microsoft еще есть над чем работать в следующей версии своего компилятора C++, если таковой планируется.
Gcc продемонстрировал относительно неплохой результат, но все таки отстал от лидера (C#). Как и в прошлый раз, результаты с разворотом цикла приводятся исключительно в целях справедливости и не должны рассматриваться в качестве оцениваемых.
Первый не синтетический тест. Что же он показал? Собственно, показал примерно те же зависимости, которые мы наблюдали в предыдущих тестах. Всс отстал и занял место между Delphi и Java. Gсс был более удачлив, но раскрутка циклов на реальных задачах не дала прироста производительности. Напротив, тест без разворота циклов занял наименьшее время, 9.36, с разворотом циклов - среднее, 9.95, с "полным" разворотом циклов - 9.97, а если включить сразу оба варианта разворотов циклов, то время выполнения теста и вовсе выходит за 10 секунд. Так что данная оптимизация на хороших алгоритмах может дать скорее замедление (хотя и незначительное), чем прирост производительности.
Порадовал только один VC7, который снова смог поднять планку, в этот раз уже на ощутимые полсекунды. Снова повторился прирост не только в режиме с автоматической inline-подстановкой, но и в обычном.
Это первый тест, в котором опция раскрутки циклов в gcc дала прирост производительности, тем самым позволив gcc занять верхнюю ступень пьедестала почета. Кривизна алгоритма как бы частично компенсировалась разворотом цикла. Однако вариант с "полным" разворотом циклов ничем не отличался от более простого аналога. Время gcc, показанное без оптимизаций раскрутки циклов, оказалось хуже, чем у большинства участников, но тоже очень достойным, подтвердив, что gcc является качественным продуктом. Для сравнения, конечно же, нужно брать результат с раскруткой цикла.
Порадовал в этот раз и bcc. Его результат был хотя и не лучшим, но настолько мало отставал от лидера, что bcc можно поздравить с неплохим результатом.
В этом тесте VC7 и gcc показали примерно одинаковый результат, практически вдвое лучший, чем у всех конкурентов. Это уже действительно достижение, так как данный тест является совершенно реальным целочисленным расчетом с не очень оптимальным алгоритмом, но все же намного более оправданным, чем (воистину бредовый) алгоритм пузырьковой сортировки.
Надеемся, что в дальнейшем замечательные методы оптимизации попадут и в другие компиляторы. В конце концов, Microsoft обладает полной информацией об алгоритмах, применяемых в обоих компиляторах, а все остальные могут учиться на опыте gcc.
Borland показал достойный результат, но, как всегда, чуть хуже чем у Delphi.
Удивительно, но трех сотых секунды было достаточно, чтобы пальма первенства ушла из рук Delphi в руки VC7. Не думаю, что поклонники Delphi от этого сильно расстроятся, ведь результат Delphi поистине замечателен, но факт есть факт.
Однако сейчас хочется поговорить немного о другом. Как уже говорилось, в прошлой серии скорость выполнения этого теста в большей степени зависит не от качества компилятора, а от качества реализации хипа. По умолчанию Delphi использует однопоточный режим работы с хипом, и некоторые читатели (с одновременно знакомым и загадочным именем Anonym) усомнились в том, что реализация хипа в Delphi лучше, чем стандартная реализация в W2k. Обосновывалось это тем, что мы не провели тестов в многопоточном режиме. мы решил исправить данное упущение.
Для того, чтобы включить многопоточный режим, мы добавили в обработчик события FormCreate переключение свойства IsMultiThread:
Это действительно привело к снижению скорости выполнения теста до 11.51 секунды, но повторное выполнение не привело к какому бы то ни было увеличению времени. А если учесть, что результаты VC6 и Intel C++ были приведены тоже для однопоточного режима, и то, что даже в этом случае Delphi осталась лидером (среди тех участников), то можно сказать, что слова о качестве реализации хипа в Delphi совершенно справедливы. Однако мы не делали тестов на конкурентный доступ к хипу из нескольких потоков, и не можем сказать, как поведут себя конкретные реализации в этом случае. Возможно, в будущем мы проведем такой тест.
Пока можно сказать, что первенство VC7 несколько омрачается тем, что в многопоточном режиме время повторного выполнения этого теста значительно увеличивается. Но, как уже говорилось, это проблема не VC7 как такового, а W2k.
Кое что о этом тесте мы уже сказали. Так что Delphi мы больше трогать не будем. Поговорим лучше об остальных участниках. К сожалению, результаты этого теста нельзя назвать удовлетворительными, так как мы не смогли обеспечить одинаковые условия сравнения даже для C++-компиляторов. Дело в том, что подключение MFC к не Microsoft-овским компиляторам - это непростая задача, на которую попросту не было времени. Особенно это было сложно с gcc. Поэтому мы приняли решение воспользоваться более переносимой реализацией из STL - std::string. Но и тут не все так просто. Существует множество реализаций STL, и наши подопытные (а именно bcc и gcc) использовали разные версии. Причем у bcc оказался самый древний и медленный вариант от HP. Однако результаты теста имеют право на жизнь, так как скорее всего пользоваться программист будет тем, что имеется под рукой.
VC7, как и в других тестах, несколько улучшил свой результат, но до лидеров не достал.
Bcc показал совсем плохой результат, но как уже говорилось, возможно это в большей степени зависит не от качества оптимизации, а от качества реализации STL.
Еще одним тестом, в котором выигрывает не сильнейший, а хитрейший, стал Если у кого-нибудь на примете есть алгоритм, удовлетворяющий условиям, перечисленным выше, большая просьба связаться с нами по e-mail (tcs@optim.ru), и передать этот алгоритм.
Хочется поблагодарить Александра Корсукова, Булата Юнусова и Игоря Ткачева, помогавших (своим личным трудом и советами) в переносе кода под gcc и bcc.
Тесты
Вызов метода объекта (Method call)
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 1.44 с разворотом циклов 0.37 с "полным" разворотом циклов 0.36 Borland C++ 5.5 9.39 VC.Net (v 7.0) beta 2 С inline-подстановкой 0.00 Без inline-подстановки 0.00 Вызов виртуального метода объекта (virtual method call)
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 18.78
с разворотом циклов 18.67
с "полным" разворотом циклов 18.66
Borland C++ 5.5 8.90
VC.Net (v 7.0) beta 2 С inline-подстановкой 5.77
Без inline-подстановки 5.77
Доступ к члену класса
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 4.01
с разворотом циклов 0.40
с "полным" разворотом циклов 0.40
Borland C++ 5.5 6.79
VC.Net (v 7.0) beta 2 С inline-подстановкой 1.44
Без inline-подстановки 4.33
Quick Sort (быстрая сортировка)
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 9.36 с разворотом циклов 9.95 с "полным" разворотом циклов 9.97 Borland C++ 5.5 10.71 VC.Net (v 7.0) beta 2 С inline-подстановкой 8.08 Без inline-подстановки 8.10 Пузырьковая сортировка
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 5.36 с разворотом циклов 4.81 с "полным" разворотом циклов 4.81 Borland C++ 5.5 5.05 VC.Net (v 7.0) beta 2 С inline-подстановкой 5.00 Без inline-подстановки 5.00 Подсчет p (целочисленные вычисления)
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 4.10 с разворотом циклов 3.80 с "полным" разворотом циклов 3.80 Borland C++ 5.5 6.84 VC.Net (v 7.0) beta 2 С inline-подстановкой 3.77 Без inline-подстановки 3.77 Tree sort
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 12.63 с разворотом циклов 12.56 с "полным" разворотом циклов 12.71 Borland C++ 5.5 11.54 VC.Net (v 7.0) beta 2 С inline-подстановкой 11.34 Без inline-подстановки 11.37
procedure TForm1.FormCreate(Sender: TObject);
begin
IsMultiThread := True;
end;
String-тест
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 5.12 с разворотом циклов 5.39 с "полным" разворотом циклов 5.13 Borland C++ 5.5 15.80 VC.Net (v 7.0) beta 2 С inline-подстановкой 4.11 Без inline-подстановки 4.10 Float-Тест
Компилятор Опции Время (с) GNU C++ 2.95.3-7 (mingw) Без разворота циклов 14.46 с разворотом циклов 3.34 с "полным" разворотом циклов 3.36 Borland C++ 5.5 15.12 VC.Net (v 7.0) beta 2 С inline-подстановкой 12.26 Без inline-подстановки 12.2 Благодарности