问题与练习
- 解决
perf-ninja::pgo
实验作业。 - 尝试为代码段使用大页。选择一个大型应用程序(如果能够访问源代码则更佳,但不是必需的),其二进制文件大小超过100MB。尝试使用 [@sec:FeTLB] 中描述的一种方法将其代码段重新映射到大页上。观察性能的任何变化,
/proc/meminfo
中的大页分配情况,以及测量 ITLB 命中和未命中的 CPU 性能计数器。 - 假设你有一段代码,其中包含一个循环中的 C++ switch 语句。你已经对代码进行了分析,并发现 switch 语句中的一个特定情况占了 70% 的时间。其他 40 种情况每种使用时间不到 3%,另外 20 种情况从未发生。你会如何优化这个 switch/循环的性能?
- 在你日常使用的应用程序上运行 PGO、llvm-bolt 或 Propeller。比较“优化前”和“优化后”的性能分析,以了解加速来自何处。
AI回答:
解决
perf-ninja::pgo
实验作业:- 首先,确保你有一个支持PGO(Profile Guided Optimizations)的编译环境,比如GCC或Clang。
- 编译你的程序,启用PGO插桩(instrumentation),这通常涉及到添加特定的编译器标志,如
-fprofile-instr-generate
。 - 使用你的程序运行一系列代表性的工作负载,以收集性能数据。这通常涉及到运行程序多次,或者使用特定的工具来收集运行时数据。
- 分析收集到的性能数据,这可能包括函数调用次数、循环迭代次数等。
- 使用这些数据重新编译你的程序,启用PGO使用(
-fprofile-use
)来生成优化后的二进制文件。 - 测试优化后的程序,比较性能提升。
尝试为代码段使用大页:
- 选择一个大型应用程序,确保其二进制文件大小超过100MB。
- 在Linux系统上,你可以使用
madvise
系统调用来建议内核使用大页。例如,madvise((void *)address, size, MADV_HUGEPAGE)
。 - 另一种方法是在编译时使用特定的链接器选项,如
-Wl,-zmax-page-size=2M
,这会告诉链接器尝试将代码段放置在2MB大页上。 - 观察性能变化,可以通过运行基准测试来完成。
- 查看
/proc/meminfo
文件来确认大页的使用情况。 - 使用性能分析工具(如
perf
)来测量ITLB的命中和未命中情况。
优化C++ switch语句:
- 对于频繁执行的特定情况,可以考虑将其提取到一个单独的函数中,以减少switch语句的复杂性。
- 对于从未发生的分支,可以完全移除它们,以简化switch语句。
- 对于使用频率较低的分支,可以考虑使用跳转表(jump table)或者基于范围的switch来优化。
- 如果switch语句基于某些可预测的模式(如枚举类型),可以考虑使用位掩码或查找表来加速决策过程。
运行PGO、llvm-bolt或Propeller:
- 对于PGO,按照上述步骤1的指导进行。
- 对于llvm-bolt,可以使用
llvm-bolt
工具对二进制文件进行优化。这通常涉及到反汇编代码,应用优化,然后重新链接。 - 对于Propeller,这是一个二进制重链接工具,它依赖于链接器输入,可以在多个机器上分布式运行。
- 在优化前后,使用性能分析工具(如
perf
)来比较性能指标,如CPU周期、缓存命中率等,以了解性能提升的来源。