Как оптимизировать время запуска скрипта SCons? - PullRequest
20 голосов
/ 23 августа 2009

У меня есть скрипт SCons, который занимает около 10 секунд, просто чтобы выяснить, что ничего не нужно перестраивать, что ужасно долго для того, что по сути является довольно маленьким проектом. Чтение самого SConscript занимает всего секунду или две, большую часть времени тратит на:

scons: Building targets ...

шаг.

Как я могу узнать, что именно scons делает на данный момент? И какие еще общие советы можно дать по написанию быстрых скриптов SCons?

Ответы [ 6 ]

26 голосов
/ 22 сентября 2009

(Украдено непосредственно у http://www.scons.org/wiki/GoFastButton)

Команда 'scons --max-drift = 1 --implicit-deps-unchanged' выполнит вашу сборку максимально быстро.

OR

  • env.Decider ('MD5-timestamp'): начиная с SCons 0,98, вы можете установить функцию Decider в среде. MD5-timestamp говорит, что если временная метка совпадает, не пытайтесь повторно MD5ing файла. Это может дать огромные ускорения. См. Справочную страницу для информации.
  • - max-drift: По умолчанию SCons будет вычислять контрольную сумму MD5 для каждого исходного файла в вашей сборке при каждом запуске и будет кэшировать контрольную сумму только после того, как файлу исполнилось 2 дня. Это значение по умолчанию, равное 2 дням, предназначено для защиты от перекоса часов в NFS или системах контроля версий. Вы можете настроить эту задержку, используя --max-drift = SECONDS, где SECONDS - это некоторое количество секунд. Уменьшение SECONDS может улучшить скорость сборки за счет устранения лишних вычислений контрольной суммы MD5. Вместо того, чтобы указывать это в командной строке при каждом запуске, вы можете установить эту опцию в вашем файле SConstruct или SConscript, используя «SetOption ('max_drift', SECONDS)».
  • - неявный-deps-неизмененный: по умолчанию SCons повторно сканирует все исходные файлы на наличие неявных зависимостей (например, заголовок C / C ++ #include), что может быть дорогостоящим процессом. Вы можете указать SCons кэшировать неявные зависимости между вызовами, используя --implicit-deps-unchanged. Используя эти опции, вы даете обещание SCons, что вы не изменили ни одну из неявных зависимостей с момента последнего запуска. Если вы меняете неявные зависимости, то использование --implicit-deps-change приведет к их повторному сканированию и кешированию. (Вы не можете установить эту опцию из файлов SConstruct или SConscript.)
  • - implicit-cache: эта опция указывает SCons разумно кэшировать неявные зависимости. Он пытается определить, изменились ли неявные зависимости со времени последней сборки, и если это так, он пересчитает их. Обычно это медленнее, чем при использовании --implicit-deps-неизмененного, но также более точный. Вместо того, чтобы указывать это в командной строке при каждом запуске, вы можете установить эту опцию в вашем файле SConstruct или SConscript, используя «SetOption ('implicit_cache', 1)».
  • CPPPATH: обычно вы сообщаете Scons о включаемых каталогах, устанавливая переменную конструирования CPPPATH, которая заставляет SCons искать эти каталоги при выполнении неявного сканирования зависимостей, а также включает эти каталоги в командной строке компиляции. Если у вас есть заголовочные файлы, которые никогда или редко изменяются (например, системные заголовки или заголовки времени выполнения C), то вы можете исключить их из CPPPATH и включить их в переменную конструкции CCFLAGS, что заставит SCons игнорировать эти каталоги при сканировании для неявных зависимостей. Тщательная настройка каталогов включения таким способом обычно может привести к значительному увеличению скорости при минимальной потере точности.
  • Избегайте сканирования RCS и SCCS с помощью env.SourceCode (".", None) - это особенно интересно, если в вашей программе используется много заголовков c или c ++, а ваша файловая система удаленная (nfs, samba) .
  • При использовании «BuildDir» используйте его с «duplicate», установленным в 0: «BuildDir (dir1, dir2, duplicate = 0». Это заставит scons вызывать Builders, используя пути к исходным файлам в src_dir и путь имена производных файлов в build_dir. Однако это может вызвать проблемы при сборке, если исходные файлы создаются во время сборки, если какие-либо вызываемые инструменты жестко запрограммированы для помещения производных файлов в тот же каталог, что и исходные файлы.
  • На многопроцессорной машине может быть полезно запускать несколько заданий одновременно - используйте --jobs N (где N - количество процессоров на вашей машине) или "SetOption ('num_jobs', N)" внутри вашего SConstruct или SConscript. На компьютерах с Windows число процессоров доступно в переменной среды NUMBER_OF_PROCESSORS.
  • Если у вас есть несколько десятков определений препроцессора ("-DFOO1 -DFOO2"), вы можете обнаружить, что, используя --profile, SCons тратит много времени в функции subst (), обычно просто добавляя строку -D к определениям снова и снова. Это действительно может замедлить сборки, где ничего не изменилось. С более чем 100 определениями я увидел, что время сборки без всяких усилий сократилось с 35 до 20 секунд, используя идею, описанную в разделе «Кэширование CPPDEFINES» в другом месте на этой странице.

Другой способ ускорить процесс - избежать повторного связывания программ, когда общая библиотека была изменена, но не перестроена. См. SharedLibrarySignatureOverride

9 голосов
/ 23 августа 2009

сканирует md5-суммы файлов, чтобы выяснить, что они изменились, поэтому он в значительной степени md5sums всех ваших файлов.

Вы можете указать ему использовать только временные метки, чтобы решить, что перестраивать, и не нужно каждый раз MD5 подсчитывать все файлы, как это делает make, что должно ускорить процесс. Это может быть более хрупким. например если файл изменился в течение 1 секунды с момента его последнего создания, scons не заметит этого. Используйте

env.Decider('timestamp-newer')

Существует также временная метка MD5, которая сначала проверяет временную метку, а затем сравнивает содержимое с помощью Md5, если оно действительно изменилось, если временная метка новее.

env.Decider('MD5-timestamp')

Еще один простой способ ускорить процесс - запустить параллельное построение с помощью параметра -j.

scons -j 2

В моем 2-ядерном корпусе -j 3 обычно дает наибольшее ускорение.

Некоторая информация о том, что делают scons, может быть сделана с помощью аргумента --debug для вызова scons, см. Страницу руководства для различных опций.

8 голосов
/ 24 августа 2009

Сделали небольшую пробу и ошибку, чтобы выяснить, почему SCons медленный, некоторые выводы пока (точные результаты, конечно, будут варьироваться в зависимости от структуры и сложности сценария SCons):

  • CacheDir() не оказывает заметного негативного воздействия.
  • Decider() оказывает лишь незначительное влияние, не стоит беспокоиться.
  • Использование variant_dir / VariantDir() увеличивает время сборки примерно на 10%.
  • Чтение самого файла SConstruct занимает около 10% от полного вызова scons.
  • Самым большим влиянием, похоже, являются библиотечные зависимости: использование Gtkmm в проекте удвоило время сборки для меня.

Возможные решения:

  • Не выполняйте полное перестроение, а только перестраивайте каталог / модуль, над которым вы работаете (scons -u вместо scons -D).
  • Сделать элементы из SConscript необязательными, поэтому их можно перестраивать только при вызове вручную.
  • Используйте флаг компилятора -isystem для библиотечных включений вместо -I, это изменение само по себе сократило время сборки с 10,5 до 6 секунд для меня, это можно легко сделать с помощью небольшого вызова sed:

    env.ParseConfig('pkg-config --cflags --libs gtkmm-2.4 | sed "s/-I/-isystem/g"')

    Не совсем уверен, почему это работает, я предполагаю, что он сокращает зависимости, которые выводит gcc, и, таким образом, в свою очередь, зависимости, которые scons отслеживает.

Использование CacheDir() и scons -j N, конечно, также очень рекомендуется, но только ускоряет фактическое построение, а не оценку самого скрипта SCons.

7 голосов
/ 30 сентября 2014

Перемещение сторонних включений из CPPPATH в CCFLAGS имело огромное значение. Для нашего проекта с 12 внешними включаемыми каталогами (включая boost и python) компиляция бездействовала с 30 секунд до 3 секунд - ускорение в 10 раз.

5 голосов
/ 02 мая 2014

Когда SCons создает первый Environment, он выполняет серию поисков, чтобы увидеть, какие инструменты доступны. Вы можете избежать ненужных проверок и ускорения SCons, явно выбрав инструменты в DefaultEnvironment перед созданием вашего первого env.

DefaultEnvironment(tools=[])
2 голосов
/ 05 апреля 2017

Добавьте в свой SConscript что-то вроде

if 'explain' in GetOption("debug"):
    Progress('Evaluating $TARGET\n')

и запустить с --debug=explain. Вы увидите, сколько SCons тратит время на оценку

...