zoco

让你的PHP7更快 GCC PGO

2017-09-11


依据来源:让你的PHP7更快(GCC PGO) | 风雪之隅

执行步骤

下载最新的 php-7.2.0RC4.tar.gz https://downloads.php.net/~remi/php-7.2.0RC4.tar.gz

./configure --enable-fpm --with-config-file-path=/etc --with-config-file-scan-dir=/etc/php.d

第一遍编译PHP7, 让它生成会产生profile数据的可执行文件

make prof-gen -j 8

prof-gen参数是PHP7的Makefile特有的。

然后, 开始训练GCC:

需要在文件app.php中指定file和controller,不然会报404或者其他错误,这里的更改只是为了训练用,训练结束还需要将代码改回去。

$file = 'nearby_controller.php';

$controller = 'nearby_controller'

在nearby_controller.php中指定id和count,不然之后的代码无法训练到(尽量训练多的代码)。

进行训练,可以是100或者更多次,要注意看报错

sapi/cgi/php-cgi -T 100 /api_v2.php

训练结束,开始安装

make prof-clean
make prof-use -j 8 
sudo make install

压测结果

训练之前:

Requests per second:    326.02 [#/sec] (mean)

训练之后:

Requests per second:    361.31 [#/sec] (mean)

这个结果压测多次,发现有时训练之后的qps比训练之前的或高或低,但差距都不是很明显。

最终结论

GCC PGO在api的代码中优化效果不明显,而且操作起来较为复杂,不具备上线条件。

PGO相关解释

有编译器用到概率的,但我不知道最先进的编译器用到的概型有哪些先进的做法。编译器使用到概率的地方,最常见是跟profile-guided optimization(PGO)相关的。通过收集profile信息来估算某些代码执行的频繁程度,并对其做相应的优化。

例如说,

  1. cold code outlining

如果有:

if (cond) {
  // then...
} else {
  // else...
}
// next

并且收集到的profile说cond有超过90%都走到then分支上,那么就把then分支放在fallthrough位置上,而把else分支放到主干代码的“更后面”。于是生成的代码会是这样:

if !cond goto Label_else
  // then...
// next...
...
Label_else:
  // else...

这样,高概率执行的代码就都放在一起了,低概率执行的代码则会放到“外面”去。

  1. guarded devirtualization

例如说有这样一个虚函数调用:

o->foo()

如果profile收集到信息说,有80%的可能调用到A :: foo(),有11%的可能调用到B :: foo(),有9%未知,那么一种可能的代码生成策略是:

if (o.type == A) {
  A::foo(o)  // devirtualized
} else if (o.type == B) {
  B::foo(o)  // devirtualized
} else {
  o->vtable[slotid(#foo)](o) // virtual call fallback
}

像上面这两种使用profile所收集到的概率来引导编译器优化的就是PGO。

其中,概率显然是要涉及到“嵌套/叠加”的: