pyrsmk / streetfight
一个简单的基准测试工具
6.0.4
2019-08-21 15:03 UTC
Requires
- php: >=7.2.0
- pyrsmk/funktions: ^0
- pyrsmk/illuminator: ^3
Requires (Dev)
- pyrsmk/minisuite: ^5.0
This package is auto-updated.
Last update: 2024-09-11 16:23:02 UTC
README
StreetFight是一个基准测试工具,旨在快速了解某段代码与另一段代码相比性能如何。它并不打算成为一个详尽的性能分析库,可能不会再进一步发展。
注意,StreetFight遵循优雅对象原则,并在内部使用Funktions的帮助下进行一些函数式编程。
安装
StreetFight需要PHP 7.2。
composer require pyrsmk/streetfight
示例
以下是执行基准测试并直接从其中检索报告的常见方式。此示例比较了预增量操作和后增量操作的性能。
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Match\AutoTimedMatch; use StreetFight\Report\Report; use StreetFight\Report\PercentageReport; use StreetFight\Report\DescSortedReport; $report = // Sort the report in descending direction new DescSortedReport( // Convert the seconds report to percentage new PercentageReport( // Create a report to process match results new Report( // Create a match to process the benchmark for a certain time // (here, AutoTimedMatch will compute automatically the time of the match) // (see below for types of match) new AutoTimedMatch( // A typical round... new Round( // ...with a challenger list new ChallengerList( new Challenger('Pre-increment', function () { $i = 0; ++$i; }), new Challenger('Post-increment', function () { $i = 0; $i++; }) ) ) ) ) ) ); var_dump($report->asPercentages()); /* [ 'Post-increment' => 100, 'Pre-increment' => 98.84 ] */
匹配对象
有三种类型的匹配
StreetFight\Match\Match(int $rounds, RoundInterface $round)
:它将运行一定数量的回合,并需要一个StreetFight\Round\Round
对象StreetFight\Match\TimedMatch(int $time, RoundInterface $round)
:它将在基准测试运行期间至少运行指定毫秒的时间,并需要一个StreetFight\Round\Round
对象StreetFight\Match\AutoTimedMatch(RoundInterface $round)
:与TimedMatch
相反,它将自动计算基准测试运行的最大时间,并仅接受一个StreetFight\Round\Round
对象作为参数
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Match\Match; new Match( 100, // Will iterate 100 times new Round( new ChallengerList( new Challenger('Pre-increment', function () { $i = 0; ++$i; }), new Challenger('Post-increment', function () { $i = 0; $i++; }) ) ) )
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Match\TimedMatch; new TimedMatch( 5000, // Will run for 5 seconds at least new Round( new ChallengerList( new Challenger('Pre-increment', function () { $i = 0; ++$i; }), new Challenger('Post-increment', function () { $i = 0; $i++; }) ) ) )
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Match\AutoTimedMatch; // The recommended and simplest way to run the benchmark new AutoTimedMatch( new Round( new ChallengerList( new Challenger('Pre-increment', function () { $i = 0; ++$i; }), new Challenger('Post-increment', function () { $i = 0; $i++; }) ) ) )
报告对象
有几种类型的Report
对象
StreetFight\Report\Report(MatchInterface $match)
:主要的Report
对象,只能接受一个Match
对象作为参数;结果以原始秒为单位返回StreetFight\Report\RoundedSecondsReport
:主要Report
对象的装饰器;结果以秒为单位四舍五入到两位小数StreetFight\Report\MillisecondsReport
:主要Report
对象的装饰器;结果以毫秒为单位返回StreetFight\Report\MicrosecondsReport
:主要Report
对象的装饰器;结果以微秒为单位返回StreetFight\Report\PercentageReport
:主要Report
对象的装饰器;结果以百分比形式返回StreetFight\Report\AscSortedReport
:一个装饰器,将报告按升序排序StreetFight\Report\DescSortedReport
:一个装饰器,将报告按降序排序
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Match\AutoTimedMatch; use StreetFight\Report\Report; use StreetFight\Report\MicrosecondsReport; use StreetFight\Report\AscSortedReport; // Sort the report new AscSortedReport( // Format the report results in microseconds new MicrosecondsReport( // The main Report object new Report( new AutoTimedMatch( new Round( new ChallengerList( new Challenger('Pre-increment', function () { $i = 0; ++$i; }), new Challenger('Post-increment', function () { $i = 0; $i++; }) ) ) ) ) ) )
设置BEFORE和AFTER钩子
如果您需要运行一些特定的例程,您可以在Round
对象中设置它们
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Hook\Hook; new Round( new ChallengerList( new Challenger('file_put_contents (overwrite)', function () { file_put_contents('foo.txt', 'bar'); }), new Challenger('fwrite (overwrite)', function () { $f = fopen('foo.txt', 'w'); fwrite($f, 'bar'); fclose($f); }), new Challenger('file_put_contents (append)', function () { file_put_contents('foo.txt', 'bar', FILE_APPEND); }), new Challenger('fwrite (append)', function () { $f = fopen('foo.txt', 'a'); fwrite($f, 'bar'); fclose($f); }), ), // Set a hook that will be run BEFORE each task of each iteration new Hook(function () { touch('foo.txt'); }), // Set a hook that will be run AFTER each task of each iteration new Hook(function () { unlink('foo.txt'); }) )
向任务传递一些数据
如上例所示,相同的数据被用于所有任务。此外,我们可能需要在每个迭代中生成随机数据。但是,由于可变性使得StreetFight难以跟踪数据(并且将数据传递到对象中会复杂化API),因此决定在StreetFight本身之外以过程化方式定义它。以下是如何使用任意数据的示例,基于之前的示例
use StreetFight\Challenger\Challenger; use StreetFight\Challenger\ChallengerList; use StreetFight\Round\Round; use StreetFight\Hook\Hook; $data = [ 'filename' => 'foo.txt', 'content' => 'bar' ]; new Round( new ChallengerList( new Challenger('file_put_contents (overwrite)', function () use ($data) { file_put_contents($data['filename'], $data['content']); }), new Challenger('fwrite (overwrite)', function () use ($data) { $f = fopen($data['filename'], 'w'); fwrite($f, $data['content']); fclose($f); }), new Challenger('file_put_contents (append)', function () use ($data) { file_put_contents($data['filename'], $data['content'], FILE_APPEND); }), new Challenger('fwrite (append)', function () use ($data) { $f = fopen($data['filename'], 'a'); fwrite($f, $data['content']); fclose($f); }), ), new Hook(function () { touch($data['filename']); }), new Hook(function () { unlink($data['filename']); }) )
备注
根据您正在基准测试的代码,执行时间可能会超过PHP的max_execution_time
指令。只需设置set_time_limit(0)
即可。
许可
MIT.