Skip to content

Commit

Permalink
Adds diff calculation between two traces
Browse files Browse the repository at this point in the history
  • Loading branch information
butschster committed Dec 1, 2022
1 parent 5a9a044 commit bf40168
Show file tree
Hide file tree
Showing 6 changed files with 5,067 additions and 8 deletions.
95 changes: 95 additions & 0 deletions src/Converter/Diff.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
<?php

declare(strict_types=1);

namespace SpiralPackages\Profiler\Converter;

final class Diff implements \JsonSerializable
{
private readonly array $keys;
public readonly FlatterList $diff;
public readonly array $diffPercent;
private int $functionsCount;
private float $functionsCountPercent;

public function __construct(
private readonly FlatterList $current,
private readonly FlatterList $head,
) {
$this->keys = $current->getKeys();
$emptyData = \array_fill_keys($this->keys, 0);

$diff = [];
$diffPercent = [];

foreach ($current->getData() as $key => $baseData) {
$headData = $head->getData()[$key] ?? $emptyData;
$diff[$key] = $this->diffKeys($headData, $baseData);

if ($key === 'main()') {
$diffPercent[$key] = $this->diffPercentKeys($headData, $baseData);
}
}

$currentCount = $this->getFunctionCount($current);
$headCount = $this->getFunctionCount($head);

$this->functionsCount = $headCount - $currentCount;
$this->functionsCountPercent = $headCount / $currentCount;

$this->diff = new FlatterList($current->getKeys(), $diff);
$this->diffPercent = $diffPercent;
}

public function jsonSerialize(): array
{
return [
'current' => $this->current,
'head' => $this->head,
'diff' => $this->diff,
'functions_count' => $this->functionsCount,
'diff_percent' => $this->diffPercent,
'functions_count_percent' => $this->functionsCountPercent,
];
}


/**
* Get the total number of tracked function calls in this run.
*/
private function getFunctionCount(FlatterList $list): int
{
$total = 0;
foreach ($list->getData() as $data) {
$total += $data['ct'];
}

return $total;
}

private function diffKeys(array $a, array $b): array
{
$keys = $this->keys;
foreach ($keys as $key) {
$a[$key] -= $b[$key];
}

return $a;
}

private function diffPercentKeys(array $a, array $b): array
{
$out = [];
$keys = $this->keys;

foreach ($keys as $key) {
if ($b[$key] !== 0) {
$out[$key] = $a[$key] / $b[$key];
} else {
$out[$key] = -1;
}
}

return $out;
}
}
46 changes: 41 additions & 5 deletions src/Converter/FlatterList.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,32 +18,53 @@ final class FlatterList implements \JsonSerializable
{
/** @const Key used for methods with no parent */
private const NO_PARENT = '__top__';
private readonly array $indexed;
private bool $withExclusive;

public function __construct(
private readonly array $keys,
private array $data,
private readonly array $indexed
private array $data
) {
$this->withExclusive = false;
$this->indexData();
}

public function diff(self $head): Diff
{
return new Diff($this, $head);
}

public function getKeys(): array
{
$keys = $this->keys;

if ($this->withExclusive) {
$keys = \array_merge($keys, ['ewt', 'ecpu', 'emu', 'epmu', 'ect']);
}

return $keys;
}

public function callGraph(string $metric = 'wt', float $threshold = 0.01): CallGraph
{
$valid = $this->keys;
$valid = $this->getKeys();
if (!\in_array($metric, $valid)) {
throw new \InvalidArgumentException("Unknown metric '$metric'. Cannot generate callgraph.");
}

return new CallGraph(
$this->calculateSelf()->data,
$this->getData(),
$this->indexed,
$metric,
$threshold
);
}

private function calculateSelf(): self
public function withExclusiveValues(): self
{
$self = clone $this;
$self->withExclusive = true;

// Init exclusive values
foreach ($self->data as &$data) {
$data['ewt'] = $data['wt'];
Expand Down Expand Up @@ -113,4 +134,19 @@ public function getData(): array
{
return $this->data;
}

private function indexData(): void
{
$indexed = [];

foreach ($this->data as $key => $data) {
$parents = $data['parents'] ?? [];
unset($data['parents']);
foreach ($parents as $parent) {
$indexed[$parent][$key] = $data;
}
}

$this->indexed = $indexed;
}
}
2 changes: 1 addition & 1 deletion src/Converter/FlatterListConverter.php
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public function convert(array $data): FlatterList
$result[$func]['parents'][] = $parent;
} else {
$result[$func] = $values;
$result[$func]['parents'] = [$parent];
$result[$func]['c'] = [$parent];
}

// Build the indexed data.
Expand Down
4 changes: 2 additions & 2 deletions tests/src/TestCase.php
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@ public function getTrace(): array
return \json_decode(\file_get_contents(__DIR__ . '/fixture/trace.json'), true)['data'];
}

public function getFlatterList(): FlatterList
public function getFlatterList(string $version = 'v1'): FlatterList
{
$data = \json_decode(\file_get_contents(__DIR__ . '/fixture/flater_list.json'), true);
$data = \json_decode(\file_get_contents(__DIR__ . "/fixture/flater_list.{$version}.json"), true);

return new FlatterList(
['ct', 'wt', 'cpu', 'mu', 'pmu'],
Expand Down
File renamed without changes.
Loading

0 comments on commit bf40168

Please sign in to comment.