我有一个 SCons 脚本,仅仅是为了发现不需要重新构建而花费了约 10 秒钟的时间,这对于一个规模相对较小的项目来说感觉非常长。读取 SConscript 本身只需要一两秒钟,大部分时间都花在了:
scons: Building targets ...
步骤。
我如何找出scons
在这一点上到底在做什么?还有哪些关于编写快速SCons脚本的通用建议可以提供?
我有一个 SCons 脚本,仅仅是为了发现不需要重新构建而花费了约 10 秒钟的时间,这对于一个规模相对较小的项目来说感觉非常长。读取 SConscript 本身只需要一两秒钟,大部分时间都花在了:
scons: Building targets ...
步骤。
我如何找出scons
在这一点上到底在做什么?还有哪些关于编写快速SCons脚本的通用建议可以提供?
(直接从http://www.scons.org/wiki/GoFastButton盗来)
执行命令“scons --max-drift=1 --implicit-deps-unchanged”将尽可能快地构建您的项目。
或者:
另一个加快速度的技巧是在共享库已修改但未重建时避免重新链接程序。请参阅 SharedLibrarySignatureOverride
scons会通过md5-sums计算文件是否已更改,因此它几乎会对所有文件进行md5sums。
您可以告诉它只使用时间戳来决定何时重新构建,而不必每次都对所有文件进行MD5sums,就像“make”一样,这应该可以加快速度。但是它可能更加脆弱。例如,如果一个文件在上次构建的1秒内发生了更改,scons将不会注意到。使用
env.Decider('timestamp-newer')
还有一种MD5-timestamp方法,它会先检查时间戳,然后使用Md5比较内容是否已经改变,如果时间戳更新了,就会执行比较操作。
env.Decider('MD5-timestamp')
scons -j 2
在我的双核电脑上,使用-j 3参数通常可以获得最大的加速效果。
通过在调用scons时使用--debug参数,可以获得关于scons正在执行的一些输出信息,有关各种选项,请参阅man页面。
为了找出SCons为什么慢,我进行了一些试验和错误,目前发现以下结果(具体结果当然会因SCons脚本的结构和复杂性而异):
CacheDir()
没有明显的负面影响。Decider()
只有非常微小的影响,不值得费心。variant_dir
/VariantDir()
会使构建时间增加约10%。SConstruct
文件本身占完整scons调用的约10%。可能的解决方案:
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脚本的评估。
SCons 创建第一个 Environment
时会进行一系列的查找以确定有哪些工具可用。在创建第一个 env
之前,在 DefaultEnvironment
中明确选择工具,可以避免不必要的检查并加快 SCons 的速度。
DefaultEnvironment(tools=[])
在您的SConscript中添加以下内容:
if 'explain' in GetOption("debug"):
Progress('Evaluating $TARGET\n')
并加上 --debug=explain
,运行程序。您将了解SCons花费时间评估的内容。
scons --profile
+ snakeviz
这个组合向我展示了瓶颈在哪里。
--profile
以cProfile
格式输出一个二进制文件,该文件可以在标准库中找到。
snakeviz
是一个非常棒的可视化工具,可以通过GUI快速查看该文件:
scons --profile f.prof
pip install -u snakeviz
snakeviz f.prof
你可以将鼠标悬停在每个框上,以查看包含该函数的文件的完整路径。
在更一般的Python环境中提出的问题:有没有简单的方法来对Python脚本进行基准测试?
--debug
+ ts -s
这并没有解决我的具体问题,但通常可以给你一些想法:
--debug
标志,或所有看起来有趣的标志ts -s
管道传递它,显示每行何时出现在stdout上:如何监视Bash中最后输出行是多长时间的每行stdout以进行基准测试?time scons --debug=count,duplicate,explain,findlibs,includes,memoizer,memory,objects,prepare,presub,stacktrace,time |
ts -s | tee f
这是一个样例输出,显示了我在2秒和10秒之间有一个巨大的时间差,这也是我试图关注的地方:
00:00:02 SConscript:/data/gem5/master3/build/ARM/sim/power/SConscript took 1.556 ms
00:00:02 dup: relinking variant 'build/ARM/sim/probe/SConscript' from 'src/sim/probe/SConscript'
00:00:02 Building build/ARM/sim/probe/SConscript with action:
00:00:02 UnlinkFunc(target, source, env)
00:00:02 Building build/ARM/sim/probe/SConscript with action:
00:00:02 LinkFunc(target, source, env)
00:00:02 SConscript:/data/gem5/master3/build/ARM/sim/probe/SConscript took 0.401 ms
00:00:10 SConscript:/data/gem5/master3/build/ARM/tests/opt/SConscript took 98.225 ms
00:00:10 SConscript:/data/gem5/master3/build/ARM/SConscript took 8885.387 ms
00:00:10 SConscript:/data/gem5/master3/SConstruct took 9409.641 ms
00:00:10 scons: done reading SConscript files.
00:00:10 scons: Building targets ...
在scons 3.0.1和Ubuntu 18.04中进行了测试。
另请参阅