Получение достоверных контрольных показателей — это половина дела, а другая половина — правильная их интерпретация, изучение чего-то нового и умение их применять.
100-кратная разница между отладочной и обычной сборками меня удивила, поэтому я решил копнуть глубже.
В результате я лучше усвоил, что происходит в отладке; Искал различия между студиями 2005 и 2008 годов (не нашел); Разобрался как ускорить отладочную сборку в 3 раза за пару минут (блокируемся против удара в спину); методом «бери и беги» я получил результаты, отличающиеся от авторских в 3,5 раза (адская мощь х64 в действии!); и ради интереса я сравнил плохой, бесполезный недовектор с хорошим (плохой оказался до 100 раз быстрее).
Подробности под катом.
Начну со ссылок на источники, а то потом тяжело искать.
Начальное сообщение , их тестовый код , мой тестовый код .
Устранив тряску, я вернулся к исходному вопросу: тормоза тормозят более чем в 100 раз, откуда они берутся? Чужой тест — это хорошо, но я написал свой и прогнал его более привычно.
Создавать проект было лениво, компилировать из командной строки гораздо быстрее.
cl2005 /O2 /EHsc 1.cpp
std it++ res=49995000, 28.5 msec
std ++it res=49995000, 28.6 msec
my res=49995000, 19.0 msec
cl2005 /EHsc 1.cpp
std it++ res=49995000, 534.2 msec
std ++it res=49995000, 437.6 msec
my res=49995000, 69.9 msec
Упс.
Результаты, правда, разные: у тех ребят в 30 раз медленнее, у меня — всего в 10. У тех ребят постинкремент замедляется в 3 раза, у меня — около 20%.
Что я делаю не так? Неужели различия между компилятором и запрещенной библиотекой настолько серьезны? Что ж, давайте установим 2008 и проверим.
cl2008 /O2 /EHsc 1.cpp
std it++ res=49995000, 64.3 msec
std ++it res=49995000, 63.4 msec
my res=49995000, 19.0 msec
cl2008 /EHsc 1.cpp
std it++ res=49995000, 732.1 msec
std ++it res=49995000, 678.8 msec
my res=49995000, 70.0 msec
Хм.
Отличия действительно есть, только в обратную сторону: релизная сборка VS 2005, правда, была в три раза быстрее.
Есть улучшения; Судя по всему, SCL в студии номер 2008 стал раза в три безопаснее, может быть.
с _SECURE_SCL 0 скорость такая же.
(Забегая вперед, большинство других тестов тоже практически такие же.
) Что еще я делаю не так? Компилятор теперь тот же, std::vector вроде тот же, вывод понятен: компилирую неправильно.
Я имею в виду, что ключи компилятора расходятся.
Смотрим решение, там довольно разросшаяся командная строка.
/Od /D "WIN32" /D "_DEBUG" /D "_CONSOLE" /D "_UNICODE" /D "UNICODE" /Gm /EHsc /RTC1 /MDd /Fo"Debug\\" /Fd"Debug\vc90.pdb" /W3 /nologo /c /ZI /TP /errorReport:prompt
Благодаря революционному чутью и грубой силе можно быстро выбросить неважные ключи и оставить важные.
Есть три важных ключа: а) /MDd, б) /RTC1, в) /ZI. Результаты выглядят следующим образом.
cl2008 /Od /EHsc /MDd 1.cpp
std it++ res=49995000, 6026.1 msec
std ++it res=49995000, 1953.9 msec
my res=49995000, 66.5 msec
cl2008 /Od /EHsc /MDd /RTC1 1.cpp
std it++ res=49995000, 7572.0 msec
std ++it res=49995000, 2385.3 msec
my res=49995000, 101.8 msec
cl2008 /Od /EHsc /MDd /RTC1 /ZI 1.cpp
std it++ res=49995000, 18722.0 msec
std ++it res=49995000, 7131.8 msec
my res=49995000, 511.9 msec
Ну а теперь все как у людей: обход вектора тормозит как гад, а постинкремент начал тормозить.
Хороший! Вы можете понять, что происходит. За пару минут чтения кл/? Раскрываются три простые, понятные вещи (по одной на ключ), которые пока еще новые (см.
хорошо забытые старые) и потому удивительные.
/MDd связал библиотеку отладки (что не важно) и автоматически включил /D _DEBUG (что важно).
Из-за этого в SCL был включен дополнительный пакет проверок в дополнение к включенным _SECURE_SCL, который успешно замедлил пост-инкремент в 8 раз, а пре-инкремент - в жалкие 3 раза.
/RTC1 включает проверки на подделку стека и неинициализированные переменные.
Если пройти дизассем в отладчике, то можно увидеть, что во внутреннем цикле происходит пять вызовов разных функций (++, !=, * и два деструктора).
Каждый вызов надо проверять: а вдруг он примет и как разобьет стек! Для этого в стек помещается чуть менее 256 байт маркерного материала для каждого (каждого) вызова того или иного оператора, перегруженного в STL. Пока-пока, еще 20% уже не самой лучшей производительности.
/ZI, однако, превосходит всех и забирает банк домой.
Это «Изменить и продолжить».
Исправление и перезапуск программы на лету наверное удобно (сам не знаю, не пользуюсь).
За удобство надо платить и цена еще в 3 раза превышает тормоза.
В общей сложности в дебаге постинкремент тормозит эпик в 291 раз (!!!) по сравнению с релизом.
Сразу возникает вопрос: почему у меня целых 291 раз, а у этих ребят только 95?! Собираю исходный тест, терпения ждать конца не хватает, уменьшаю счет в 10 раз, время в голове умножаю на 10. Получается, что it++, x86, release: 1.00
++it, x86, release: 1.00
it++, x86, debug: 275.7
++it, x86, debug: 101.9
it++, x64, release: 0.87779
++it, x64, release: 0.87753
it++, x64, debug: 83.2849
++it, x64, debug: 27.1557
Судя по цифрам, в релизе с моего х86 взяли подоходный налог в размере 13%, а в дебаге меня полностью ограбили, оставив только трусы, носки и тапочки.
Исчезающе обидно, но это нормально.
Я все равно от ХР не откажусь, семерка для меня сложна, слишком аэропрозрачна, плюс ждем второй сервиспак.
По результатам понятно, кто виноват в адских тормозах отладочной сборки.
Он потребляет _SECURE_SCL чуть больше 2 раз, отключая оптимизацию 5 раз, от 3 раз (++it) до 8 раз (it++) потребляет проверки под _DEBUG, 1,2 раза выбрасывает /RTC, а с финальным аккордом выбрасывает /ZI еще до 3 раз, итого 2*5*8*1,2*3=288, курить по крупинке, весь код в.
проверки, замедления 300 (триста) раз.
Конечно, вы едите курицу руками.
Из вечных трех теперь остался только один вопрос: что делать? В общем, можно многое сделать, но это займет много времени.
Однако за 2 минуты можно сделать 2 полезных дела.
Bo1x, если принять волевое решение не использовать Edit and Continue (то есть, если это вообще работает на вашем проекте) и генерировать обычные советские PDB, то он начинает работать в 3 раза быстрее, если не во все 5 раз.
Чеки Bo2x, /RTC — это, конечно, не круто.
Однако! Чтение MSDN открывает интересную прагму runtime_checks. Те.
Вы можете отключить эти проверки индивидуально для особо частых функций в проекте или для всего STL. Окружаем внешний раздел include двумя линиями и наслаждаемся.
#pragma runtime_checks("",off)
.
#pragma runtime_checks("",restore)
Мы возвращаем свои честные 6 секунд вместо 18 секунд при использовании it++, 2 секунды вместо 7 секунд при использовании ++it. Вывод о необходимости использования ++ убедительно подтверждается.
Отладочная сборка ускорена примерно в 3 раза.
Выгода! Пробуем применить полученные знания к исходному тесту, получается аналогично.
По крайней мере на старом добром x86. vanilla
it++, x86, debug: 275.7
++it, x86, debug: 101.9
#pragma runtime_checks, /Zi instead of /ZI
it++, x86, debug: 102.2
++it, x86, debug: 30.0
Плохой, кривой, никчемный и примитивный недовектор, который вообще ничего не умеет, показывает в дебаге свои честные 0,066 секунды, т.е.
В 90 раз быстрее, чем it++, или в 30 раз быстрее, чем ++it. Раз 100 в начале поста я соврал, округлили.
У него всего одна проверка: корректность индекса при доступе (которая, однако, покрывает примерно 99% необходимых проверок от вектора); фокус с пре- и пост-инкрементами отсутствует вместе с итераторами.
Это ничего не значит. Автор ни на что не намекает. Бенчмарк явно синтетический.
Вектор был написан буквально за 3 минуты и функционал соответствующий.
не существует по сравнению с STL. Скорость отладочной сборки не обязательно важна; может потребоваться дополнительная проверка; скорость развития всегда важна для всех; Профайлер всегда скажет вам правду.
Помните про _SECURE_SCL, про _DEBUG, про ключи компилятора, про #pragma runtime_checks. Эффект, ну, может быть ошеломляющим.
(Лично меня убила разница в 300 раз.
А разница в 3-5 раз из-за /ЗИ вместо /Зи после этого тоже съела труп.
«Я знал об этом, но не догадался.
») Правильные ориентиры для вас.
И быстрая отладка.
Теги: #C++ #бенчмаркинг #отладка #C++
-
Сопротивление Бесполезно
19 Oct, 24 -
Дизайн Роботов В Planet Of The Eyes
19 Oct, 24 -
5 Приемов Написания Игры
19 Oct, 24 -
Вышла Вторая Альфа-Версия Ubuntu 9.04
19 Oct, 24 -
Приключения Gigabyte В России
19 Oct, 24 -
Вы Используете Монопроект?
19 Oct, 24 -
Гугл Калькулятор На Русском Языке
19 Oct, 24