美文网首页PHP开发PHPLaravel
PHP7 内核之 FAST_ZPP 详解

PHP7 内核之 FAST_ZPP 详解

作者: 八重樱勿忘 | 来源:发表于2020-06-08 14:57 被阅读0次

从PHP7开始,大家可能会发现,不少函数不再使用传统的参数处理方式,而是改用了我们称之为Fast zend parameters parsing(FAST_ZPP)的新型方式, 比如在PHP7之前,count函数是这样的:

PHP_FUNCTION(count)

{

zval *array;

long mode = COUNT_NORMAL;

if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &array, &mode) == FAILURE) {

return;

}

....

}

在PHP7以后,变成了:

PHP_FUNCTION(count)

{

zval *array;

zend_long mode = COUNT_NORMAL;

ZEND_PARSE_PARAMETERS_START(1, 2)

Z_PARAM_ZVAL(array)

Z_PARAM_OPTIONAL

Z_PARAM_LONG(mode)

ZEND_PARSE_PARAMETERS_END();

...

}

很多PHP扩展开发的同学可能在初次接触的时候,会觉得很陌生,不要焦虑,让我慢慢道来 :)

当时在做PHPNG(PHP7的开发项目代号)的开发的时候,我们主要的发现性能提升点的一个方式就是bench各种大型实际项目,来发现占用资源比较大的部分,而最常用benchmark对象之一是wordpress,因为它够复杂,够慢,(它也是我们开发JIT的时候对主要bench目标:))  代表了非OO型代码类的典型应用,  在实际的benchmark的过程中我们发现,将近有6%的耗时被zend_parse_parameters给占用了。

事实上zend_parameters_parsing确实是一个很庞大的函数:

ZEND_API int zend_parse_parameters(int num_args, const char *type_spec, ...)

它根据type_spec字符串中指定的标识符,来处理输入参数,而这个参数符有很多种(具体含义可以参看: README.PARAMETER_PARSING_API):

a A b C d f h H l L o O p P r s S z * + | / !

根据不同的组合来表示我们的PHP函数要接受的参数类型,比如例子中的count,  通过”z|l”表示要接受一个zval类型的参数,和一个可选的long类型的mode参数,当zend_parse_parameters在runtime的时候被调用的时候,就会需要分析这些字符,然后调用对应的逻辑,对于一些本身就很简单的函数来说,比如count,这个开销就会显得很明显。

再回头来看这个函数的特点,我们会发现,比如对于count这个例子来说,其实type_spec在编译期就是确定的常量,也就是说,其实在编译的时候,我们就应该已经知道了”a|l”应该调用那些对应的参数处理逻辑。

而事实上,当代的编译器都具备这个基本优化能力, 比如对于如下的代码:

#include <stdlib.h>

#define AAA  1;

int main() {

int a = AAA;

if (a) {

abort();

}

return 0;

}

如果我们尝试让编译优化(-o2)它,并检查生成的汇编:

main:

.LFB18:

subq    $8, %rsp

call    abort@PLT

大家可以看到,if判断已经被抹掉了, 因为在编译时刻, 就能知道a是1, if一定为真。

而FAST_ZPP就是充分借助了这个能力而来的一种新型的参数申明方式, 比如对于Z_PARAM_ZVAL(array)

#define Z_PARAM_ZVAL_EX(dest, check_null, separate) \

if (separate) { \

Z_PARAM_PROLOGUE(separate); \

zend_parse_arg_zval_deref(_arg, &dest, check_null); \

} else { \

++_i; \

ZEND_ASSERT(_i <= _min_num_args || _optional==1); \

ZEND_ASSERT(_i >  _min_num_args || _optional==0); \

if (_optional && UNEXPECTED(_i >_num_args)) break; \

_real_arg++; \

zend_parse_arg_zval(_real_arg, &dest, check_null); \

}

#define Z_PARAM_ZVAL(dest) \

Z_PARAM_ZVAL_EX(dest, 0, 0)

在编译时刻就能被先替换为:

zend_parse_arg_zval(((zval*)execute_data) - 1, &array, 0);

而如果我们进一步审视zend_parse_arg_zval:

static zend_always_inline void zend_parse_arg_zval(zval *arg, zval **dest, int check_null)

{

*dest = (check_null &&

(UNEXPECTED(Z_TYPE_P(arg) == IS_NULL) ||

(UNEXPECTED(Z_ISREF_P(arg)) &&

UNEXPECTED(Z_TYPE_P(Z_REFVAL_P(arg)) == IS_NULL)))) ? NULL : arg;

}

我们会发现它也是一个inline申明的函数,而参数因为是常量,那么就可以进一步被evaluate成:

zval *array = ((zval*)execute_data) - 1;

怎么样,是不是一看就知道会快很多? 没有type_spec分析,没有额外的函数调用,直接获取到参数。

刚刚说到的inline函数可以在编译时期根据常数的剪枝内联, 也是用来避免同类函数的重复代码的很好的方法,在PHP7中也有大量使用,有兴趣的可以参看zend_hash.c中的很多相似函数的定义。

当然,这么做也有一个问题就是, 会增大我们程序的binary size, 这个也很容易理解, 比如对于count来说,本来原来只是调用一个外部函数,一个call指令就够了,但现在就会有很多内联进来的指令。

而binary size变大以后,执行时期的cache miss就会增大,也会影响性能,所以FAST_ZPP我们也不是建议全部使用, 而真是针对实际应用中调用频率比较大,并且本身函数逻辑较为简单的函数来使用.

总结一下,一般来说,我们自己写的扩展函数,并不需要一定使用FAST_ZPP, 因为如果自身是复杂的函数逻辑的, 这点开销对比起来,其实也还好了。

最后,附上新的FAST_ZPP API和老的参数描述之间的对应如下:

更多PHP内容请访问:

群内已经有管理将知识体系整理好(源码,学习视频等资料),欢迎加群免费领取

这套精品PHP教程绝不是市场上的那些妖艳贱货可比,作为web开发的佼佼者PHP并不逊色其他语言,加上Swoole后更加是如虎添翼!进军通信 、物联网行业开发百度地图、百度订单中心、虎牙、战旗TV等!寒冬裁员期过后正是各大企业扩大招人的时期,现在市场初级程序员泛滥,进阶中高级程序员绝对是各大企业急需的人才,这套学习教程适合那些1-5年以内的PHP开发者正处于瓶颈期,想要突破自己进阶中高级、架构师!名额有限,先到先得!

腾讯T3-T4标准精品PHP架构师教程目录大全,只要你看完保证薪资上升一个台阶(持续更新)

部分资料截图:

还有限时精品福利:

★腾讯高级PHP工程师笔试题目

★亿级PV高并发场景订单的处理

★laravel开发天猫商城组件服务

★战旗TV视频直播的架构项目实战

扫描下面二维码领取

对PHP后端技术,对PHP架构技术感兴趣的朋友,我的官方群点击此处,一起学习,相互讨论。

群内已经有管理将知识体系整理好(源码,学习视频等资料),欢迎加群免费领取。

本课程深度对标腾讯T3-T4标准,贴身打造学习计划为web开发人员进阶中高级、架构师提升技术,为自己增值涨薪!加入BAT特训营还可以获得内推大厂名额以及GO语言学习权限!!!

相关文章

  • PHP7 内核之 FAST_ZPP 详解

    从PHP7开始,大家可能会发现,不少函数不再使用传统的参数处理方式,而是改用了我们称之为Fast zend par...

  • 《PHP7内核剖析》

    FPM三种不同的进程管理方式 php-fpm进程管理一共有三种模式:ondemand、static、dynamic...

  • Linux内核内存管理专题训练营

    【Linux内核内存管理专题训练营】 最新Linux内核技术详解 独家Linux内核内存管理干货分享 两天持续技术...

  • PHP7内核知识整理

    php7基础逻辑 worker进程 进程管理方式 static:启动master的时候按照pm.max_child...

  • PHP7内核剖析.epub

    [下载地址 ] PHP作为最流行的语言之一,自第一个版本发布至今的二十几年里经历了多次重大改进,PHP7版本最大的...

  • PHP7之Mongodb的开发详解

    1.mongdb的连接 2.mongdb的添加 3.mongdb的删除 4.mongdb的修改 5.mongdb的...

  • PHP7内核剖析1之CGI与FastCGI

    CGI:是 Web Server 与 Web Application 之间数据交换的一种协议。FastCGI:同 ...

  • CSS3之径向渐变(radial-gradient)

    上一篇文章主要讲解了线性渐变,这篇文章主要对径向渐变进行详解,也是分为带内核和不带内核两种情形。 1 带内核的径...

  • epoll内核源码详解

    epoll内核源码详解 牛客网上找到的一篇博客,仅供自己学习使用, 在深入了解epoll的实现之前, 先来了解内核...

  • Chromium内核原理之blink内核工作解密

    《Chromium内核原理之blink内核工作解密》《Chromium内核原理之多进程架构》《Chromium内核...

网友评论

    本文标题:PHP7 内核之 FAST_ZPP 详解

    本文链接:https://www.haomeiwen.com/subject/flxbzhtx.html