Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

snapshot method renamed to takeSnapshot #14

Merged
merged 1 commit into from
Oct 19, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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;
}
36 changes: 17 additions & 19 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,16 +57,16 @@ 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
*/
public function __construct(
private readonly Profile $parentProfile,
bool $snapshotOnTick,
bool $takeSnapshotOnTick,
) {
parent::__construct(
snapshotOnTick: $snapshotOnTick,
takeSnapshotOnTick: $takeSnapshotOnTick,
);
}

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
Loading