十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

SerenityOS 构建性能剖析指南:从 Ninja 日志到编译器火焰图的三种实践路径

SerenityOS 构建性能剖析指南:从 Ninja 日志到编译器火焰图的三种实践路径 SerenityOS 构建性能剖析指南从 Ninja 日志到编译器火焰图的三种实践路径【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenitySerenityOS 是一个从零构建的类 Unix 操作系统代码仓库横跨 AK、Kernel 与 Userland 三大核心区域包含数千个 C 源文件编译一次完整系统通常需要数分钟甚至更久。本文以官方文档 Documentation/BuildProfilingInstructions.md 为骨架系统讲解三种获取编译耗时信息的方法整体计时、Ninja 日志逐文件分析、以及 GCC/Clang 编译器内部阶段剖析。读完本文你将能够定位拖慢构建的热点源文件并借助火焰图等可视化工具制定针对性的加速方案。三种方法速览官方文档给出的三种方法信息粒度由粗到细方法命令 / 工具粒度适用场景整体计时time ninja install整个构建快速确认改动后构建总耗时是否恶化Ninja 日志分析.ninja_logninjatracing Speedscope单个.cpp文件找出编译最慢的文件作为优化目标编译器阶段剖析-ftime-report/-ftime-report-details单个文件内的编译器 pass深入理解文件内部哪一阶段解析、模板实例化等最耗时三者的关系是层层下钻先看总量再定位文件最后分析文件内部的耗时构成。方法一用time给整个构建计时最直接的方式是让 Shell 的time内建命令包裹构建命令time ninja install这会输出构建总耗时包括 real / user / sys 三列分别对应墙钟时间、用户态 CPU 时间和内核态 CPU 时间。它适合在改动前后做粗粒度对比——例如验证把某个头文件的#include拆掉之后整体构建快了多少。SerenityOS 的实际构建流程中ninja install会编译内核、用户态库与服务并最终组装出可启动的磁盘镜像。仓库根目录的 CMakeLists.txt 中定义了诸如install-native-partition等自定义目标整个构建树由 CMake 生成、Ninja 执行因此 Ninja 自身的日志机制成为下一步剖析的基础。方法二读取 Ninja 日志逐文件定位编译热点Ninja 构建系统会在当前目录生成一份日志文件.ninja_log其中记录了每个构建命令也就是每个.cpp文件的编译的起止时间。这份日志的价值在于它直接告诉你哪个源文件消耗了最多的编译时间而这些文件就是加速整体构建的优先目标。前置条件文档明确指出转换日志需要ninjatracing脚本。它可以把.ninja_log转换为多种 profile 查看器可读的 JSON 格式。使用前需要满足三个条件Python 3 可用ninjatracing脚本以python作为解释器调用而你的系统上 Python 3 通常安装为python3。两种解决方式任选其一创建python指向python3的符号链接直接把ninjatracing文件首行的解释器改为python3。可执行权限确保ninjatracing具有执行权限例如通过chmod x但请注意本文仓库为只读此操作应在你自己的构建环境中完成。加入 PATH将脚本所在目录加入PATH或放在一个方便手动调用的位置。操作步骤由于缓存会跳过未变更文件的编译、导致日志缺失真实耗时必须先清理构建产物和 ccache 缓存保证每个文件都被完整编译一次ninja clean ccache --clear随后正常执行构建ninja日志默认写入当前目录的.ninja_log。在调用 ninja 的同一目录下执行转换ninjatracing .ninja_log trace.json最后把trace.json拖入 Speedscope 或任何其他兼容的火焰图可视化工具即可直观看到每个文件的编译耗时分布。仓库中的 ccache 支持为什么清理缓存是必要的SerenityOS 的构建系统默认就集成了 ccache 支持。仓库中的 Meta/CMake/setup_ccache.cmake 会在检测到ccache可执行程序时自动将其设置为CMAKE_C_COMPILER_LAUNCHER与CMAKE_CXX_COMPILER_LAUNCHERfind_program(CCACHE_PROGRAM ccache) if(CCACHE_PROGRAM) foreach(compiler ${COMPILERS}) ... set(${compiler}_LAUNCHER ${CCACHE_PROGRAM} CACHE FILEPATH ...) endforeach() endif()这意味着日常增量构建中大量文件会命中 ccache 而跳过真实编译——这正是剖析前必须执行ninja clean和ccache --clear的原因只有强制全量重编.ninja_log中的时间数据才具有真实意义。.ninja_log与ninjatracing的协作原理Ninja 的日志机制本身是内置的每完成一条构建边Ninja 就把该边对应的输出文件、命令起始与结束的微秒级时间戳写入.ninja_log。ninjatracing读取这些条目将其转换为 Chrome Trace Event 格式的 JSONtraceEvents数组而 Speedscope 这类火焰图查看器恰好消费该格式从而把文件 → 时间的二维数据渲染为可视化火焰图。整个过程不依赖任何编译器改动因此对 GCC 和 Clang 都通用。方法三-ftime-report——透视编译器内部各阶段耗时如果想知道单个文件内部哪个编译阶段最耗时例如模板实例化、名称查找、优化就需要在编译器中开启计时标志。GCC 输出示例为 GCC 添加-ftime-report标志后每个被编译的文件都会输出一张阶段耗时表。以下是官方文档给出的实际输出示例对应一个Kernel/CommandLine.cpp的编译Time variable usr sys wall GGC phase setup : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 1326k ( 2%) phase parsing : 0.57 ( 61%) 0.19 ( 83%) 1.63 ( 65%) 59M ( 74%) phase lang. deferred : 0.10 ( 11%) 0.03 ( 13%) 0.30 ( 12%) 8761k ( 11%) phase opt and generate : 0.23 ( 25%) 0.01 ( 4%) 0.48 ( 19%) 10M ( 13%) phase last asm : 0.03 ( 3%) 0.00 ( 0%) 0.08 ( 3%) 539k ( 1%) |name lookup : 0.11 ( 12%) 0.01 ( 4%) 0.25 ( 10%) 2004k ( 2%) |overload resolution : 0.08 ( 9%) 0.00 ( 0%) 0.26 ( 10%) 7900k ( 10%) dump files : 0.02 ( 2%) 0.00 ( 0%) 0.00 ( 0%) 0 ( 0%) callgraph construction : 0.04 ( 4%) 0.00 ( 0%) 0.06 ( 2%) 2677k ( 3%) callgraph optimization : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 4752 ( 0%) callgraph functions expansion : 0.15 ( 16%) 0.00 ( 0%) 0.32 ( 13%) 6267k ( 8%) callgraph ipa passes : 0.03 ( 3%) 0.01 ( 4%) 0.08 ( 3%) 1413k ( 2%) ipa inheritance graph : 0.00 ( 0%) 0.00 ( 0%) 0.02 ( 1%) 3760 ( 0%) ipa profile : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 0 ( 0%) trivially dead code : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 224 ( 0%) df reg dead/unused notes : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 104k ( 0%) alias analysis : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 70k ( 0%) preprocessing : 0.06 ( 6%) 0.03 ( 13%) 0.16 ( 6%) 1365k ( 2%) parser (global) : 0.04 ( 4%) 0.04 ( 17%) 0.13 ( 5%) 6894k ( 8%) parser struct body : 0.09 ( 10%) 0.03 ( 13%) 0.20 ( 8%) 9020k ( 11%) parser function body : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 83k ( 0%) parser inl. func. body : 0.03 ( 3%) 0.01 ( 4%) 0.05 ( 2%) 1567k ( 2%) parser inl. meth. body : 0.11 ( 12%) 0.03 ( 13%) 0.30 ( 12%) 10M ( 13%) template instantiation : 0.27 ( 29%) 0.08 ( 35%) 0.89 ( 36%) 25M ( 32%) constant expression evaluation : 0.01 ( 1%) 0.00 ( 0%) 0.01 ( 0%) 356k ( 0%) constraint satisfaction : 0.01 ( 1%) 0.00 ( 0%) 0.02 ( 1%) 130k ( 0%) early inlining heuristics : 0.00 ( 0%) 0.00 ( 0%) 0.02 ( 1%) 21k ( 0%) inline parameters : 0.01 ( 1%) 0.00 ( 0%) 0.03 ( 1%) 146k ( 0%) integration : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 564k ( 1%) tree CFG cleanup : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 5768 ( 0%) tree SSA other : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 13k ( 0%) tree operand scan : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 429k ( 0%) tree CCP : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 18k ( 0%) expand : 0.01 ( 1%) 0.00 ( 0%) 0.03 ( 1%) 1303k ( 2%) varconst : 0.00 ( 0%) 0.00 ( 0%) 0.04 ( 2%) 6744 ( 0%) forward prop : 0.01 ( 1%) 0.00 ( 0%) 0.02 ( 1%) 3520 ( 0%) CSE : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 1144 ( 0%) loop fini : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 0 ( 0%) branch prediction : 0.00 ( 0%) 0.01 ( 4%) 0.00 ( 0%) 20k ( 0%) combiner : 0.01 ( 1%) 0.00 ( 0%) 0.02 ( 1%) 138k ( 0%) integrated RA : 0.01 ( 1%) 0.00 ( 0%) 0.01 ( 0%) 1112k ( 1%) LRA reload inheritance : 0.00 ( 0%) 0.00 ( 0%) 0.02 ( 1%) 13k ( 0%) LRA create live ranges : 0.00 ( 0%) 0.00 ( 0%) 0.01 ( 0%) 8568 ( 0%) reload CSE regs : 0.01 ( 1%) 0.00 ( 0%) 0.02 ( 1%) 100k ( 0%) final : 0.00 ( 0%) 0.00 ( 0%) 0.02 ( 1%) 323k ( 0%) variable output : 0.01 ( 1%) 0.00 ( 0%) 0.00 ( 0%) 15k ( 0%) symout : 0.09 ( 10%) 0.00 ( 0%) 0.20 ( 8%) 13M ( 17%) variable tracking : 0.00 ( 0%) 0.00 ( 0%) 0.04 ( 2%) 471k ( 1%) var-tracking dataflow : 0.02 ( 2%) 0.00 ( 0%) 0.03 ( 1%) 18k ( 0%) var-tracking emit : 0.00 ( 0%) 0.00 ( 0%) 0.04 ( 2%) 117k ( 0%) rest of compilation : 0.01 ( 1%) 0.00 ( 0%) 0.03 ( 1%) 1258k ( 2%) TOTAL : 0.93 0.23 2.50 79M [24/3139] Building CXX object Kernel/CMakeFiles/Kernel.dir/CommandLine.cpp.o如何读懂这张表输出表的四列含义分别为usr / sys用户态与内核态 CPU 时间秒wall墙钟时间秒GGCGCC 的垃圾收集器分配的内存量如59M、25M等。结合上述示例可以观察到 SerenityOS 这类重度模板化 C 项目的典型特征phase parsing解析阶段占墙钟 65%是整个编译的大头解析阶段内部template instantiation模板实例化一项就占 36%且 GGC 内存高达 25M——这是模板元编程密集代码的标志|name lookup名称查找与|overload resolution重载决议合计约占 20%典型地反映了对 STL 与 AK 容器模板的深度依赖symout符号输出也占到 10%对应内核这类大型二进制的调试符号生成开销。理解这些阶段后优化方向就有了依据例如通过减少模板实例化深度、拆分过大的头文件、或降低调试符号生成开销SerenityOS 默认编译选项为-g1见 Meta/CMake/serenity_compile_options.cmake都能显著压缩解析与模板实例化耗时。如何为 SerenityOS 构建开启该标志文档给出的方法是编辑仓库根目录的CMakeLists.txt在约第 220 行的编译选项列表中加入add_compile_options(-ftime-report)对照当前仓库编译选项的注入点在 CMakeLists.txt 的include(serenity_compile_options)其具体内容位于 Meta/CMake/serenity_compile_options.cmake该文件又引入 Meta/CMake/common_compile_options.cmake 的公共选项如-Wall -Wextra -Werror与 C26 标准。因此两种等效做法在根CMakeLists.txt的include(serenity_compile_options)附近即文档所说约 220 行区域添加add_compile_options(-ftime-report)或直接向Meta/CMake/serenity_compile_options.cmake追加一行add_compile_options(-ftime-report)使其对所有子目录生效。若使用 Ladybird / Lagom 构建在主机上运行浏览器与测试库的构建系统则应修改 Meta/CMake/lagom_compile_options.cmake其中同样通过include(.../common_compile_options.cmake)复用公共选项且区分 Debug-Og -ggdb3与 Release-O2 -g1两种模式。关于-ftime-report-details与 Clang文档还提到两点需要注意-ftime-report-details可以一并添加它会输出更细粒度的阶段明细。文档作者注明未实测该标志实际使用时应自行验证输出规模与可用性。Clang 兼容性Clang 同样支持-ftime-report但文档作者同样声明未实测其输出。另外若你在 Clang 下配合-ftime-traceClang 特有的 JSON 计时输出可被 Chrome DevTools 加载可以实现比-ftime-report更精细的 per-pass 可视化——不过这属于 Clang 的补充手段本文以官方文档口径为准。输出量巨大的处理技巧-ftime-report会为每个.cpp文件输出一张上述表格全量构建时输出量非常庞大。实际剖析时建议先通过.ninja_log方法二定位最慢的文件再只针对它单独重编以捕获其-ftime-report输出ninja Kernel/CMakeFiles/Kernel.dir/CommandLine.cpp.o这样输出中只含该文件的计时表便于阅读或将构建输出重定向到文件后再检索ninja /tmp/build-report.txt 21综合实践一套可落地的剖析流程把三种方法组合起来形成完整的构建性能诊断闭环粗测time ninja install记录基线总耗时。定位文件ninja clean ccache --clear ninja随后ninjatracing .ninja_log trace.json用 Speedscope 查看火焰图锁定耗时最高的几个.cpp。深入阶段对热点文件单独编译并开启-ftime-report确认瓶颈是模板实例化、解析还是符号输出。验证优化应用头文件精简、模板实例化减少或编译选项调整后重复步骤 13 对比前后差异。需要特别注意的是官方文档对-ftime-report的定位是取决于你是否理解编译器内部机制通常不推荐作为首要手段——因为其输出面向编译器开发者对多数人而言方法二Ninja 日志 火焰图是性价比最高的切入点。总结本文围绕官方文档 Documentation/BuildProfilingInstructions.md 展开完整覆盖了三种编译耗时剖析手段time ninja install的整体计时、.ninja_logninjatracing Speedscope 的逐文件火焰图分析以及-ftime-report/-ftime-report-details的编译器阶段内部分解并结合仓库中的 CMakeLists.txt、Meta/CMake/serenity_compile_options.cmake、Meta/CMake/lagom_compile_options.cmake 与 Meta/CMake/setup_ccache.cmake 说明了选项注入位置与缓存清理的必要性。按照先总量、再文件、后阶段的路径你就能系统性地找到构建瓶颈为 SerenityOS乃至任何 Ninja GCC/Clang 构建的 C 项目量身定制加速方案。【免费下载链接】serenityThe Serenity Operating System 项目地址: https://gitcode.com/GitHub_Trending/se/serenity创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表