使用Huagepage和PGO來(lái)提升PHP7的執(zhí)行性能
Hugepage
PHP7剛剛發(fā)布了RC4, 包含一些bug修復(fù)和一個(gè)我們最新的性能提升成果, 那就是”HugePageFy PHP TEXT segment”, 通過(guò)啟用這個(gè)特性,PHP7會(huì)把自身的TEXT段(執(zhí)行體)”挪“到Huagepage上,之前的測(cè)試,我們能穩(wěn)定的在Wordpress上看到2%~3%的QPS提升。
關(guān)于Hugepage是啥,簡(jiǎn)單的說(shuō)下就是默認(rèn)的內(nèi)存是以4KB分頁(yè)的,而虛擬地址和內(nèi)存地址是需要轉(zhuǎn)換的, 而這個(gè)轉(zhuǎn)換是要查表的,CPU為了加速這個(gè)查表過(guò)程都會(huì)內(nèi)建TLB(Translation Lookaside Buffer), 顯而易見(jiàn)如果虛擬頁(yè)越小,表里的條目數(shù)也就越多,而TLB大小是有限的,條目數(shù)越多TLB的Cache Miss也就會(huì)越高, 所以如果我們能啟用大內(nèi)存頁(yè)就能間接降低這個(gè)TLB Cache Miss,至于詳細(xì)的介紹,Google一搜一大堆我就不贅述了,這里主要說(shuō)明下如何啟用這個(gè)新特性, 從而帶來(lái)明顯的性能提升。
新的Kernel啟用Hugepage已經(jīng)變得非常容易了,以我的開(kāi)發(fā)虛擬機(jī)為例(Ubuntu Server 14.04,Kernel 3.13.0-45), 如果我們查看內(nèi)存信息:
$ cat /proc/meminfo | grep Huge
AnonHugePages: 444416 kB HugePages_Total: 0 HugePages_Free: 0 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB
可見(jiàn)一個(gè)Hugepage的size是2MB, 而當(dāng)前并沒(méi)有啟用HugePages. 現(xiàn)在讓我們先編譯PHP RC4, 記得一定不要加: –disable-huge-code-pages (這個(gè)新特性是默認(rèn)啟用的, 你加了這個(gè)就關(guān)了)
然后配置opcache, 從PHP5.5開(kāi)始Opcache已經(jīng)是默認(rèn)啟用編譯的,但是是編譯動(dòng)態(tài)庫(kù)的, 所以我們還是要在php.ini中配置加載下。
zend_extension=opcache.so
這個(gè)新特性是做在Opcache里的,所以也要通過(guò)Opcache啟用這個(gè)特性(通過(guò)設(shè)置opcache.huge_code_pages=1), 具體的配置:
opcache.huge_code_pages=1
現(xiàn)在讓我們配置OS, 分配一些Hugepages:
$ sudo sysctl vm.nr_hugepages=128 vm.nr_hugepages = 128
現(xiàn)在讓我們?cè)俅螜z查內(nèi)存信息:
$ cat /proc/meminfo | grep Huge
AnonHugePages: 444416 kB HugePages_Total: 128 HugePages_Free: 128 HugePages_Rsvd: 0 HugePages_Surp: 0 Hugepagesize: 2048 kB
可以看到我們分配的128個(gè)Hugepages已經(jīng)就緒了, 然后我們來(lái)啟動(dòng)php-fpm:
$ /home/huixinchen/local/php7/sbin/php-fpm
[01-Oct-2015 09:33:27] NOTICE: [pool www] 'user' directive is ignored when FPM is not running as root [01-Oct-2015 09:33:27] NOTICE: [pool www] 'group' directive is ignored when FPM is not running as root
現(xiàn)在, 再次檢查內(nèi)存信息:
$ cat /proc/meminfo | grep Huge
AnonHugePages: 411648 kB HugePages_Total: 128 HugePages_Free: 113 HugePages_Rsvd: 27 HugePages_Surp: 0 Hugepagesize: 2048 kB
說(shuō)到這里,如果Hugepages可用, 其實(shí)Opcache也會(huì)用Hugepages來(lái)存儲(chǔ)opcodes緩存, 所以為了驗(yàn)證opcache.huge_code_pages確實(shí)生效, 我們不妨關(guān)閉opcache.huge_code_pages, 然后再啟動(dòng)一次后看內(nèi)存信息:
$ cat /proc/meminfo | grep Huge
AnonHugePages: 436224 kB HugePages_Total: 128 HugePages_Free: 117 HugePages_Rsvd: 27 HugePages_Surp: 0 Hugepagesize: 2048 kB
可見(jiàn)開(kāi)啟了huge_code_pages以后, fpm啟動(dòng)后多用了4個(gè)pages, 現(xiàn)在我們檢查下php-fpm的text大小:
$ size /home/huixinchen/local/php7/sbin/php-fpm
text data bss dec hex filename 10114565 695200 131528 10941293 a6f36d /home/huixinchen/local/php7/sbin/php-fpm
可見(jiàn)text段有10114565個(gè)字節(jié)大小, 總共需要占用4.8個(gè)左右的2M的pages, 考慮到對(duì)齊以后(尾部不足2M Page部分不挪動(dòng)), 申請(qǐng)4個(gè)pages, 正好和我們看到的相符。
說(shuō)明配置成功! Enjoy :)
但是有言在先, 啟用此特性以后, 會(huì)造成一個(gè)問(wèn)題就是你如果嘗試通過(guò)Perf report/anno 去profiling的時(shí)候, 會(huì)發(fā)現(xiàn)符號(hào)丟失(valgrind, gdb不受影響), 這個(gè)主要原因是Perf的設(shè)計(jì)采用監(jiān)聽(tīng)了mmap,然后記錄地址范圍, 做IP到符號(hào)的轉(zhuǎn)換, 但是目前HugeTLB只支持MAP_ANON, 所以導(dǎo)致Perf認(rèn)為這部分地址沒(méi)有符號(hào)信息,希望以后版本的Kernel可以修復(fù)這個(gè)限制吧..
GCC PGO
PGO正如名字所說(shuō)(Profile Guided Optimization 有興趣的可以Google), 他需要用一些用例來(lái)獲得反饋, 也就是說(shuō)這個(gè)優(yōu)化是需要和一個(gè)特定的場(chǎng)景綁定的.
你對(duì)一個(gè)場(chǎng)景的優(yōu)化, 也許在另外一個(gè)場(chǎng)景就事與愿違了. 它不是一個(gè)通用的優(yōu)化. 所以我們不能簡(jiǎn)單的就包含這些優(yōu)化, 也無(wú)法直接發(fā)布PGO編譯后的PHP7.
當(dāng)然, 我們正在嘗試從PGO找出一些共性的優(yōu)化, 然后手工Apply到PHP7上去, 但這個(gè)很明顯不能做到針對(duì)一個(gè)場(chǎng)景的特別優(yōu)化所能達(dá)到的效果, 所以我決定寫(xiě)這篇文章簡(jiǎn)單介紹下怎么使用PGO來(lái)編譯PHP7, 讓你編譯的PHP7能特別的讓你自己的獨(dú)立的應(yīng)用變得更快.
首先, 要決定的就是拿什么場(chǎng)景去Feedback GCC, 我們一般都會(huì)選擇: 在你要優(yōu)化的場(chǎng)景中: 訪問(wèn)量最大的, 耗時(shí)最多的, 資源消耗最重的一個(gè)頁(yè)面.
拿Wordpress為例, 我們選擇Wordpress的首頁(yè)(因?yàn)槭醉?yè)往往是訪問(wèn)量最大的).
我們以我的機(jī)器為例:
Intel(R) Xeon(R) CPU X5687 @ 3.60GHz X 16(超線程),
48G Memory
php-fpm 采用固定32個(gè)worker, opcache采用默認(rèn)的配置(一定要記得加載opcache)
以wordpress 4.1為優(yōu)化場(chǎng)景..
首先我們來(lái)測(cè)試下目前WP在PHP7的性能(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
可見(jiàn)Wordpress 4.1 目前在這個(gè)機(jī)器上, 首頁(yè)的QPS可以到1116.48. 也就是每秒鐘可以處理這么多個(gè)對(duì)首頁(yè)的請(qǐng)求,
現(xiàn)在, 讓我們開(kāi)始教GCC, 讓他編譯出跑Wordpress4.1更快的PHP7來(lái), 首先要求GCC 4.0以上的版本, 不過(guò)我建議大家使用GCC-4.8以上的版本(現(xiàn)在都GCC-5.1了).
第一步, 自然是下載PHP7的源代碼了, 然后做./configure. 這些都沒(méi)什么區(qū)別
接下來(lái)就是有區(qū)別的地方了, 我們要首先第一遍編譯PHP7, 讓它生成會(huì)產(chǎn)生profile數(shù)據(jù)的可執(zhí)行文件:
$ make prof-gen
注意, 我們用到了prof-gen參數(shù)(這個(gè)是PHP7的Makefile特有的, 不要嘗試在其他項(xiàng)目上也這么搞哈 :) )
然后, 讓我們開(kāi)始訓(xùn)練GCC:
$ sapi/cgi/php-cgi -T 100 /home/huixinchen/local/www/htdocs/wordpress/index.php >/dev/null
也就是讓php-cgi跑100遍wordpress的首頁(yè), 從而生成一些在這個(gè)過(guò)程中的profile信息.
然后, 我們開(kāi)始第二次編譯PHP7.
$ make prof-clean $ make prof-use && make install
好的, 就這么簡(jiǎn)單, PGO編譯完成了, 現(xiàn)在我們看看PGO編譯以后的PHP7的性能:
$ 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
現(xiàn)在每秒鐘可以處理1191.78個(gè)QPS了, 提升是~7%. 還不賴哈(咦, 你不是說(shuō)10%么? 怎么成7%了? 呵呵, 正如我之前說(shuō)過(guò), 我們嘗試分析PGO都做了些什么優(yōu)化, 然后把一些通用的優(yōu)化手工Apply到PHP7中. 所以也就是說(shuō), 那~3%的比較通用的優(yōu)化已經(jīng)包含到了PHP7里面了, 當(dāng)然這個(gè)工作還在繼續(xù)).
于是就這么簡(jiǎn)單, 大家可以用自己的產(chǎn)品的經(jīng)典場(chǎng)景來(lái)訓(xùn)練GCC, 簡(jiǎn)單幾步, 獲得提升, 何樂(lè)而不為呢
相關(guān)文章
PHP5.4中json_encode中文轉(zhuǎn)碼的變化小結(jié)
在php5.4以前做json_encode的時(shí)候中文會(huì)被unicode編碼,中文都會(huì)被編碼,變成不可讀的,類似“\u***”的格式,接下來(lái)介紹幾種5.4之前不進(jìn)行unicode轉(zhuǎn)碼的處理方法2013-01-01
jquery獲取多個(gè)checkbox的值異步提交給php的方法
這篇文章主要介紹了jquery獲取多個(gè)checkbox的值異步提交給php的方法,涉及jQuery操作頁(yè)面元素進(jìn)行異步傳輸?shù)南嚓P(guān)技巧,需要的朋友可以參考下2015-06-06
ThinkPHP使用心得分享-ThinkPHP + Ajax 實(shí)現(xiàn)2級(jí)聯(lián)動(dòng)下拉菜單
聯(lián)動(dòng)菜單的數(shù)據(jù)存在數(shù)據(jù)庫(kù),可以隨時(shí)通過(guò)對(duì)數(shù)據(jù)庫(kù)添加刪除修改改變菜單數(shù)據(jù),而不需修改代碼,同時(shí),實(shí)現(xiàn)了2級(jí)后,也可以實(shí)現(xiàn)3級(jí),4級(jí)。。。等關(guān)聯(lián)菜單2014-05-05
從一個(gè)不錯(cuò)的留言本弄的mysql數(shù)據(jù)庫(kù)操作類
本文通過(guò)實(shí)例代碼給大家介紹了mysql數(shù)據(jù)庫(kù)操作類的相關(guān)知識(shí),感興趣的朋友跟隨腳本之家小編一起看看吧2007-09-09
php中通過(guò)curl檢測(cè)頁(yè)面是否被百度收錄
最近要對(duì)網(wǎng)站做個(gè)整理,需要檢測(cè)網(wǎng)站內(nèi)哪些頁(yè)面沒(méi)有被百度搜索引擎收錄從而進(jìn)行相關(guān)的調(diào)整。由于使用site命令一條條的去看實(shí)在是看不過(guò)來(lái),就想到了使用php程序來(lái)批量處理一下2013-09-09
本地機(jī)apache配置基于域名的虛擬主機(jī)詳解
以下是對(duì)本地機(jī)apache配置基于域名的虛擬主機(jī)進(jìn)行了詳細(xì)的介紹,需要的朋友可以過(guò)來(lái)參考下2013-08-08

