|
10 | 10 | [](https://github.com/sponsors/nyamsprod) |
11 | 11 |
|
12 | 12 | A minimalist profiler for PHP. The profiler is embeddable, multi-metric, and framework-agnostic |
13 | | -It fills the gap between a basic timer and full-blown profilers like [Xdebug](https://xdebug.org/) or [Blackfire](https://www.blackfire.io/). |
| 13 | +It fills the gap between a basic timer and full-blown profilers like: [PHPBench](https://phpbench.readthedocs.io/en/latest/), |
| 14 | +[Xdebug](https://xdebug.org/), [Blackfire](https://www.blackfire.io/). |
14 | 15 |
|
15 | 16 | ## Installation |
16 | 17 |
|
@@ -121,7 +122,7 @@ and formatted. |
121 | 122 | use Bakame\Aide\Profiler\Profiler; |
122 | 123 |
|
123 | 124 | // you create a new Profiler by passing the callback you want to profile |
124 | | -$report = Profiler::report($service->calculateHeavyStuff(...)); |
| 125 | +$report = Profiler::report($service->calculateHeavyStuff(...), 500); |
125 | 126 |
|
126 | 127 | // Access the raw statistical metrics |
127 | 128 | $report->executionTime->minimum; // Minimum execution time (as float|int, in nanoseconds) |
@@ -532,6 +533,25 @@ echo json_encode($marker), PHP_EOL; |
532 | 533 | ``` |
533 | 534 | See a [sample marker JSON output](./examples/marker-sample.json) for a complete structure. |
534 | 535 |
|
| 536 | +In order to facilitate JSON export, the package has a dedicated `JsonExporter` class |
| 537 | +which will be able to store the generated json in the specified location. It supports |
| 538 | +streams, string path and `SplFileInfo` objects. |
| 539 | + |
| 540 | +```php |
| 541 | +use Bakame\Aide\Profiler\JsonExporter; |
| 542 | +use Bakame\Aide\Profiler\Profiler; |
| 543 | + |
| 544 | +$report = Profiler::report($service->calculateHeavyStuff(...), 500); |
| 545 | +$exporter = new JsonExporter('path/to/store/the/profile.json', JSON_PRETTY_PRINT|JSON_BIGINT_AS_STRING); |
| 546 | +$exporter->exportReport($report); |
| 547 | +``` |
| 548 | +The report will be stored in the designated location. |
| 549 | + |
| 550 | +> [!IMPORTANT] |
| 551 | +> If you try to store multiple export in the same file (specified by a string) |
| 552 | +> They will get overwritten and only the last export will be stored. |
| 553 | +> To get the data appended provide an already open `resource` or `SplFileObject`. |
| 554 | +
|
535 | 555 | #### CLI |
536 | 556 |
|
537 | 557 | If you have the `symfony\console` package installed in your application, you can export |
@@ -610,6 +630,138 @@ $exporter->exportProfilter($profiler); |
610 | 630 |
|
611 | 631 | Remember to change the `$tracerProvider` to connect to your own environment and server. |
612 | 632 |
|
| 633 | +### CLI command |
| 634 | + |
| 635 | +A CLI Command is available to allow you to benchmark PHP **functions and methods** located in a specific file or directory using the custom `#[Profile]` attribute. |
| 636 | + |
| 637 | +This is especially useful for: |
| 638 | + |
| 639 | +- Automating performance regressions in CI pipelines |
| 640 | +- Profiling code outside the context of an application |
| 641 | + |
| 642 | +#### Usage |
| 643 | + |
| 644 | +```bash |
| 645 | +php bin/phpProfiler --path=your/script.php [--output=cli|json] [--info] [--help] |
| 646 | +``` |
| 647 | + |
| 648 | +| Option | Description | |
| 649 | +|---------------------|-------------------------------------------------------------------------------| |
| 650 | +| `--path[=PATH]` | **(Required)** Path to the file to scan for profiled functions and methods. | |
| 651 | +| `--output[=OUTPUT]` | Output format: either `json` or `cli` (default) table. | |
| 652 | +| `-i`, `--info` | Additionally display system-level profiling metadata (PHP version, CPU, etc). | |
| 653 | +| `-h`, `--help` | Show help for the command. | |
| 654 | + |
| 655 | +#### Example |
| 656 | + |
| 657 | +let's assume you have the following file located in `/path/profiler/test.php`. |
| 658 | + |
| 659 | +```php |
| 660 | +<?php |
| 661 | + |
| 662 | +declare(strict_types=1); |
| 663 | + |
| 664 | +namespace Foobar\Baz; |
| 665 | + |
| 666 | +use Bakame\Aide\Profiler\Profile; |
| 667 | +use function random_int; |
| 668 | +use function usleep; |
| 669 | + |
| 670 | +require 'vendor/autoload.php'; |
| 671 | + |
| 672 | +trait TimerTrait { |
| 673 | + #[Profile(type: Profile::METRICS, iterations: 10)] |
| 674 | + private function test() : int { |
| 675 | + usleep(100); |
| 676 | + |
| 677 | + return random_int(1, 100); |
| 678 | + } |
| 679 | +} |
| 680 | + |
| 681 | +enum Foobar |
| 682 | +{ |
| 683 | + use TimerTrait; |
| 684 | + |
| 685 | + case Foobar; |
| 686 | +} |
| 687 | + |
| 688 | +#[Profile(type: Profile::REPORT, iterations: 20, warmup: 2)] |
| 689 | +function test() : int { |
| 690 | + usleep(100); |
| 691 | + |
| 692 | + return random_int(1, 100); |
| 693 | +} |
| 694 | +``` |
| 695 | +If you run the following command: |
| 696 | + |
| 697 | +```bash |
| 698 | +php bin/phpProfiler --path=/path/profiler/test.php |
| 699 | +``` |
| 700 | +It will output 2 console tables: |
| 701 | + |
| 702 | +```bash |
| 703 | +PHPProfiler 0.11.0 by Ignace Nyamagana Butera and contributors. |
| 704 | + |
| 705 | +Runtime: PHP 8.3.23 |
| 706 | +Platform: Linux |
| 707 | + |
| 708 | +Report for the function Foobar\Baz\test located in /path/profiler/test.php called 20 times |
| 709 | ++------------------------+---------------+------------+------------+--------------+------------+-----------+------------+------------+----------+-----------+ |
| 710 | +| Metric | Nb Iterations | Min Value | Max Value | Median Value | Sum | Range | Average | Variance | Std Dev | Coef Var | |
| 711 | ++------------------------+---------------+------------+------------+--------------+------------+-----------+------------+------------+----------+-----------+ |
| 712 | +| CPU Time | 20 | 7.000 µs | 32.000 µs | 8.000 µs | 183.000 µs | 25.000 µs | 9.150 µs | 28.128 μs² | 5.304 µs | 57.9621 % | |
| 713 | +| Execution Time | 20 | 132.125 µs | 158.208 µs | 133.292 µs | 2.701 ms | 26.083 µs | 135.029 µs | 32.436 μs² | 5.695 µs | 4.2178 % | |
| 714 | +| Memory Usage | 20 | 1.031 KB | 1.031 KB | 1.031 KB | 20.625 KB | 0.000 B | 1.031 KB | 0.000 B² | 0.000 B | 0.0000 % | |
| 715 | +| Peak Memory Usage | 20 | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B² | 0.000 B | 0.0000 % | |
| 716 | +| Real Memory Usage | 20 | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B² | 0.000 B | 0.0000 % | |
| 717 | +| Real Peak Memory Usage | 20 | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B | 0.000 B² | 0.000 B | 0.0000 % | |
| 718 | ++------------------------+---------------+------------+------------+--------------+------------+-----------+------------+------------+----------+-----------+ |
| 719 | +Average metrics for the method Foobar\Baz\Foobar::test located in /path/profiler/test.php called 10 times |
| 720 | ++------------------------------------+ |
| 721 | +| Execution Time: 140.213 µs | |
| 722 | +| CPU Time: 11.700 µs | |
| 723 | +| Memory Usage: 1.0 KB | |
| 724 | +| Real Memory Usage: 0.0 B | |
| 725 | +| Peak Memory Usage: 0.0 B | |
| 726 | +| Real Peak Memory Usage: 0.0 B | |
| 727 | ++------------------------------------+ |
| 728 | +``` |
| 729 | +
|
| 730 | +- one about the full report on the function `test` (this is equivalent as using `Profiler::report`) |
| 731 | +- the other about the average metrics for the `Foobar::test` method. (this is equivalent as using `Profiler::metrics`) |
| 732 | +
|
| 733 | +The `#[Profile]` attribute exposes the same arguments as the `Profiler` methods: |
| 734 | + |
| 735 | +- `iterations`: Number of times to execute the function for statistical significance. |
| 736 | +- `warmup`: (Optional) Number of warmup iterations before measuring. |
| 737 | +- `type`: Either `Profile::METRICS` or `Profile::REPORT`; To determine if you want the `Profiler::report` or the `Profiler::metrics` output. |
| 738 | + |
| 739 | +#### Notes |
| 740 | + |
| 741 | +The command line supports **function-level** and **method-level** profiling, including methods defined |
| 742 | +via traits, even inside Enums. |
| 743 | + |
| 744 | +- Functions or methods without a `#[Profile]` attribute will be ignored. |
| 745 | +- Functions or methods with arguments will also be ignored. |
| 746 | + |
| 747 | +All required dependencies should be loaded in the target file (use `require`, `include` or Composer autoload). |
| 748 | + |
| 749 | +#### Integration into CI |
| 750 | + |
| 751 | +You can run the profiler command in your CI pipelines to detect regressions or performance anomalies. |
| 752 | + |
| 753 | +```yaml |
| 754 | +- name: Run Profiler |
| 755 | + run: php bin/phpProfiler --path=/path/profiler/test.php --output=json |
| 756 | +``` |
| 757 | + |
| 758 | +> [!IMPORTANT] |
| 759 | +> The command line requires `symfony\console` and the `psr\log` interfaces to work. |
| 760 | + |
| 761 | +> [!CAUTION] |
| 762 | +> The command line can scan your full codebase if you specify a directory instead of a path. But |
| 763 | +> favor the cli output as the json output will not return a valid json file. |
| 764 | + |
613 | 765 | ### Helpers |
614 | 766 |
|
615 | 767 | #### Environment |
|
0 commit comments