zoukankan      html  css  js  c++  java
  • Opcode查看利器之vld

    简介

    在PHP的生命周期中

    词法分析(zend_language_scanner),将PHP代码转换为语言片段(Tokens)
    语法分析(zend_language_parser)将Tokens转换成简单而有意义的表达式
    编译(compiler),将表达式编译成Opocdes,返回zend_op_array指针
    Zend Engine(zend_vm_execute),顺次执行Opcodes,每次一条, 根据传入的zend_op_array指针,执行opcode并将结果返回输出
    

    在上述执行过程中,经常被人提起的解释型语言性能问题也就是因为每次执行脚本,上述过程都会重复执行。因此,也就出现了APC, xcache, eAccelerator等缓存,不过现在官方主推的是opcache

    什么是opcode缓存

    当解释器完成对脚本代码的分析后,便将它们生成可以直接运行的中间代码,也称为操作码(Operate Code,opcode)。Opcode cache的目地是避免重复编译,减少CPU和内存开销。如果动态内容的性能瓶颈不在于CPU和内存,而在于I/O操作,比如数据库查询带来的磁盘I/O 开销,那么opcode cache的性能提升是非常有限的。也就是opcode cache能带来CPU和内存开销的降低

    APC, xcache, eAccelerator,opcache 使用共享内存进行存储,并且可以直接从中执行文件,而不用在执行前“反序列化”代码

    词法分析

    Zend/zend_language_scanner.c 会根据Zend/zend_language_scanner.l(Lex文件),来对输入的 PHP代码进行词法分析,从而得到一个一个的“词”,PHP4.2+开始提供了一个函数叫token_get_all ,这个函数就可以将一段PHP代码 Scanning成Tokens

    一、安装VLD扩展

    1、下载

    地址:http://pecl.php.net/package/vld

    wget  http://pecl.php.net/get/vld-0.13.0.tgz
    

     2、编译安装

    cd /usr/local/src/
    wget http://pecl.php.net/get/vld-0.13.0.tgz
    tar -zxf vld-0.13.0.tgz 
    cd vld-0.13.0
    phpize && ./configure  --with-php-config=php-config --enable-vld
    make && make install
    echo extension=vld.so >> /etc/php.d/vld.ini
    service php-fpm reload
    php-config、phpize要加入环境变量
    

     3、opcode的结构

    vim Zend/zend_compile.h

    typedef struct _zend_op_array zend_op_array;
    typedef struct _zend_op zend_op;
    
    struct _zend_op {
            opcode_handler_t handler;
            znode_op op1;
            znode_op op2;
            znode_op result;
            ulong extended_value;
            uint lineno;
            zend_uchar opcode;
            zend_uchar op1_type;
            zend_uchar op2_type;
            zend_uchar result_type;
    };
    
    struct _zend_op_array {
            /* Common elements */
            zend_uchar type;
            const char *function_name;
            zend_class_entry *scope;
            zend_uint fn_flags;
            union _zend_function *prototype;
            zend_uint num_args;
            zend_uint required_num_args;
            zend_arg_info *arg_info;
            /* END of common elements */
    
            zend_uint *refcount;
    
            zend_op *opcodes;
            zend_uint last;
    
            zend_compiled_variable *vars;
            int last_var;
    
            zend_uint T;
    
            zend_brk_cont_element *brk_cont_array;
            int last_brk_cont;
    
            zend_try_catch_element *try_catch_array;
            int last_try_catch;
    
            /* static variables support */
            HashTable *static_variables;
    
            zend_uint this_var;
    
            const char *filename;
            zend_uint line_start;
            zend_uint line_end;
            const char *doc_comment;
            zend_uint doc_comment_len;
            zend_uint early_binding; /* the linked list of delayed declarations */
    
            zend_literal *literals;
            int last_literal;
    
            void **run_time_cache;
            int  last_cache_slot;
    
            void *reserved[ZEND_MAX_RESERVED_RESOURCES];
    };
    

     4、opcode的使用

    STD_PHP_INI_ENTRY("vld.active",       "0", PHP_INI_SYSTEM, OnUpdateBool, active,       zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.skip_prepend", "0", PHP_INI_SYSTEM, OnUpdateBool, skip_prepend, zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.skip_append",  "0", PHP_INI_SYSTEM, OnUpdateBool, skip_append,  zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.execute",      "1", PHP_INI_SYSTEM, OnUpdateBool, execute,      zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.verbosity",    "1", PHP_INI_SYSTEM, OnUpdateBool, verbosity,    zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.format",       "0", PHP_INI_SYSTEM, OnUpdateBool, format,       zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.col_sep",      "	", PHP_INI_SYSTEM, OnUpdateString, col_sep,   zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.save_dir",     "/tmp", PHP_INI_SYSTEM, OnUpdateString, save_dir, zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.save_paths",   "0", PHP_INI_SYSTEM, OnUpdateBool, save_paths,   zend_vld_globals, vld_globals)
    STD_PHP_INI_ENTRY("vld.dump_paths",   "1", PHP_INI_SYSTEM, OnUpdateBool, dump_paths,   zend_vld_globals, vld_globals)
    

     这些是vld的系统配置

    默认值

    static void vld_init_globals(zend_vld_globals *vld_globals)
    {
            vld_globals->active       = 0;
            vld_globals->skip_prepend = 0;
            vld_globals->skip_append  = 0;
            vld_globals->execute      = 1;
            vld_globals->format       = 0;
            vld_globals->col_sep      = "	";
            vld_globals->path_dump_file = NULL;
            vld_globals->dump_paths   = 1;
            vld_globals->save_paths   = 0;
            vld_globals->verbosity    = 1;
    }
    

     php -dvld.active=1 -dvld.execute= -f  test.php

    [root@localhost code]# php -dvld.active test.php    
    Finding entry points
    Branch analysis from position: 0
    Jump found. Position 1 = -2
    filename:       /data/code/test.php
    function name:  (null)
    number of ops:  5
    compiled vars:  none
    line     #* E I O op                           fetch          ext  return  operands
    -------------------------------------------------------------------------------------
       2     0  E >   SEND_VAL                                                 'dbname'
             1        DO_FCALL                                      1  $0      'config'
             2        SEND_VAR_NO_REF                               6          $0
             3        DO_FCALL                                      1          'var_dump'
       3     4      > RETURN                                                   1
    
    branch: #  0; line:     2-    3; sop:     0; eop:     4; out1:  -2
    path #1: 0, 
    

    更多指令参见:http://php.net/manual/en/internals2.opcodes.list.php,同时列出了每条指令的案例

  • 相关阅读:
    两分钟彻底让你明白Android Activity生命周期(图文)!
    C++命名空间 namespace的作用和使用解析
    编译型语言、解释型语言、静态类型语言、动态类型语言概念与区别
    git 使用详解(8)-- tag打标签
    C#托管代码与C++非托管代码互相调用
    Qt属性表控件的使用 QtTreePropertyBrowser
    在VS2010上使用C#调用非托管C++生成的DLL文件(图文讲解)
    (二十二)访问者模式详解(伪动态双分派)
    (二十一)状态模式详解(DOTA版)
    (二十)职责链模式详解(都市异能版)
  • 原文地址:https://www.cnblogs.com/chenpingzhao/p/4648059.html
Copyright © 2011-2022 走看看