From fbb52d2709ce65f4593cc04ed5d0632cbba4c629 Mon Sep 17 00:00:00 2001 From: David Badura Date: Mon, 9 Oct 2023 11:28:41 +0200 Subject: [PATCH 1/2] add benchmark tests --- .github/workflows/benchmark.yml | 113 ++++++++++++++++++ Makefile | 10 ++ phpbench.json | 54 +++++++++ tests/Benchmark/Fixture/NameChanged.php | 13 ++ tests/Benchmark/Fixture/ProfileCreated.php | 15 +++ tests/Benchmark/Fixture/ProfileId.php | 23 ++++ .../Benchmark/Fixture/ProfileIdNormalizer.php | 37 ++++++ tests/Benchmark/HydratorBench.php | 88 ++++++++++++++ 8 files changed, 353 insertions(+) create mode 100644 .github/workflows/benchmark.yml create mode 100644 phpbench.json create mode 100644 tests/Benchmark/Fixture/NameChanged.php create mode 100644 tests/Benchmark/Fixture/ProfileCreated.php create mode 100644 tests/Benchmark/Fixture/ProfileId.php create mode 100644 tests/Benchmark/Fixture/ProfileIdNormalizer.php create mode 100644 tests/Benchmark/HydratorBench.php diff --git a/.github/workflows/benchmark.yml b/.github/workflows/benchmark.yml new file mode 100644 index 0000000..6cd52b0 --- /dev/null +++ b/.github/workflows/benchmark.yml @@ -0,0 +1,113 @@ +# https://help.github.com/en/categories/automating-your-workflow-with-github-actions + +name: "Benchmark" + +on: + pull_request: + +jobs: + phpbench: + name: "Benchmark" + + runs-on: ${{ matrix.operating-system }} + + strategy: + matrix: + dependencies: + - "locked" + php-version: + - "8.2" + operating-system: + - "ubuntu-latest" + + steps: + - name: "Install PHP" + uses: "shivammathur/setup-php@2.25.5" + with: + coverage: "pcov" + php-version: "${{ matrix.php-version }}" + ini-values: memory_limit=-1 + extensions: pdo_sqlite + + - name: "Checkout base" + uses: actions/checkout@v3 + with: + ref: ${{ github.base_ref }} + + - uses: ramsey/composer-install@2.2.0 + with: + dependency-versions: ${{ matrix.dependencies }} + + - name: "phpbench on base" + run: "vendor/bin/phpbench run tests/Benchmark --progress=none --report=default --tag=base" + + - name: "Checkout" + uses: actions/checkout@v3 + with: + clean: false + + - uses: ramsey/composer-install@2.2.0 + with: + dependency-versions: ${{ matrix.dependencies }} + + - name: "phpbench diff" + run: "vendor/bin/phpbench run tests/Benchmark --progress=none --report=diff --ref=base > bench.txt" + + - name: "Get Bench Result" + id: phpbench + run: | + echo 'BENCH_RESULT<> $GITHUB_ENV + cat bench.txt >> $GITHUB_ENV + echo 'EOF' >> $GITHUB_ENV + + - uses: actions/github-script@v6 + with: + script: | + // Get the existing comments. + const {data: comments} = await github.rest.issues.listComments({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.number, + }) + + // Find any comment already made by the bot. + const botComment = comments.find(comment => comment.user.id === 41898282) + const commentBody = ` + + Hello :wave: + +
+ here is the most recent benchmark result: + +

+ + \`\`\` + ${{ env.BENCH_RESULT }} + \`\`\` + +

+
+ + This comment gets update everytime a new commit comes in! + + `; + + if (context.payload.pull_request.head.repo.full_name !== 'patchlevel/event-sourcing') { + console.log('Not attempting to write comment on PR from fork'); + } else { + if (botComment) { + await github.rest.issues.updateComment({ + owner: context.repo.owner, + repo: context.repo.repo, + comment_id: botComment.id, + body: commentBody + }) + } else { + await github.rest.issues.createComment({ + owner: context.repo.owner, + repo: context.repo.repo, + issue_number: context.payload.number, + body: commentBody + }) + } + } diff --git a/Makefile b/Makefile index d90b09d..a15b772 100644 --- a/Makefile +++ b/Makefile @@ -41,5 +41,15 @@ static: psalm phpstan phpcs-check test: phpunit ## run tests +.PHONY: benchmark +benchmark: vendor ## run benchmarks + vendor/bin/phpbench run tests/Benchmark --report=default + +.PHONY: benchmark-diff-test +benchmark-diff-test: vendor ## run benchmarks + vendor/bin/phpbench run tests/Benchmark --revs=1 --report=default --progress=none --tag=base + vendor/bin/phpbench run tests/Benchmark --revs=1 --report=diff --progress=none --ref=base + + .PHONY: dev dev: static test ## run dev tools diff --git a/phpbench.json b/phpbench.json new file mode 100644 index 0000000..729b39d --- /dev/null +++ b/phpbench.json @@ -0,0 +1,54 @@ +{ + "$schema":"./vendor/phpbench/phpbench/phpbench.schema.json", + "runner.bootstrap": "vendor/autoload.php", + "runner.file_pattern": "*Bench.php", + "report.generators": { + "diff": { + "generator": "component", + "partition": ["benchmark_name"], + "components": [ + { + "component": "section", + "title": "{{ first(frame[\"benchmark_name\"]) }}", + "components": [ + { + "component": "table_aggregate", + "partition": ["subject_name", "variant_name"], + "groups": + { + "time (kde mode)": + { + "cols": ["time"] + }, + "memory": + { + "cols": ["memory"] + } + }, + "row": + { + "subject": "first(partition[\"subject_name\"]) ~ \" (\" ~ first(partition[\"variant_name\"]) ~ \")\"", + "time": + { + "type": "expand", + "partition": "suite_tag", + "cols": + { + "Tag: {{ key }}": "mode(partition[\"result_time_avg\"]) as time ~ ' (' ~ rstdev(partition['result_time_avg']) ~ ')'" + } + }, + "memory": + { + "type": "expand", + "partition": "suite_tag", + "cols": + { + "Tag: {{ key }} ": "mode(partition[\"result_mem_peak\"]) as memory" + } + } + } + }] + }] + } + } +} \ No newline at end of file diff --git a/tests/Benchmark/Fixture/NameChanged.php b/tests/Benchmark/Fixture/NameChanged.php new file mode 100644 index 0000000..13dcfb6 --- /dev/null +++ b/tests/Benchmark/Fixture/NameChanged.php @@ -0,0 +1,13 @@ +id; + } +} diff --git a/tests/Benchmark/Fixture/ProfileIdNormalizer.php b/tests/Benchmark/Fixture/ProfileIdNormalizer.php new file mode 100644 index 0000000..f867ebf --- /dev/null +++ b/tests/Benchmark/Fixture/ProfileIdNormalizer.php @@ -0,0 +1,37 @@ +toString(); + } + + public function denormalize(mixed $value): ProfileId|null + { + if ($value === null) { + return null; + } + + if (!is_string($value)) { + throw new InvalidArgumentException(); + } + + return ProfileId::fromString($value); + } +} diff --git a/tests/Benchmark/HydratorBench.php b/tests/Benchmark/HydratorBench.php new file mode 100644 index 0000000..4e8ae69 --- /dev/null +++ b/tests/Benchmark/HydratorBench.php @@ -0,0 +1,88 @@ +hydrator = new MetadataHydrator(); + + $object = $this->hydrator->hydrate(ProfileCreated::class, [ + 'profileId' => '1', + 'name' => 'foo', + ]); + + $this->hydrator->extract($object); + } + + #[Bench\Revs(10)] + public function benchHydrate1Object(): void + { + $this->hydrator->hydrate(ProfileCreated::class, [ + 'profileId' => '1', + 'name' => 'foo', + ]); + } + + #[Bench\Revs(10)] + public function benchExtract1Object(): void + { + $object = new ProfileCreated(ProfileId::fromString('1'), 'foo'); + + $this->hydrator->extract($object); + } + + #[Bench\Revs(10)] + public function benchHydrate1_000Objects(): void + { + for ($i = 0; $i < 1_000; $i++) { + $this->hydrator->hydrate(ProfileCreated::class, [ + 'profileId' => '1', + 'name' => 'foo', + ]); + } + } + + #[Bench\Revs(10)] + public function benchExtract1_000Objects(): void + { + $object = new ProfileCreated(ProfileId::fromString('1'), 'foo'); + + for ($i = 0; $i < 1_000; $i++) { + $this->hydrator->extract($object); + } + } + + #[Bench\Revs(10)] + public function benchHydrate1_000_000Objects(): void + { + for ($i = 0; $i < 1_000_000; $i++) { + $this->hydrator->hydrate(ProfileCreated::class, [ + 'profileId' => '1', + 'name' => 'foo', + ]); + } + } + + #[Bench\Revs(10)] + public function benchExtract1_000_000Objects(): void + { + $object = new ProfileCreated(ProfileId::fromString('1'), 'foo'); + + for ($i = 0; $i < 1_000_000; $i++) { + $this->hydrator->extract($object); + } + } +} From 6f2801c9a326418d266736363da7f0d8a1d056ca Mon Sep 17 00:00:00 2001 From: David Badura Date: Mon, 9 Oct 2023 11:30:27 +0200 Subject: [PATCH 2/2] fix workflows --- .github/workflows/coding-standard.yml | 3 --- .github/workflows/mutation-tests.yml | 3 --- .github/workflows/phpstan.yml | 3 --- .github/workflows/psalm.yml | 3 --- .github/workflows/unit.yml | 13 +++++-------- tests/Benchmark/HydratorBench.php | 13 ++++++++----- 6 files changed, 13 insertions(+), 25 deletions(-) diff --git a/.github/workflows/coding-standard.yml b/.github/workflows/coding-standard.yml index 9ee6db7..2dc2aee 100644 --- a/.github/workflows/coding-standard.yml +++ b/.github/workflows/coding-standard.yml @@ -4,9 +4,6 @@ name: "Check Coding Standard" on: pull_request: - branches-ignore: - - "[0-9]+.[0-9]+.x" - - "renovate/*" push: branches: - "[0-9]+.[0-9]+.x" diff --git a/.github/workflows/mutation-tests.yml b/.github/workflows/mutation-tests.yml index 267354f..c1fa595 100644 --- a/.github/workflows/mutation-tests.yml +++ b/.github/workflows/mutation-tests.yml @@ -4,9 +4,6 @@ name: "Mutation tests" on: pull_request: - branches-ignore: - - "[0-9]+.[0-9]+.x" - - "renovate/*" push: branches: - "[0-9]+.[0-9]+.x" diff --git a/.github/workflows/phpstan.yml b/.github/workflows/phpstan.yml index be65f77..67be957 100644 --- a/.github/workflows/phpstan.yml +++ b/.github/workflows/phpstan.yml @@ -4,9 +4,6 @@ name: "Static Analysis by PHPStan" on: pull_request: - branches-ignore: - - "[0-9]+.[0-9]+.x" - - "renovate/*" push: branches: - "[0-9]+.[0-9]+.x" diff --git a/.github/workflows/psalm.yml b/.github/workflows/psalm.yml index cc9c9de..f28e9b2 100644 --- a/.github/workflows/psalm.yml +++ b/.github/workflows/psalm.yml @@ -4,9 +4,6 @@ name: "Static Analysis by Psalm" on: pull_request: - branches-ignore: - - "[0-9]+.[0-9]+.x" - - "renovate/*" push: branches: - "[0-9]+.[0-9]+.x" diff --git a/.github/workflows/unit.yml b/.github/workflows/unit.yml index f186c7c..f1d7294 100644 --- a/.github/workflows/unit.yml +++ b/.github/workflows/unit.yml @@ -3,14 +3,11 @@ name: "Unit tests" on: - pull_request: - branches-ignore: - - "[0-9]+.[0-9]+.x" - - "renovate/*" - push: - branches: - - "[0-9]+.[0-9]+.x" - - "renovate/*" + pull_request: + push: + branches: + - "[0-9]+.[0-9]+.x" + - "renovate/*" jobs: phpunit: diff --git a/tests/Benchmark/HydratorBench.php b/tests/Benchmark/HydratorBench.php index 4e8ae69..704ca88 100644 --- a/tests/Benchmark/HydratorBench.php +++ b/tests/Benchmark/HydratorBench.php @@ -15,10 +15,13 @@ final class HydratorBench { private Hydrator $hydrator; - public function setUp(): void + public function __construct() { $this->hydrator = new MetadataHydrator(); + } + public function setUp(): void + { $object = $this->hydrator->hydrate(ProfileCreated::class, [ 'profileId' => '1', 'name' => 'foo', @@ -45,7 +48,7 @@ public function benchExtract1Object(): void } #[Bench\Revs(10)] - public function benchHydrate1_000Objects(): void + public function benchHydrate1000Objects(): void { for ($i = 0; $i < 1_000; $i++) { $this->hydrator->hydrate(ProfileCreated::class, [ @@ -56,7 +59,7 @@ public function benchHydrate1_000Objects(): void } #[Bench\Revs(10)] - public function benchExtract1_000Objects(): void + public function benchExtract1000Objects(): void { $object = new ProfileCreated(ProfileId::fromString('1'), 'foo'); @@ -66,7 +69,7 @@ public function benchExtract1_000Objects(): void } #[Bench\Revs(10)] - public function benchHydrate1_000_000Objects(): void + public function benchHydrate1000000Objects(): void { for ($i = 0; $i < 1_000_000; $i++) { $this->hydrator->hydrate(ProfileCreated::class, [ @@ -77,7 +80,7 @@ public function benchHydrate1_000_000Objects(): void } #[Bench\Revs(10)] - public function benchExtract1_000_000Objects(): void + public function benchExtract1000000Objects(): void { $object = new ProfileCreated(ProfileId::fromString('1'), 'foo');