CI框架源码解析四之基准测试类文件Benchmark.php

        本篇博客我们解析讲述的是基准测试类文件Benchmark.php,通过前面几篇博文的解析,我们已经了解到:CI框架中核心流程的核心功能都是由不同的类组件来完成的。这些类组件类似于一个一个单独的模块,不同的模块完成不同的功能,各模块之间可以相互调用,共同构成了CI框架的核心骨架。

        从本篇开始,将进一步去分析各类组件的实现细节,深入CI框架核心内容的黑盒内部(通过我们的解析研究之后,其实就应该是白盒了,仅仅对于应用来说,它应该算是黑盒),从而使我们更好的去认识、把握、使用这个开源框架。

        由于基准测试类文件Benchmark.php是CI框架中第一个加载的core类组件,因此我们的分析首先从该类组件开始。BenchMark的含义非常明确,使用过BenchMark工具的同学应该比较清楚,这是一个基准测试类组件。既然是BenchMark,我们便可大胆猜想,BM组件的主要功能就是记录程序的运行时间、内存使用、cpu使用等情况。

        这个组件结构较简单,只有一个$marker内部变量和三个对外的接口:

① mark($name);

② elapsed_time($point1 = '', $point2 = '', $decimals = 4);

③ memory_usage()

1、$marker

        $marker用于记录程序运行到某个点的时间,$marker:Benchmark类内部用于存放所有标记点的数组。它仅是一个变量数组,在这里我们就不多做解释了。

2、mark($name)

    public function mark($name)
    {
        //这个方法其实很简单,就是在程序的任意地方调用地方法时,会记录当前的时间点。
        $this->marker[$name] = microtime(TRUE);
    }

        在性能调试过程中,我们想更精确的了解类库加载时间,控制器方法执行时间,缓存操作时间怎么做?或者我们想很俗气的在网站底部显示一个:本次加载耗时0.007s应该怎么做?CI框架提供了一个叫Benchmark的基准测试类,用于计算两个标记点之间的时间差。

使用流程如下:

        Ⅰ 标记一个起始点;

        Ⅱ 标记一个结束点;

        Ⅲ 使用 elapsed_time 函数计算时间差。

    //标记一个起始点
    $this->benchmark->mark('code_init');
    //......
    //代码主体
    //......
    //标记一个结束点
    $this->benchmark->mark('code_end');
    //使用 elapsed_time 函数计算时间差。
    echo $this->benchmark->elapsed_time('code_start', 'code_end');
    //print_r($this->benchmark);这个方式也可以输出

        如果标记点名称成对出现并以 _start 和 _end 结束,那么可以用于性能分析器中显示这一基准测试数据。位于libraries下Profiler的_compile_benchmarks()方法会分析测试点mark数组中的KEY键,如果包含_start及_end的元素存在,会处理并显示到性能分析结果表中。

    $this->benchmark->mark('my_mark_start');
    // Some code happens here...
    $this->benchmark->mark('my_mark_end');

3、elapsed_time($point1 = '', $point2 = '', $decimals = 4)

    public function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
    {
        //如果第一个参数为空,即函数参数都为空的情况下,直接返回{elapsed_time}
        if ($point1 === '') {
            return '{elapsed_time}';
        }
        //如果$point1标记点不存在,则返回空
        if (!isset($this->marker[$point1])) {
            return '';
        }
        //如果$point2标记点不存在,则用当前时间生成一个$point2
        if (!isset($this->marker[$point2])) {
            $this->marker[$point2] = microtime(TRUE);
        }
        return number_format($this->marker[$point2] - $this->marker[$point1], $decimals);
    }

        如果elapsed_time不带任何参数,就可以显示从 CodeIgniter 运行开始到最终结果输出到浏览器之间花费的总时间。<?php echo $this->benchmark->elapsed_time();?>。也可以把{elapsed_time}放在VIEW视图里。

        如果没有给出明确的时间点,那么会计算出整个程序运行的时间。怎么可以做到计算出整个程序的运行时间的呢?其实执行此计算的是Output组件。而调用Benchmark::elapsed_time();(无参数)的时候,实质上先返回的并不是整个程序运行的时间,也不可能做到,实质返回的是一个{elapsed_time}标签,然后Output在处理输出的时候,再计算出整个程序运行时间,因为处理输出阶段程序可以视为处于最后阶段,于是可以近似计算出总时间,然后把输出中的{elapsed_time}替换掉。下面的memory_usage()原理相同。

4、memory_usage()

    public function memory_usage()
    {
        return '{memory_usage}';
    }

        此函数用来显示内存占用,在视图文件中 使用下面这行代码来显示整个系统所占用的内存大小:<?php echo $this->benchmark->memory_usage();?>。也可以{memory_usage};这个方法只能在视图文件中使用,显示的结果代表整个应用所占用的内存大小。方法很简单,就是返回{memory_usage}。

        具体实现是在输出类Output.php中实现的$memory = round(memory_get_usage() / 1024 / 1024, 2).'MB';然后用$memory替换了{memory_usage}这个核心函数是memory_get_usage()函数,函数原型int memory_get_usage ([ bool $real_usage = false ] )。如果$real_usage设置为 TRUE,获取系统分配的真实内存尺寸。如果未设置或者设置为 FALSE,将是 emalloc() 报告使用的内存量。php5.2.1 后不需要在编译时使用 --enable-memory-limit选项就能够使用这个函数。


归纳一下常用的检测:

        Ⅰ 用microtime函数可以分析程序执行时间。microtime — 返回当前 Unix 时间戳和微秒数。microtime()返回的结果是以 "msec sec" 的格式返回一个字符串,其中 sec(时间戳)是自 Unix 纪元起到现在的秒数,与time()返回的结果一样。msec 是微秒部分。microtime(true)返回的值是sec+msec的和,保留四位小数。

        Ⅱ memory_get_usage可以分析内存占用空间(php5.2.1 后不需要在编译时使用 --enable-memory-limit选项就能够使用这个函数)。memory_get_peak_usage()可以返回分配给 PHP 内存的峰值。


        最后,贴一下整个基准测试类Benchmark.php文件的源码(注释版):

    <?php
    /**
     * =======================================
     * Created by Pocket Knife Technology.
     * User: ZhiHua_W
     * Date: 2016/10/18 0311
     * Time: 上午 09:20
     * Project: CodeIgniter框架—源码分析
     * Power: Analysis for Benchmark.php
     * =======================================
     */
    
    //此句不再多说
    defined('BASEPATH') OR exit('No direct script access allowed');
    
    /**
     * Class CI_Benchmark
     * 这类使您可以标记点,计算它们之间的时间差
     * 内存消耗也可以显示。
     */
    class CI_Benchmark
    {
        //记录程序运行到某个点的时间
        //$marker:Benchmark类内部用于存放所有标记点的数组
        public $marker = array();
    
        /**
         * 这个可以在程序任意地方调用,加入一个mark
         * mark($name)方法,设置标记点,并插入一下key为标记名,值为当前时间的元素到$this->marker数组。
         */
        public function mark($name)
        {
            //这个方法其实很简单,就是在程序的任意地方调用地方法时,会记录当前的时间点。
            $this->marker[$name] = microtime(TRUE);
        }
    
        /**
         * 计算任意两个点之间的运行时间
         * elapsed_time($point1 = '', $point2 = '', $decimals = 4)方法,计算间隔时间。
         * 如果elapsed_time不带任何参数,就返加return '{elapsed_time}',
         * 而这个{elapsed_time}标记最终在output类中被替换成$BM->elapsed_time('total_execution_time_start', 'total_execution_time_end');
         * 在CodeIgniter.php中可以看到在composer autoload代码块后设置起始点$BM->mark('total_execution_time_start');
         * total_execution_time_end点是不存在的,elapsed_time方法会插入一个同名点,并用当前时间赋值。
         * 实际上最后就是输出当前调用elapsed_time函数的时间减去mark('total_execution_time_start')的时间的差值。
         */
        public function elapsed_time($point1 = '', $point2 = '', $decimals = 4)
        {
            //如果第一个参数为空,即函数参数都为空的情况下,直接返回{elapsed_time}
            if ($point1 === '') {
                return '{elapsed_time}';
            }
            //如果$point1标记点不存在,则返回空
            if (!isset($this->marker[$point1])) {
                return '';
            }
            //如果$point2标记点不存在,则用当前时间生成一个$point2
            if (!isset($this->marker[$point2])) {
                $this->marker[$point2] = microtime(TRUE);
            }
            return number_format($this->marker[$point2] - $this->marker[$point1], $decimals);
        }
    
        /**
         * 显示内存占用
         * 在视图文件中 使用下面这行代码来显示整个系统所占用的内存大小:
         * <?php echo $this->benchmark->memory_usage();?>,也可以{memory_usage},
         * 这个方法只能在视图文件中使用,显示的结果代表整个应用所占用的内存大小。
         * 方法很简单,就是返回{memory_usage}
         *
         * 具体实现是在输出类Output.php中实现的
         * $memory = round(memory_get_usage() / 1024 / 1024, 2).'MB';
         * 然后用$memory替换了{memory_usage}
         * 这个核心函数是memory_get_usage()函数,
         * 函数原型int memory_get_usage ([ bool $real_usage = false ] )。如果$real_usage设置为 TRUE,获取系统分配的真实内存尺寸。
         * 如果未设置或者设置为 FALSE,将是 emalloc() 报告使用的内存量。
         * php5.2.1 后不需要在编译时使用 --enable-memory-limit选项就能够使用这个函数
         */
        public function memory_usage()
        {
            return '{memory_usage}';
        }
    
    }

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页