CodeIgniter 基准测试类(CI_Benchmark)实战指南:标记计时、总执行时间与内存消耗 CodeIgniter 基准测试类CI_Benchmark实战指南标记计时、总执行时间与内存消耗【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniterCodeIgniter 内置的 Benchmarking 类CI_Benchmark在框架启动时自动加载并始终处于活跃状态允许开发者在任意两个标记点之间计算时间差并可在视图模板中输出整站执行时间与内存消耗。本文以 官方文档 benchmark.rst 为主体结合 Benchmark.php、CodeIgniter.php、Output.php 等核心源码与 Benchmark_test.php 测试用例带你从基本用法到底层原理全面掌握这套性能观测工具。基准测试类的工作原理类初始化与生命周期Benchmark 类是 CodeIgniter 少数几个无需手动加载的组件之一。在框架入口 CodeIgniter.php 中可以看到系统通过load_class(Benchmark, core)完成实例化并在实例化后立即打下第一个标记$BM load_class(Benchmark, core); $BM-mark(total_execution_time_start); $BM-mark(loading_time:_base_classes_start);也就是说计时从框架被调用的那一刻就已开始。此后框架在加载基础类完毕、实例化控制器前后分别打下多个内部标记见 CodeIgniter.php 与 CodeIgniter.php// 基础类加载完成后 $BM-mark(loading_time:_base_classes_end); // 控制器实例化前 $BM-mark(controller_execution_time_( .$class. / .$method. )_start); $CI new $class(); call_user_func_array(array($CI, $method), $params); // 控制器执行完毕后 $BM-mark(controller_execution_time_( .$class. / .$method. )_end);而计时的“终点”则由 Output 类在向浏览器发送最终视图之前打上。也就是说elapsed_time()不带参数调用时计时会一直持续到输出阶段才停止从而能精确反映整个系统的完整执行耗时。核心数据结构CI_Benchmark的源码非常精简Benchmark.php整个类只维护一个公开数组属性public $marker array();marker是一个以标记名称为键、以microtime(TRUE)浮点时间戳为值的关联数组。每次调用mark()都会向该数组写入一个新的键值对因此可以设置任意多组标记互不干扰。使用 Benchmark 类基本用法三步计时CI_Benchmark可以在控制器、视图或模型中使用基本流程只有三步标记一个起点标记一个终点调用elapsed_time()查看两者之间的耗时。官方文档给出的真实示例可放在控制器方法中$this-benchmark-mark(code_start); // 这里发生一些代码逻辑 $this-benchmark-mark(code_end); echo $this-benchmark-elapsed_time(code_start, code_end);文档特别强调code_start、code_end这样的命名完全是任意的它们只是两个标记点的名称。你可以使用任意单词也可以同时设置多组标记。例如$this-benchmark-mark(dog); // 一些代码逻辑 $this-benchmark-mark(cat); // 更多代码逻辑 $this-benchmark-mark(bird); echo $this-benchmark-elapsed_time(dog, cat); echo $this-benchmark-elapsed_time(cat, bird); echo $this-benchmark-elapsed_time(dog, bird);三组调用分别输出狗→猫、猫→鸟、狗→鸟三段区间的时间差标记之间的计时可以任意组合复用。方法签名与边界行为从源码可以看到elapsed_time()的完整签名Benchmark.phppublic function elapsed_time($point1 , $point2 , $decimals 4)其边界行为如下第一个参数为空字符串时直接返回{elapsed_time}伪变量而不是计算任何差值这个伪变量稍后由 Output 类替换为真实的总执行时间起点标记不存在时返回空字符串不会抛出异常终点标记不存在时自动以当前时间microtime(TRUE)作为终点——也就是说你甚至可以只打一个起点标记elapsed_time(start)会以“调用时刻”作为终点返回值格式通过number_format()格式化默认保留 4 位小数。测试用例 Benchmark_test.php 对上述行为做了完整验证它断言无参调用返回{elapsed_time}、不存在的起点返回空字符串并通过覆盖标记值的方式验证了$decimals从 0 到 4 的输出精度如1、1.0、1.00、1.000、1.0002还验证了“终点自动补全”的行为。为 Profiler 准备基准点如果希望自己的基准数据出现在 Profiler性能分析器面板中标记点的命名必须遵循特定规则每个标记点必须成对设置配对的两个标记名必须完全一致只是结尾分别以_start和_end收尾。例如$this-benchmark-mark(my_mark_start); // 一些代码逻辑... $this-benchmark-mark(my_mark_end); $this-benchmark-mark(another_mark_start); // 更多代码逻辑... $this-benchmark-mark(another_mark_end);Profiler 之所以能识别这类命名是因为其内部_compile_benchmarks()方法使用正则匹配所有以_end结尾的标记并检查对应的_start标记是否存在Profiler.phpif (preg_match(/(.?)_end$/i, $key, $match) isset($this-CI-benchmark-marker[$match[1]._end], $this-CI-benchmark-marker[$match[1]._start])) { $profile[$match[1]] $this-CI-benchmark-elapsed_time($match[1]._start, $key); }注意此正则忽略大小写/i修饰符因此My_Mark_start与my_mark_end也能被识别为一对。Profiler 面板默认会展示基准结果、SQL 查询和$_POST数据其中benchmarks区块默认开启见 profiling.rst。更多细节请参阅 Profiler 文档。显示总执行时间如果想在页面上显示“从 CodeIgniter 启动到最终输出发送到浏览器”的总耗时只需在任意一个视图模板中插入?php echo $this-benchmark-elapsed_time();?注意这里没有传任何参数。文档强调无参调用时计时器并不会在调用处停止而是会一直运行到最终输出发送给浏览器之前。因此这个函数放在视图的哪个位置都不影响结果它始终反映整站执行的总时长。如果你不想写纯 PHP也可以直接在视图模板中使用伪变量{elapsed_time}这背后是 Output 类的替换机制在 Output.php 的_display()方法中输出类会先调用$BM-elapsed_time(total_execution_time_start, total_execution_time_end)计算真实耗时然后用str_replace()将{elapsed_time}伪变量替换为计算结果$elapsed $BM-elapsed_time(total_execution_time_start, total_execution_time_end); if ($this-parse_exec_vars TRUE) { $memory round(memory_get_usage() / 1024 / 1024, 2).MB; $output str_replace(array({elapsed_time}, {memory_usage}), array($elapsed, $memory), $output); }这里total_execution_time_start正是框架入口处打下的第一个标记而total_execution_time_end在输出阶段被打下两者之差就是整站总执行时间。替换行为受 Output 类的$parse_exec_vars属性控制默认值为TRUEOutput.php。需要特别提醒如果你想测量控制器方法内部的某段代码必须自己设置起点和终点标记。总执行时间伪变量只反映整站层面的耗时无法替代局部分段计时。显示内存消耗如果你的 PHP 安装时启用了--enable-memory-limit可以在视图文件中通过以下代码显示整站消耗的内存量?php echo $this-benchmark-memory_usage();?同样地也可以使用伪变量形式{memory_usage}从源码看memory_usage()方法本身并不做任何计算它只是返回{memory_usage}字符串Benchmark.php。真正计算内存的是 Output 类在输出阶段用memory_get_usage()获取实际内存占用换算成 MB保留两位小数后替换掉伪变量$memory round(memory_get_usage() / 1024 / 1024, 2).MB;这也是文档强调“该函数只能在视图文件中使用”的原因——它只有在输出阶段被替换后才有实际意义反映的是整个应用的总内存消耗而非调用点的瞬时内存。类参考Class Reference下表为CI_Benchmark公开 API 的完整签名与行为说明mark($name)参数string $name—— 要设置的标记名称返回void说明设置一个基准标记点。可以多次调用以设置多个执行点用于分段计时。底层实现为$this-marker[$name] microtime(TRUE);。elapsed_time([$point1 [, $point2 [, $decimals 4]]])参数string $point1—— 起始标记点string $point2—— 结束标记点int $decimals—— 结果保留的小数位数默认 4返回string—— 两个标记点之间的耗时格式化后的字符串说明计算并返回两个标记点之间的时间差。当第一个参数为空时函数返回{elapsed_time}伪变量从而允许在模板中展示整站总执行时间真实数值由 Output 类在输出阶段替换。若$point1对应的标记不存在则返回空字符串若$point2不存在则以当前时间自动补全。memory_usage()返回string——{memory_usage}标记说明直接返回{memory_usage}伪变量。它允许你把该变量放在模板的任何位置内存数据直到输出阶段才被计算随后由 Output 类替换为真实值。实战建议与小结综合文档与源码使用 Benchmark 类的几个要点开箱即用无需加载或初始化$this-benchmark在控制器、视图、模型中随时可用局部计时对控制器方法内部的代码段计时务必自行调用mark(xxx_start)/mark(xxx_end)成对设置并通过elapsed_time(xxx_start, xxx_end)读取结果全局统计显示整站执行时间用无参elapsed_time()或{elapsed_time}伪变量显示整站内存消耗用memory_usage()或{memory_usage}伪变量两者仅限视图模板对接 Profiler需要被 Profiler 收集的标记必须成对命名且以_start/_end结尾例如db_query_start/db_query_end精度可控elapsed_time()的第三个参数$decimals可控制输出精度默认 4 位小数测试用例覆盖了 04 位的全部输出形态。这套机制虽然实现极简核心类仅约 80 行代码却为 CodeIgniter 应用提供了从入口到输出、从整站到局部代码块的完整时间与内存观测能力是性能排查与优化时最轻量的切入点。【免费下载链接】CodeIgniterOpen Source PHP Framework (originally from EllisLab)项目地址: https://gitcode.com/gh_mirrors/co/CodeIgniter创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考