跟踪配置文件质量

使用 PGO 进行原生镜像时最具挑战性的步骤是为相关工作负载收集配置文件。由于源代码会不断演变,应用程序很少会保持静止。有时,对于源代码的每次更改,都要经历“构建带工具的镜像”、“收集配置文件”和“构建优化的镜像”等步骤,这非常耗时。本文档将解答以下问题:“随着应用程序的源代码不断变化,我还能使用现有的配置文件多长时间?”

方法 1:无限期重用配置文件 #

当构建优化的应用程序时,原生镜像会尽力使用给定的配置文件。这意味着,即使为应用程序提供过时的配置文件(甚至完全不同的应用程序的配置文件),也不应该阻止原生镜像生成原生可执行文件。

注意:不正确的配置文件会导致性能比没有配置文件还差。这是因为不正确的配置文件会导致编译器将优化资源浪费在应用程序的错误元素上,并降低重要元素的优先级。

话虽如此,但对于不断演变的应用程序,无限期地重用单个配置文件最终会适得其反。

方法 2:定期收集配置文件 #

由于应用程序可能会定期更改,因此定期收集新的配置文件是合理的。一种实现此目标的方法是使用每天的 Linux cron 作业,使用 master 分支的顶端构建应用程序的带工具版本,运行工作负载以收集配置文件,并将生成的 iprof 文件上传到其他优化构建可以从中下载的 FTP 服务器。这确保了应用程序版本和使用的配置文件之间的差异永远不会超过固定时间间隔(在本例中为 24 小时)。

但是,定期收集配置文件会延长计算时间,因此应该权衡收集配置文件的频率和应用程序更改的频率。如果应用程序相对稳定,并且源代码更改很少,那么可以减少重新分析的频率。以下是一些需要牢记的事项

  • 将分析计划与应用程序发布计划保持一致,以避免使用过时的配置文件构建应用程序。
  • 理想情况下,将生产工作负载转换为可重现的工作负载,在构建过程中收集配置文件,然后使用始终是最新的配置文件创建优化的原生可执行文件。

这样,只要工作负载执行与生产环境中后来执行的应用程序的相同部分,就可以避免出现过时或不匹配的配置文件。

方法 3:跟踪配置文件质量指标随时间推移的变化情况 #

为了更好地了解配置文件的质量,原生镜像提供了两个指标,您可以在构建优化的可执行文件时请求这些指标:配置文件相关性配置文件适用性。这些指标反映了配置文件与优化可执行文件中出现的类和方法之间的关系。

这些指标在构建之间(使用相同配置文件)的值发生变化,表明这些构建中的类和/或方法集也发生了变化(在收集配置文件的时间和当前构建之间)。

如何获取配置文件质量指标 #

要计算和打印配置文件质量指标,在构建优化的原生可执行文件时传递 -H:+PGOPrintProfileQuality 选项。(此选项为实验性选项。)

我们以 配置文件引导优化基本用法 中介绍的“生命游戏”示例应用程序为例。

native-image -cp . GameOfLife -o gameoflife-pgo --pgo=gameoflife.iprof -H:+PGOPrintProfileQuality

在构建输出的第 5 阶段,您应该看到有关配置文件适用性和配置文件相关性的附加行。

GraalVM Native Image: Generating 'gameoflife-pgo' (executable)
...
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.28GB)
Info: PGO: Profile applicability is 21.74%. Profile relevance is 72.71%.
...

这些指标的绝对值并不能说明太多问题,也不应该孤立地考虑。如前所述,这些指标描述了配置文件与应用程序代码之间的关系。如果更改应用程序并重新使用配置文件,应该会看到指标值发生变化。

例如,对 applyRules () 应用程序方法执行简单的“方法重命名”重构。从配置文件的角度来看,applyRules () 方法已从应用程序的方法集中删除,并引入了名为 applyGameRules 的新方法。使用相同的配置文件和修改后的应用程序重新运行优化构建会返回以下输出。

native-image -cp . GameOfLife -o gameoflife-pgo --pgo=gameoflife.iprof -H:+PGOPrintProfileQuality
========================================================================================================================
GraalVM Native Image: Generating 'gameoflife-pgo' (executable)...
...
[5/8] Inlining methods...     [***]                                                                      (0.4s @ 0.28GB)
Info: PGO: Profile applicability is 21.67%. Profile relevance is 72.66%.                                                                  (6.8s @ 0.29GB)
...

回想一下,第一个构建中的配置文件适用性为 21.74%,现在为 21.67%。同样,第一个构建中的配置文件相关性为 72.71%,现在为 72.66%。对代码的微小更改导致了指标值的小幅变化,通知您配置文件可能略微过时。

注意:在本例中,您重命名了一个非常热门的方法。这种更改很可能导致性能下降,因为配置文件无法应用于热门方法。在应用程序的冷代码中进行类似更改会产生类似的指标值降低,但这不会影响性能。请注意,这些指标衡量的是提供的配置文件与应用程序中方法集之间的关系,而不是对配置文件、应用程序源代码或依赖项的更改可能会产生的任何性能影响的衡量或预测。当在单个构建中观察到这些数字时,它们也毫无意义或毫无用处。它们的作用在于观察在跨构建重复使用配置文件时或为应用程序的相同构建提供不同的配置文件时,指标的变化情况。

配置文件质量指标:适用性 #

适用性指标回答以下问题:“此配置文件对应用程序的方法适用程度如何?”。在编译应用程序中的各个方法时,它会跟踪代码中需要配置文件的位置数量 N,以及配置文件可用的次数 S。配置文件适用性指标是 S / N 的比率,以百分比表示。

这意味着,将新代码添加到应用程序(而不是配置文件)会导致配置文件适用性降低。这是因为更多代码意味着对配置文件的更多请求,并且配置文件可以应用的次数(S)相同,但被用于所有配置文件请求(N)的更大数量所除。

注意:不应期望配置文件适用性为 100%。在几乎所有情况下,良好的工作负载都会区分应用程序的热门部分和冷门部分,并且不会执行代码的某些冷门部分。因此,配置文件将不包含应用程序冷门部分的任何条目(例如,异常处理程序),因为这些部分在实际工作负载中很少执行。100% 的适用性意味着镜像中的所有代码部分都已完全分析,这在实践中几乎是不可能的。

配置文件质量指标:相关性 #

相关性指标旨在回答以下问题:“配置文件内容与应用程序方法的匹配程度如何?”。加载配置文件时,会将配置文件中的所有数据与应用程序方法集进行对比,并将与这些方法不匹配的所有条目都删除。例如,如果从类中删除了一个方法,但使用仍然包含该方法条目的配置文件,那么所有这些条目都将在加载配置文件时被删除。配置文件相关性是在加载期间未被删除的数据的百分比。

这意味着,从应用程序中删除代码(而不是从配置文件中删除代码)会导致配置文件相关性降低,因为配置文件中与新应用程序版本相关的数据的百分比降低了。另一方面,将新代码(例如,新类或依赖项)添加到应用程序不会影响此指标,因为您需要从配置文件中删除的数据量不会改变。

注意:不应期望构建与用于收集配置文件的应用程序完全相同的应用程序的优化二进制文件会产生 100% 的配置文件相关性。这不是这种情况,因为带工具的二进制文件和优化二进制文件的方法在细微方面有所不同。例如,带工具的二进制文件包含用于收集配置文件数据以及用于将这些数据序列化到文件的代码。此代码是不必要的,因此在优化二进制文件中不存在。看一下“生命游戏”示例,大约 70% 的相关性主要是因为应用程序非常小(单个 Java 类,代码不到 120 行)。因此,带工具的二进制文件和优化二进制文件的方法集之间的差异相当大。对于更大的实际应用程序,此百分比通常更大,但不是 100%。

进一步阅读 #

与我们联系