今年做PHP 在ARM上的性能性能优化,利用GCC全局寄存器特性使提升PHP在aarch64上性能提升10%。
源码修改已经提交到官方社区,随PHP 7.4以上官方版本发布。
发一篇帖子记录一下,对于PHP 7 , 不愿意升级PHP版本的,也可以修改几行代码,重新编译安装即可。
顺便总结了一下,利用GCC全局寄存器性能提升的内部原理和可用的推广点。
此性能优化点在PHP的Zend引擎中,任何使用PHP的场景都适用。
1 源码修改
源码修改涉及的2个文件如表1.所示。
表1. 源码修改涉及文件
| 修改文件 | Zend_execute.c | zend.m4 |
| 源文件描述 | 源码宏定义 | 通用宏处理器,configure脚本依赖它 |
2个文件修改的内容均一致,总计新增3x2=6行代码。
修改后代码和源码对比如图1.所示。
图1. PHP源码修改点
通过编译器的宏进行GCC版本判断和CPU类别判断,选取ARM64后两个通用寄存器x27和x28。寄存器的使用方法如图2.所示。
图2. Zend中寄存器使用
在并发访问worepress首页的场景中,获得了10%以上的性能提升。源码已合入PHP官方社区,将在PHP 7.4及以上版本发布。
2 内部原理
PHP 的Zend引擎在opcode的执行过程中,会频繁的用到execute_data(执行数据)和opline(当前执行的指令)两个变量。优化前的软件流程参考普通处理方式,优化后的软件流程参考全局寄存处理方式。
普通的处理方式
执行每条opcode指令的handler时,会把execute_data地址作为参数传给handler使用,先从当前栈上获取execute_data地址,然后再从堆上获取变量的数据(在缓存命中的情况下,从缓存中获取数据)。
GCC全局寄存器处理方式
使用GCC提供的全局寄存器特性保存execute_data和opline变量的地址在寄存器中,直接从寄存器读取地址。相对普通处理方式,节省了从缓存/内存中读取数据的时间。
3 技术推广
将频繁使用的char、int或指针型变量存储在寄存器中,使用4.8.0以上GCC进行源码编译
4 附录
寄存器变量
寄存器变量存放在CPU的寄存器中,使用时,不需要访问内存直接从寄存器中读写,与存储在内存中的变量相比,寄存器变量具有更快的访问速度。 C语言中使用关键字register来声明变量为寄存器变量。受硬件寄存器长度的限制,寄存器变量只能是char、int或指针型,而不能使其他复杂数据类型。
全局寄存器变量
GCC从4.8.0版本开始支持另外一项特性:全局寄存器变量(Global Register Variables),可以把全局变量定义为寄存器变量,从而可以实现函数间共享数据。可以通过下面的语法告诉编译器使用寄存器来保存数据:
图3 寄存器变量声明语法
全局寄存器变量详细介绍参考链接:











































苏公安网备 32011402010933号