Skip to content

Commit

Permalink
refactor: snapshot method renamed to takeSnapshot
Browse files Browse the repository at this point in the history
  • Loading branch information
petrknap committed Oct 19, 2024
1 parent 3ff471d commit f0cef91
Show file tree
Hide file tree
Showing 13 changed files with 79 additions and 84 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -50,35 +50,35 @@ echo doSomething(new NullProfiler());

## Useful features

### Snapshots
### Take snapshot

If you need to **measure the current values**, just call the `snapshot` method on the [`Profiling`](./src/Profiling.php).
If you need to **measure the current values**, just call the `takeSnapshot` method on the [`Profiling`](./src/Profiling.php), or a [profiler](./src/ProfilerInterface.php).

```php
namespace PetrKnap\Profiler;

$profiling = Profiling::start();
// do something
$profiling->snapshot();
$profiling->takeSnapshot();
// do something more
$profile = $profiling->finish();

printf('There are %d memory usage records.', count($profile->getMemoryUsages()));
```

If you want to automate it then use a [snapshot on tick](#snapshot-on-tick).
If you want to automate it then [take snapshot on tick](#take-snapshot-on-tick).
Or you can use a more practical [cascade profiling](#cascade-profiling).

#### Snapshot on tick
#### Take snapshot on tick

For greater precision, you can force **snapshot on each `N` tick**.
For greater precision, you can take **snapshot on each `N` tick**.

```php
declare(ticks=2); // this declaration is important (N=2)

namespace PetrKnap\Profiler;

$profiling = Profiling::start(snapshotOnTick: true);
$profiling = Profiling::start(takeSnapshotOnTick: true);
(fn () => 'something')();
$profile = $profiling->finish();

Expand Down
11 changes: 0 additions & 11 deletions src/Exception/ProfilerCouldNotSnapshotOutsideParentProfile.php

This file was deleted.

11 changes: 11 additions & 0 deletions src/Exception/ProfilerCouldNotTakeSnapshotOutsideParentProfile.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 LogicException;

final class ProfilerCouldNotTakeSnapshotOutsideParentProfile extends LogicException implements ProfilerException
{
}
2 changes: 1 addition & 1 deletion src/NullProfiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ public function getMemoryUsages(): array
};
}

public function snapshot(): void
public function takeSnapshot(): void
{
}
}
35 changes: 17 additions & 18 deletions src/Profile.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,13 @@
*/
final class Profile implements ProcessableProfileInterface, ProfileWithOutputInterface
{
public const DO_NOT_SNAPSHOT_ON_TICK = false;
public const DO_NOT_TAKE_SNAPSHOT_ON_TICK = false;

private const MICROTIME_FORMAT = '%.6f';
private const SORTED_BY_TIME = true;

private ProfileState $state;
private bool|null $isSnapshotingOnTick;
private bool|null $isTakingSnapshotOnTick;
private OptionalFloat $timeBefore;
private OptionalInt $memoryUsageBefore;
private OptionalFloat $timeAfter;
Expand All @@ -43,10 +43,10 @@ final class Profile implements ProcessableProfileInterface, ProfileWithOutputInt
private Optional $outputOption;

public function __construct(
bool $snapshotOnTick = self::DO_NOT_SNAPSHOT_ON_TICK,
bool $takeSnapshotOnTick = self::DO_NOT_TAKE_SNAPSHOT_ON_TICK,
) {
$this->state = ProfileState::Created;
$this->isSnapshotingOnTick = $snapshotOnTick ? false : null;
$this->isTakingSnapshotOnTick = $takeSnapshotOnTick ? false : null;
$this->timeBefore = OptionalFloat::empty();
$this->memoryUsageBefore = OptionalInt::empty();
$this->timeAfter = OptionalFloat::empty();
Expand All @@ -56,7 +56,7 @@ public function __construct(

public function __destruct()
{
$this->unregisterTickSnapshot();
$this->unregisterTickHandlers();
}

public function getState(): ProfileState
Expand All @@ -77,15 +77,15 @@ public function start(): void
$this->timeBefore = OptionalFloat::of(microtime(as_float: true));
$this->memoryUsageBefore = OptionalInt::of(memory_get_usage(real_usage: true));

$this->registerTickSnapshot();
$this->registerTickHandlers();
}

/**
* @throws Exception\ProfileCouldNotBeFinished
*/
public function finish(): void
{
$this->unregisterTickSnapshot();
$this->unregisterTickHandlers();

if ($this->state !== ProfileState::Started) {
throw new Exception\ProfileCouldNotBeFinished();
Expand All @@ -99,23 +99,23 @@ public function finish(): void
/**
* @throws Exception\ProfileCouldNotRegisterTickHandler
*/
public function registerTickSnapshot(): void
public function registerTickHandlers(): void
{
if ($this->isSnapshotingOnTick === false) {
register_tick_function([$this, 'snapshot']) or throw new Exception\ProfileCouldNotRegisterTickHandler();
$this->isSnapshotingOnTick = true;
if ($this->isTakingSnapshotOnTick === false) {
register_tick_function([$this, 'takeSnapshot']) or throw new Exception\ProfileCouldNotRegisterTickHandler();
$this->isTakingSnapshotOnTick = true;
}
}

public function unregisterTickSnapshot(): void
public function unregisterTickHandlers(): void
{
if ($this->isSnapshotingOnTick === true) {
unregister_tick_function([$this, 'snapshot']);
$this->isSnapshotingOnTick = false;
if ($this->isTakingSnapshotOnTick === true) {
unregister_tick_function([$this, 'takeSnapshot']);
$this->isTakingSnapshotOnTick = false;
}
}

public function snapshot(): void
public function takeSnapshot(): void
{
$this->memoryUsages[sprintf(self::MICROTIME_FORMAT, microtime(as_float: true))] = memory_get_usage(real_usage: true);
}
Expand Down Expand Up @@ -145,8 +145,7 @@ public function setOutput(mixed $output): void

public function getOutput(): mixed
{
/** @var TOutput */
return $this->outputOption->orElseThrow()->orElse(null);
return $this->outputOption->orElseThrow()->orElse(null); // @phpstan-ignore return.type
}

public function addChild(ProfileInterface $child): void
Expand Down
16 changes: 7 additions & 9 deletions src/Profiler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,22 +6,20 @@

/* final */class Profiler implements ProfilerInterface
{
/**
* @param bool $snapshotOnTick if true, it will do snapshot on each tick
*/
public function __construct(
private readonly bool $snapshotOnTick = Profile::DO_NOT_SNAPSHOT_ON_TICK,
private readonly bool $takeSnapshotOnTick = Profile::DO_NOT_TAKE_SNAPSHOT_ON_TICK,
/**
* @deprecated
* @deprecated backward compatibility with old named argument calls
*
* @todo remove it
*/
private readonly bool $listenToTicks = Profile::DO_NOT_SNAPSHOT_ON_TICK,
private readonly bool $listenToTicks = Profile::DO_NOT_TAKE_SNAPSHOT_ON_TICK,
) {
}

public function profile(callable $callable): ProcessableProfileInterface & ProfileWithOutputInterface
{
$profiling = Profiling::start($this->snapshotOnTick, $this->listenToTicks);
$profiling = Profiling::start($this->takeSnapshotOnTick, $this->listenToTicks);
$output = $callable(Profiling::createNestedProfiler($profiling));
/** @var Profile<mixed> $profile */
$profile = $profiling->finish();
Expand All @@ -30,8 +28,8 @@ public function profile(callable $callable): ProcessableProfileInterface & Profi
return $profile; // @phpstan-ignore return.type
}

public function snapshot(): void
public function takeSnapshot(): void
{
throw new Exception\ProfilerCouldNotSnapshotOutsideParentProfile();
throw new Exception\ProfilerCouldNotTakeSnapshotOutsideParentProfile();
}
}
4 changes: 2 additions & 2 deletions src/ProfilerInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ interface ProfilerInterface
public function profile(callable $callable): ProcessableProfileInterface & ProfileWithOutputInterface;

/**
* @throws Exception\ProfilerCouldNotSnapshotOutsideParentProfile
* @throws Exception\ProfilerCouldNotTakeSnapshotOutsideParentProfile
*/
public function snapshot(): void;
public function takeSnapshot(): void;
}
34 changes: 16 additions & 18 deletions src/Profiling.php
Original file line number Diff line number Diff line change
Expand Up @@ -11,35 +11,33 @@ final class Profiling
*/
private function __construct(
private readonly Profile $profile,
private readonly bool $snapshotOnTick,
private readonly bool $takeSnapshotOnTick,
) {
}

/**
* @param bool $snapshotOnTick if true, it will do snapshot on each tick
*/
public static function start(
bool $snapshotOnTick = Profile::DO_NOT_SNAPSHOT_ON_TICK,
bool $takeSnapshotOnTick = Profile::DO_NOT_TAKE_SNAPSHOT_ON_TICK,
/**
* @deprecated
* @deprecated backward compatibility with old named argument calls
*
* @todo remove it
*/
bool $listenToTicks = Profile::DO_NOT_SNAPSHOT_ON_TICK,
bool $listenToTicks = Profile::DO_NOT_TAKE_SNAPSHOT_ON_TICK,
): self {
$profile = new Profile($listenToTicks || $snapshotOnTick);
$profile = new Profile($listenToTicks || $takeSnapshotOnTick);
$profile->start();

return new self($profile, $listenToTicks || $snapshotOnTick);
return new self($profile, $listenToTicks || $takeSnapshotOnTick);
}

/**
* @throws Exception\ProfilingHasBeenAlreadyFinished
*/
public function snapshot(): void
public function takeSnapshot(): void
{
$this->checkProfileState();

$this->profile->snapshot();
$this->profile->takeSnapshot();
}

/**
Expand All @@ -59,7 +57,7 @@ public function finish(): ProfileInterface
*/
public static function createNestedProfiler(Profiling $profiling): ProfilerInterface
{
return new class ($profiling->profile, $profiling->snapshotOnTick) extends Profiler {
return new class ($profiling->profile, $profiling->takeSnapshotOnTick) extends Profiler {
/**
* @param Profile<mixed> $parentProfile
*/
Expand All @@ -68,7 +66,7 @@ public function __construct(
bool $snapshotOnTick,
) {
parent::__construct(
snapshotOnTick: $snapshotOnTick,
takeSnapshotOnTick: $snapshotOnTick,
);
}

Expand All @@ -78,23 +76,23 @@ public function profile(callable $callable): ProcessableProfileInterface & Profi
throw new Exception\ParentProfileIsNotStarted();
}

$this->parentProfile->unregisterTickSnapshot();
$this->parentProfile->unregisterTickHandlers();
try {
$profile = parent::profile($callable);
$this->parentProfile->addChild($profile);

return $profile;
} finally {
$this->parentProfile->registerTickSnapshot();
$this->parentProfile->registerTickHandlers();
}
}

public function snapshot(): void
public function takeSnapshot(): void
{
if ($this->parentProfile->getState() !== ProfileState::Started) {
throw new Exception\ProfilerCouldNotSnapshotOutsideParentProfile();
throw new Exception\ProfilerCouldNotTakeSnapshotOutsideParentProfile();
}
$this->parentProfile->snapshot();
$this->parentProfile->takeSnapshot();
}
};
}
Expand Down
4 changes: 2 additions & 2 deletions tests/NullProfilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -42,11 +42,11 @@ public function testProfileDoesNotRunProcessorAndReturnsCallablesOutput(): void
self::assertSame('output', $output);
}

public function testSnapshotDoesNotThrow(): void
public function testTakeSnapshotDoesNotThrow(): void
{
$profiler = new NullProfiler();

$profiler->snapshot();
$profiler->takeSnapshot();

self::assertTrue(true);
}
Expand Down
10 changes: 5 additions & 5 deletions tests/ProfileTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -26,20 +26,20 @@ public function testAddsChildren(): void
self::assertSame([$child1, $child2], $parent->getChildren());
}

#[DataProvider('dataSnapshotsOnTick')]
public function testSnapshotsOnTick(bool|null $shouldItSnapshot): void
#[DataProvider('dataTakesSnapshotOnTick')]
public function testTakesSnapshotOnTick(bool|null $shouldItTakeSnapshot): void
{
$profile = $shouldItSnapshot === null ? new Profile() : new Profile(snapshotOnTick: $shouldItSnapshot);
$profile = $shouldItTakeSnapshot === null ? new Profile() : new Profile(takeSnapshotOnTick: $shouldItTakeSnapshot);
$profile->start();
for ($i = 0; $i < 5; $i++) {
$i = (fn (int $i): int => $i)($i);
}
$profile->finish();

self::assertCount($shouldItSnapshot === true ? 9 : 2, $profile->getMemoryUsages());
self::assertCount($shouldItTakeSnapshot === true ? 9 : 2, $profile->getMemoryUsages());
}

public static function dataSnapshotsOnTick(): array
public static function dataTakesSnapshotOnTick(): array
{
return [
'default' => [null],
Expand Down
10 changes: 5 additions & 5 deletions tests/ProfilerTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -38,21 +38,21 @@ public function testReturnsCallablesOutput(): void
self::assertSame('output', $profile->getOutput());
}

public function testSnapshotsOnParentProfile(): void
public function testTakesSnapshotOnParentProfile(): void
{
$profiler = new Profiler();

$profile = $profiler->profile(static fn (ProfilerInterface $profiler) => $profiler->snapshot());
$profile = $profiler->profile(static fn (ProfilerInterface $profiler) => $profiler->takeSnapshot());

self::assertCount(2 + 1, $profile->getMemoryUsages());
}

public function testSnapshotsThrowsOutsideProfile(): void
public function testTakeSnapshotThrowsOutsideParentProfile(): void
{
$profiler = new Profiler();

self::expectException(Exception\ProfilerCouldNotSnapshotOutsideParentProfile::class);
self::expectException(Exception\ProfilerCouldNotTakeSnapshotOutsideParentProfile::class);

$profiler->snapshot();
$profiler->takeSnapshot();
}
}
Loading

0 comments on commit f0cef91

Please sign in to comment.