将螺旋桨与 Linux 内核一起使用

在使用 Clang 编译器时,这可以为内核启用螺旋桨构建支持。螺旋桨是一种配置文件引导优化 (PGO) 方法,用于优化二进制可执行文件。与 AutoFDO 类似,它利用硬件采样来收集关于二进制文件中不同代码路径执行频率的信息。与 AutoFDO 不同,这些信息在链接阶段之前立即使用,以优化函数内部和跨函数的块布局等。

关于采用螺旋桨优化的一些重要注意事项

  1. 虽然它可以作为独立的优化步骤使用,但强烈建议在 AutoFDO、AutoFDO+ThinLTO 或 Instrument FDO 之上应用螺旋桨。本文档的其余部分假设了这种模式。

  2. 螺旋桨在 AutoFDO/AutoFDO+ThinLTO/iFDO 之上使用了另一轮分析。整个构建过程包括“build-afdo - train-afdo - build-propeller - train-propeller - build-optimized”。

  3. 螺旋桨需要 LLVM 19 或更高版本才能使用 Clang/Clang++ 和链接器 (ld.lld)。

  4. 除了 LLVM 工具链之外,螺旋桨还需要一个分析转换工具:https://github.com/google/autofdo,版本必须在 v0.30.1 之后:https://github.com/google/autofdo/releases/tag/v0.30.1

螺旋桨优化过程包括以下步骤

  1. 初始构建:像往常一样构建 AutoFDO 或 AutoFDO+ThinLTO 二进制文件,但使用一组编译时/链接时标志,以便在内核二进制文件中创建一个特殊的元数据部分。该特殊部分仅供分析工具使用,它不是运行时镜像的一部分,也不会更改内核运行时文本段。

  2. 分析:然后,使用代表性工作负载运行上述内核,以收集执行频率数据。此数据使用硬件采样通过 perf 收集。螺旋桨在支持高级 PMU 功能(如 Intel 机器上的 LBR)的平台上最有效。此步骤与为 AutoFDO 分析内核相同(确切的 perf 参数可能不同)。

  3. 螺旋桨配置文件生成:Perf 输出文件通过离线工具转换为一对螺旋桨配置文件。

  4. 优化构建:像往常一样构建 AutoFDO 或 AutoFDO+ThinLTO 优化二进制文件,但使用编译时/链接时标志来获取螺旋桨编译时和链接时配置文件。此构建步骤使用 3 个配置文件 - AutoFDO 配置文件、螺旋桨编译时配置文件和螺旋桨链接时配置文件。

  5. 部署:优化的内核二进制文件部署并在生产环境中使用,从而提高性能并减少延迟。

准备工作

使用以下配置内核

CONFIG_AUTOFDO_CLANG=y
CONFIG_PROPELLER_CLANG=y

自定义

默认的 CONFIG_PROPELLER_CLANG 设置涵盖螺旋桨构建的内核空间对象。但是,可以通过将类似于以下行的代码添加到相应的内核 Makefile 中来为单个文件和目录启用或禁用螺旋桨构建

  • 对于启用单个文件(例如 foo.o)

    PROPELLER_PROFILE_foo.o := y
    
  • 对于启用一个目录中的所有文件

    PROPELLER_PROFILE := y
    
  • 对于禁用一个文件

    PROPELLER_PROFILE_foo.o := n
    
  • 对于禁用一个目录中的所有文件

    PROPELLER__PROFILE := n
    

工作流程

这是一个构建 AutoFDO+螺旋桨内核的工作流程示例

  1. 假设已按照 AutoFDO 文档中的说明收集了 AutoFDO 配置文件,请使用 AutoFDO 和螺旋桨构建配置在主机上构建内核

    CONFIG_AUTOFDO_CLANG=y
    CONFIG_PROPELLER_CLANG=y
    

    $ make LLVM=1 CLANG_AUTOFDO_PROFILE=<autofdo-profile-name>
    
  2. 将内核安装在测试机器上。

  3. 运行负载测试。perf 中的“-c”选项指定采样事件周期。我们建议为此目的使用合适的素数,例如 500009。

    • 对于 Intel 平台

      $ perf record -e BR_INST_RETIRED.NEAR_TAKEN:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
      
    • 对于 AMD 平台

      $ perf record --pfm-event RETIRED_TAKEN_BRANCH_INSTRUCTIONS:k -a -N -b -c <count> -o <perf_file> -- <loadtest>
      

    请注意,您可以重复上述步骤以收集多个 <perf_file>。

  4. (可选)将原始 perf 文件下载到主机。

  5. 使用 create_llvm_prof 工具 (https://github.com/google/autofdo) 生成螺旋桨配置文件。

    $ create_llvm_prof --binary=<vmlinux> --profile=<perf_file>
                       --format=propeller --propeller_output_module_name
                       --out=<propeller_profile_prefix>_cc_profile.txt
                       --propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
    

    “<propeller_profile_prefix>”可以是类似“/home/user/dir/any_string”的内容。

    此命令生成一对螺旋桨配置文件:“<propeller_profile_prefix>_cc_profile.txt”和“<propeller_profile_prefix>_ld_profile.txt”。

    如果在上一步中收集了多个 perf_file,您可以创建一个临时列表文件“<perf_file_list>”,其中每行包含一个 perf 文件名,并运行

    $ create_llvm_prof --binary=<vmlinux> --profile=@<perf_file_list>
                       --format=propeller --propeller_output_module_name
                       --out=<propeller_profile_prefix>_cc_profile.txt
                       --propeller_symorder=<propeller_profile_prefix>_ld_profile.txt
    
  6. 使用 AutoFDO 和螺旋桨配置文件重建内核。

    CONFIG_AUTOFDO_CLANG=y
    CONFIG_PROPELLER_CLANG=y
    

    $ make LLVM=1 CLANG_AUTOFDO_PROFILE=<profile_file> CLANG_PROPELLER_PROFILE_PREFIX=<propeller_profile_prefix>