- URL: https://www.laruence.com/en/2015/06/19/3063.html
- Please include attribution when republishing.
We've been steadily working to make PHP 7 faster. Last month we noticed that GCC's PGO could deliver nearly a 10% performance boost on WordPress, and that got us pretty excited.
But PGO — Profile-Guided Optimization, if you want to look it up — needs a set of workloads to gather feedback from. In other words, the optimization is tied to a specific scenario. An optimization that helps one scenario can easily backfire in another. It's not a general-purpose optimization. So we can't simply bundle these optimizations in, and we can't ship a PGO-compiled PHP 7 as-is either.
Of course, we've been trying to distill the common optimizations out of the PGO data and hand-apply them to PHP 7 — but that clearly can't reach the effect of an optimization tailored to a single scenario. So I decided to write this post giving a quick tour of how to build PHP 7 with PGO, so that your own build can make your specific standalone application faster.
The first thing to decide is which scenario to use to feed back to GCC. Usually we'd pick, from the scenario you want to optimize: the page that gets the most traffic, takes the most time, and consumes the most resources.
For WordPress, we pick the front page (since it's typically the highest-traffic page).
Here's the spec of my machine:
Intel(R) Xeon(R) CPU X5687 @ 3.60GHz X 16(超线程),
48G Memory
php-fpm is pinned to 32 workers, and opcache uses its default configuration (do remember to actually load opcache).
We use WordPress 4.1 as the optimization target.
First, let's measure the current performance of WP on PHP 7 (ab -n 10000 -c 100):
$ ab -n 10000 -c 100 http://inf-dev-maybach.weibo.com:8000/wordpress/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking inf-dev-maybach.weibo.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: nginx/1.7.12 Server Hostname: inf-dev-maybach.weibo.com Server Port: 8000 Document Path: /wordpress/ Document Length: 9048 bytes Concurrency Level: 100 Time taken for tests: 8.957 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 92860000 bytes HTML transferred: 90480000 bytes Requests per second: 1116.48 [#/sec] (mean) Time per request: 89.567 [ms] (mean) Time per request: 0.896 [ms] (mean, across all concurrent requests) Transfer rate: 10124.65 [Kbytes/sec] received
As you can see, WordPress 4.1 currently handles about 1116.48 QPS on the front page on this machine — i.e. it can process that many front-page requests per second.
Now let's start teaching GCC to compile a PHP 7 that runs WordPress 4.1 faster. You need GCC 4.0 or above, but I'd recommend GCC 4.8+ (we're on GCC 5.1 these days).
Step one is, naturally, to download the PHP 7 source and run ./configure. Nothing different there.
This is where it diverges. First we build PHP 7 once, to produce an executable that will emit profiling data:
$ make prof-gen
Note the prof-gen argument we used (this is specific to PHP 7's Makefile — don't try doing the same thing on other projects :)).
Then we start training GCC:
$ sapi/cgi/php-cgi -T 100 /home/huixinchen/local/www/htdocs/wordpress/index.php >/dev/null
which just runs the WordPress front page 100 times through php-cgi, generating profiling information along the way.
After that, we kick off the second build of PHP 7.
$ make prof-clean $ make prof-use && make install
And that's it — the PGO build is done. Now let's look at the performance of this PGO-compiled PHP 7:
$ ab -n10000 -c 100 http://inf-dev-maybach.weibo.com:8000/wordpress/ This is ApacheBench, Version 2.3 <$Revision: 655654 $> Copyright 1996 Adam Twiss, Zeus Technology Ltd, http://www.zeustech.net/ Licensed to The Apache Software Foundation, http://www.apache.org/ Benchmarking inf-dev-maybach.weibo.com (be patient) Completed 1000 requests Completed 2000 requests Completed 3000 requests Completed 4000 requests Completed 5000 requests Completed 6000 requests Completed 7000 requests Completed 8000 requests Completed 9000 requests Completed 10000 requests Finished 10000 requests Server Software: nginx/1.7.12 Server Hostname: inf-dev-maybach.weibo.com Server Port: 8000 Document Path: /wordpress/ Document Length: 9048 bytes Concurrency Level: 100 Time taken for tests: 8.391 seconds Complete requests: 10000 Failed requests: 0 Write errors: 0 Total transferred: 92860000 bytes HTML transferred: 90480000 bytes Requests per second: 1191.78 [#/sec] (mean) Time per request: 83.908 [ms] (mean) Time per request: 0.839 [ms] (mean, across all concurrent requests) Transfer rate: 10807.45 [Kbytes/sec] received
Now we're handling 1191.78 QPS — a gain of about 7%. Not bad, right? (Huh, didn't you say 10%? How is it only 7% now? Heh, as I mentioned before, we've been trying to analyze what PGO actually optimizes and then hand-apply the generic parts into PHP 7. So about 3% of the more general optimizations are already folded into PHP 7 — and that work is still ongoing.)
So, that simple. Everyone can train GCC with the canonical scenario of their own product — a few easy steps for a real gain. What's not to like 🙂
thanks
Be First to Comment