Skip to content

Commit

Permalink
add benchmark tests
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidBadura committed Oct 9, 2023
1 parent 744a4b8 commit fbb52d2
Show file tree
Hide file tree
Showing 8 changed files with 353 additions and 0 deletions.
113 changes: 113 additions & 0 deletions .github/workflows/benchmark.yml
Original file line number Diff line number Diff line change
@@ -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/[email protected]"
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/[email protected]
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/[email protected]
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<<EOF' >> $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:
<details>
<summary>here is the most recent benchmark result:</summary>
<p>
\`\`\`
${{ env.BENCH_RESULT }}
\`\`\`
</p>
</details>
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
})
}
}
10 changes: 10 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
54 changes: 54 additions & 0 deletions phpbench.json
Original file line number Diff line number Diff line change
@@ -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"
}
}
}
}]
}]
}
}
}
13 changes: 13 additions & 0 deletions tests/Benchmark/Fixture/NameChanged.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Benchmark\Fixture;

final class NameChanged
{
public function __construct(
public string $name,
) {
}
}
15 changes: 15 additions & 0 deletions tests/Benchmark/Fixture/ProfileCreated.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Benchmark\Fixture;

final class ProfileCreated
{
public function __construct(
#[ProfileIdNormalizer]
public ProfileId $profileId,
public string $name,
) {
}
}
23 changes: 23 additions & 0 deletions tests/Benchmark/Fixture/ProfileId.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Benchmark\Fixture;

final class ProfileId
{
private function __construct(
private string $id,
) {
}

public static function fromString(string $id): self
{
return new self($id);
}

public function toString(): string
{
return $this->id;
}
}
37 changes: 37 additions & 0 deletions tests/Benchmark/Fixture/ProfileIdNormalizer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Benchmark\Fixture;

use Attribute;
use InvalidArgumentException;
use Patchlevel\Hydrator\Normalizer\Normalizer;

use function is_string;

#[Attribute(Attribute::TARGET_PROPERTY)]
final class ProfileIdNormalizer implements Normalizer
{
public function normalize(mixed $value): string
{
if (!$value instanceof ProfileId) {
throw new InvalidArgumentException();
}

return $value->toString();
}

public function denormalize(mixed $value): ProfileId|null
{
if ($value === null) {
return null;
}

if (!is_string($value)) {
throw new InvalidArgumentException();
}

return ProfileId::fromString($value);
}
}
88 changes: 88 additions & 0 deletions tests/Benchmark/HydratorBench.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
<?php

declare(strict_types=1);

namespace Patchlevel\Hydrator\Tests\Benchmark;

use Patchlevel\Hydrator\Hydrator;
use Patchlevel\Hydrator\MetadataHydrator;
use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileCreated;
use Patchlevel\Hydrator\Tests\Benchmark\Fixture\ProfileId;
use PhpBench\Attributes as Bench;

#[Bench\BeforeMethods('setUp')]
final class HydratorBench
{
private Hydrator $hydrator;

public function setUp(): void
{
$this->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);
}
}
}

0 comments on commit fbb52d2

Please sign in to comment.