Skip to content

Commit

Permalink
feat: added support for recording custom data
Browse files Browse the repository at this point in the history
  • Loading branch information
petrknap committed Oct 13, 2024
1 parent be8aa2f commit 8fd524e
Show file tree
Hide file tree
Showing 10 changed files with 103 additions and 0 deletions.
17 changes: 17 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,23 @@ echo (new Profiler())->profile(function (ProfilerInterface $profiler): string {
));
```

### Recording custom data

A [profiler](./src/ProfilerInterface.php) provides the `record` method to record custom data in a [profile](./src/ProfileInterface.php).

```php
namespace PetrKnap\Profiler;

$profile = (new Profiler())->profile(function (ProfilerInterface $profiler): void {
for ($i = 0; $i < 5; $i++) {
$profiler->record('main_loop', $i);
}
$profiler->record('main_loop', 'done');
});

echo implode(' -> ', $profile->getRecords('main_loop'));
```

---

Run `composer require petrknap/profiler` to install it.
Expand Down
11 changes: 11 additions & 0 deletions src/Exception/ProfilerCouldNotRecordData.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<?php

declare(strict_types=1);

namespace PetrKnap\Profiler\Exception;

use RuntimeException;

final class ProfilerCouldNotRecordData extends RuntimeException implements ProfilerException
{
}
9 changes: 9 additions & 0 deletions src/NullProfiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,15 @@ public function getMemoryUsages(): array
{
return [];
}

public function getRecords(string $of): array
{
return [];
}
};
}

public function record(string $type, mixed $data): void
{
}
}
24 changes: 24 additions & 0 deletions src/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
use PetrKnap\Optional\Optional;
use PetrKnap\Optional\OptionalFloat;
use PetrKnap\Optional\OptionalInt;
use PetrKnap\Shorts\ArrayShorts;

/**
* @internal object can apply breaking changes within the same major version
Expand All @@ -26,6 +27,7 @@ final class Profile implements ProcessableProfileInterface, ProfileWithOutputInt
private OptionalInt $memoryUsageBefore;
private OptionalFloat $timeAfter;
private OptionalInt $memoryUsageAfter;

/**
* @var array<ProfileInterface>
*/
Expand All @@ -35,6 +37,11 @@ final class Profile implements ProcessableProfileInterface, ProfileWithOutputInt
*/
private Optional $outputOption;

/**
* @var array<string, array<numeric-string, mixed>>
*/
private array $records = [];

public function __construct()
{
$this->state = ProfileState::Created;
Expand Down Expand Up @@ -140,6 +147,23 @@ public function getMemoryUsages(bool $sortedByTime = self::SORTED_BY_TIME): arra
);
}

public function addRecord(string $type, mixed $data): void
{
$records = $this->records[$type] ?? [];
$records[sprintf(self::MICROTIME_FORMAT, microtime(as_float: true))] = $data;
$this->records[$type] = $records;
}

public function getRecords(string $type, bool $sortedByTime = self::SORTED_BY_TIME): array
{
return self::expandRecords(
$this->records[$type] ?? [],
$this->children,
__FUNCTION__,
sortedByKey: $sortedByTime,
);
}

/**
* @template TRecord of mixed
*
Expand Down
5 changes: 5 additions & 0 deletions src/ProfileInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -25,4 +25,9 @@ public function getMemoryUsageChange(): int;
* @return array<numeric-string, int> bytes at {@see microtime}
*/
public function getMemoryUsages(): array;

/**
* @return array<numeric-string, mixed> data at {@see microtime}
*/
public function getRecords(string $type): array;
}
5 changes: 5 additions & 0 deletions src/Profiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,9 @@ public function profile(callable $callable): ProcessableProfileInterface & Profi

return $profile; // @phpstan-ignore return.type
}

public function record(string $type, mixed $data): void
{
throw new Exception\ProfilerCouldNotRecordData();
}
}
5 changes: 5 additions & 0 deletions src/ProfilerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,4 +14,9 @@ interface ProfilerInterface
* @return ProcessableProfileInterface<TOutput> & ProfileWithOutputInterface<TOutput>
*/
public function profile(callable $callable): ProcessableProfileInterface & ProfileWithOutputInterface;

/**
* @throws Exception\ProfilerCouldNotRecordData
*/
public function record(string $type, mixed $data): void;
}
9 changes: 9 additions & 0 deletions src/Profiling.php
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,15 @@ public function profile(callable $callable): ProcessableProfileInterface & Profi

return $profile;
}

public function record(string $type, mixed $data): void
{
try {
$this->parentProfile->addRecord($type, $data);
} catch (Exception\ProfileException $profileException) {
throw new Exception\ProfilerCouldNotRecordData(previous: $profileException);
}
}
};
}
}
17 changes: 17 additions & 0 deletions tests/ProfileInterfaceTestTrait.php
Original file line number Diff line number Diff line change
Expand Up @@ -56,4 +56,21 @@ public function testProfilesMemoryUsages(): void
self::assertEquals(2, array_shift($memoryUsages));
self::assertEquals(3, array_shift($memoryUsages));
}

public function testRecordsDataOfCustomType(): void
{
$profile = new Profile();
$profile->addRecord('a', 'a1');
$profile->addRecord('b', 'b1');
$profile->addRecord('a', 'a2');

self::assertSame(
['a1', 'a2'],
array_values($profile->getRecords('a')),
);
self::assertSame(
['b1'],
array_values($profile->getRecords('b')),
);
}
}
1 change: 1 addition & 0 deletions tests/ReadmeTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ public static function getExpectedOutputsOfPhpExamples(): iterable
'long-term-profiling' => '',
'how-to-enable-disable-it' => 'It took 0.0 s to do something.' . 'something' . 'something',
'cascade-profiling' => 'It took 0.0 s to do something.' . 'It took 0.0 s to do something before something and something, there are 1 children profiles.' . 'something',
'recording-custom-data' => '0 -> 1 -> 2 -> 3 -> 4 -> done',
];
}
}

0 comments on commit 8fd524e

Please sign in to comment.