У нас есть очень большая программа, которая смешивает C ++ и FORTRAN (извините). Одна из моих проверок привела к резкому замедлению всего приложения (т. Е. В два или более раз) — даже в тех областях кода, на которые не повлияли мои изменения.
Факты:
Почти каждый модуль замедлился на одинаковую величину, даже те, которые не используют мой код.
Исполняемый файл примерно на 6% больше.
Метаданные не были изменены между регистрациями.
IDE / компилятор VS2010 в режиме выпуска.
Некоторые файлы .lib увеличились в два или три раза.
Я посмотрел на один из .lib-файлов, размер которого утроился, и есть только два изменения:
а) Я включил заголовочный файл большого размера, который, в свою очередь, включает в себя множество других, некоторые из которых содержат умеренно сложный встроенный код. «Дополнительные каталоги включения» изменились с нуля или до 7, так как каждый заголовочный файл включает в себя один или несколько других.
б) я вызвал 4 функции из этого заголовочного файла, но они не вызываются во время запуска, который замедлился (то есть их выполнение нельзя замедлить код, но их включение может быть)
Несмотря на поиск на форумах относительно того, замедляется ли включение заголовочных файлов выполнение (в отличие от компиляции), я не могу найти ни одной соответствующей статьи. Мои вопросы:
? Включает ли любой форма заголовка (декларация или встроенная) замедляет код выполнение?
? Есть ли качественная или количественная разница во включении в соответствии код w.r.t. скорость выполнения (я знаю, что «встроенный» — всего лишь совет компилятору)?
? Каковы корреляции между размером .lib, размером .exe и скоростью выполнения (я ожидаю много разных и противоречивых корреляций здесь)?
? Как вы думаете, улучшит ли мою ситуацию рефакторинг некоторых заголовочных файлов, чтобы им не нужно было включать другие (поместив эти включения в файл .cpp и, таким образом, сократив мои «Дополнительные каталоги включения»)?
Я предполагаю, что последний вопрос — главное в этом вопросе, так как это займет много усилий …
Замедляет ли # включение любой формы заголовка (объявления или встроенного) выполнение кода?
Добавление неиспользуемых объявлений или добавление неиспользуемых встроенных определений не замедляет выполнение. Однако я могу представить несколько вещей, которые могут замедлить выполнение:
Есть ли качественная или количественная разница во включении встроенного кода w.r.t. скорость выполнения (я знаю, что «встроенный» — всего лишь совет компилятору)?
Ну, если код недоступен, он не может быть встроен. Если это так, то это возможно. Обычно компилятор может оценить, сколько вложений сэкономит, а не встроенный, если это не поможет, но иногда он может угадать. В таком случае результат будет сильно отличаться от обычного случая, когда он немного помогает.
Каковы корреляции между размером .lib, размером .exe и скоростью выполнения (я ожидаю много разных и противоречивых корреляций здесь)?
Совершенно другой случай. Встраивание увеличивает размер кода, но может сэкономить много работы на каждом сайте вызовов. Но больший код занимает больше кеша, что замедляет его.
Как вы думаете, улучшит ли мою ситуацию рефакторинг некоторых заголовочных файлов, чтобы им не нужно было включать другие (поместив эти включения в файл .cpp и, таким образом, сократив мои «Дополнительные каталоги включения»)?
Это может или не может. Зависит от фактической причины.
Я предлагаю вам действительно попытаться найти причину. Это почти наверняка вызвано каким-то конкретным фрагментом кода, а не количеством включенного кода. Так что вернитесь к ревизии до изменения и добавьте включенное по крупицам. Сначала включите только самые внутренние заголовки, а затем добавьте заголовки, которые их используют, и так далее, один за другим. Когда вы дойдете до определенного заголовка, который ухудшает ситуацию, попробуйте закомментировать его, пока вы не сузите его до определенного объявления или нескольких из них.
Также возьмите только некоторые функции, где вы наблюдаете снижение производительности. Чем, если вы сузите это и все еще не увидите, что может быть не так, у вас будет что-то, что другие могут воспроизвести проблему, так что вы можете использовать это как новый вопрос.
Изменение заголовочных файлов не может изменить время выполнения, если случайно вы не включите что-то, что встраивает DEBUG или другой диагностический код в получившиеся двоичные файлы.
Это было бы мое предположение, особенно. учитывая изменение размера выходного файла.
Вы используете COM? Ваш включаемый файл изменил STA на MTA или наоборот? Включают ли ваши включаемые файлы в библиотеку, где раньше у вас было динамическое связывание (lib pragma)? Разве include больше не тянет библиотеку, и ваш код больше не динамически связывается? Я повторяю Стив, включена ли отладочная библиотека?
DUMPBIN может предоставить вам дополнительную информацию о том, что на самом деле было построено. Сравните результаты со старой версией, чтобы увидеть, если что-то выделяется.
ДОПОЛНИТЕЛЬНОЕ РЕДАКТИРОВАНИЕ:
Проверьте использование памяти на тестовом компьютере, проверьте активность подкачки, если есть вероятность того, что ваш больший исполняемый файл превысил пороговое значение.
Один слепой выстрел:
Это может быть проблема с кешем. Встраивание функций и добавление «мертвого» кода в библиотеку приведет к увеличению объема кода и может увеличить количество пропусков кэша во время выполнения вашей программы.
Вы можете убедиться, что это правильный путь, просто отслеживая количество пропусков кэша во время выполнения вашего процесса.
о вашем комментарии:
Сколько стоит 6%?
Если вы переполняете кэш L1 (насколько мне известно, его размер составляет около 32 КБ даже на современных процессорах), вы обмениваете доступ L1 к доступам L2, которые примерно в 2 раза медленнее.
Если вы переполните кэш L2 (может варьироваться от 256 КБ до 2 МБ) и начнете получать доступ к L3, у вас будет 5-кратное замедление при извлечении страниц (вы можете проверить этот вопрос, который дает цифры для ядра i7).
Вот общие пояснения по поводу отсутствия кеша на википедия.
Еще раз, чтобы увидеть, действительно ли это проблема, вы должны отслеживать количество пропущенных кешем ваших процессов во время его выполнения (я думаю, исследователь процесса показывает это, если вы используете Windows, или перфорация если вы используете Linux)
Замедляет ли # включение любой формы заголовка (объявления или встроенного) выполнение кода?
Хорошо, если ваше приложение должно
Это только меняет место, где появляется код, поэтому я считаю, что это ничего не меняет. (ваш код не станет быстрее / медленнее, если вы просто переместите функцию на три строки вверх, не так ли?)
Есть ли качественная или количественная разница во включении встроенного кода w.r.t. скорость выполнения (я знаю, что «inline» — всего лишь совет компилятору)
Может быть. Если вы сравните встроенную и не встроенную функцию, встроенная может оказаться быстрее, потому что ее код будет просто скопирован в соответствующем месте, в то время как обычная будет тратить некоторое время на вызов функции.
Каковы корреляции между размером .lib, размером .exe и скоростью выполнения (я ожидаю много разных и противоречивых корреляций здесь)
Хотя я могу представить себе гипотетическую ситуацию, когда больший файл замедлит скорость, я рискну сказать, что в большинстве случаев корреляции нет.
Ваш исполняемый файл, вероятно, больше, потому что, возможно, вы переопределили некоторые макросы, которые влияют на выполнение (например, отмена определения, которое должно было исключить некоторый код). Это также может привести к снижению производительности (т. Е. Вы не хотите, чтобы какой-то код выполнялся, но это произошло из-за случайного переопределения макроса).
Угадайка вряд ли найдет проблему. Диагноз найдет это.
Если замедление в два раза, это означает, что более медленный код тратит 50% своего времени на выполнение чего-то ненужного, чего раньше не делал.
Это будет очень легко найти.
это это метод, который я использую, потому что он находит проблемы.
Вот пример и вот куча причин почему.
Я предлагаю вам сначала диагностировать проблему в ООН-оптимизированный код.
Затем, когда вы устраните проблему, включите оптимизатор и дайте ему сделать свое дело.
Очень вероятно, что код содержит существенные проблемы, которые вы можете исправить, а оптимизатор — нет.
Независимо от того, что делает оптимизатор, он не облегчает поиск проблем, которые можно исправить.