Skip to content

Commit

Permalink
feat(frontend): implement Top Functions endpoint in Profiler module
Browse files Browse the repository at this point in the history
  • Loading branch information
roxblnfk committed Jun 29, 2024
1 parent b267e67 commit 48762ad
Show file tree
Hide file tree
Showing 12 changed files with 312 additions and 96 deletions.
128 changes: 64 additions & 64 deletions src/Handler/Router/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,69 @@ public static function new(string|object $classOrObject): self
: self::newStatic($classOrObject);
}

/**
* Convert query parameter to the specified type.
*/
public static function convertQueryParam(
\ReflectionParameter $param,
array $params,
): mixed {
$name = $param->getName();
$type = $param->getType();

$queryName = $queryParam->name ?? $name;

Check failure on line 143 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedAssignment

src/Handler/Router/Router.php:143:9: MixedAssignment: Unable to determine the type that $queryName is being assigned to (see https://psalm.dev/032)

Check failure on line 143 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

UndefinedVariable

src/Handler/Router/Router.php:143:22: UndefinedVariable: Cannot find referenced variable $queryParam (see https://psalm.dev/024)

Check failure on line 143 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedPropertyFetch

src/Handler/Router/Router.php:143:22: MixedPropertyFetch: Cannot fetch property on mixed var $queryParam (see https://psalm.dev/034)
if (!isset($params[$queryName])) {

Check failure on line 144 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedArrayTypeCoercion

src/Handler/Router/Router.php:144:20: MixedArrayTypeCoercion: Coercion from array offset type 'mixed|non-empty-string' to the expected type 'array-key' (see https://psalm.dev/195)

Check failure on line 144 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedArrayOffset

src/Handler/Router/Router.php:144:20: MixedArrayOffset: Cannot access value on variable $params using mixed offset (see https://psalm.dev/031)
$param->isDefaultValueAvailable() or throw new \InvalidArgumentException(\sprintf(
'Query parameter `%s` is required.',
$queryName,

Check failure on line 147 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedArgument

src/Handler/Router/Router.php:147:17: MixedArgument: Argument 2 of sprintf cannot be mixed|non-empty-string, expecting float|int|object{__tostring()}|string (see https://psalm.dev/030)
));

return $param->getDefaultValue();
}

$value = $params[$queryName];

Check failure on line 153 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedAssignment

src/Handler/Router/Router.php:153:9: MixedAssignment: Unable to determine the type that $value is being assigned to (see https://psalm.dev/032)
if ($type === null) {
return $value;
}

foreach (($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type]) as $t) {
$typeString = \ltrim($t?->getName() ?? '', '?');

Check failure on line 159 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

DocblockTypeContradiction

src/Handler/Router/Router.php:159:34: DocblockTypeContradiction: ReflectionNamedType|ReflectionType does not contain null (see https://psalm.dev/155)

Check failure on line 159 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

MixedArgument

src/Handler/Router/Router.php:159:34: MixedArgument: Argument 1 of ltrim cannot be ''|mixed, expecting string (see https://psalm.dev/030)

Check failure on line 159 in src/Handler/Router/Router.php

View workflow job for this annotation

GitHub Actions / psalm (ubuntu-latest, 8.2, locked)

PossiblyUndefinedMethod

src/Handler/Router/Router.php:159:39: PossiblyUndefinedMethod: Method ReflectionType::getName does not exist (see https://psalm.dev/108)
switch (true) {
case $typeString === 'mixed':
return $value;
case $typeString === 'array':
return (array) $value;
case $typeString === 'int':
return (int) (\is_array($value)
? throw new \InvalidArgumentException(
\sprintf(
'Query parameter `%s` must be an integer, array given.',
$queryName,
),
)
: $value);
case $typeString === 'string':
return (string) (\is_array($value)
? throw new \InvalidArgumentException(
\sprintf(
'Query parameter `%s` must be a string, array given.',
$queryName,
),
)
: $value);
default:
continue 2;
}
}

throw new \InvalidArgumentException(\sprintf(
'Query parameter `%s` must be of type `%s`, `%s` given.',
$queryName,
$type,
\gettype($value),
));
}

/**
* Find a route for specified method and path.
*
Expand Down Expand Up @@ -180,7 +243,7 @@ public function match(Method $method, string $uri, ?\ReflectionMethod $mock = nu
$object,
\array_merge($args, \is_array($match) ? $match : []),
$get,
)
),
),
};
}
Expand Down Expand Up @@ -291,69 +354,6 @@ private static function resolveArguments(
return $filteredArgs;
}

/**
* Convert query parameter to the specified type.
*/
public static function convertQueryParam(
\ReflectionParameter $param,
array $params,
): mixed {
$name = $param->getName();
$type = $param->getType();

$queryName = $queryParam->name ?? $name;
if (!isset($params[$queryName])) {
$param->isDefaultValueAvailable() or throw new \InvalidArgumentException(\sprintf(
'Query parameter `%s` is required.',
$queryName,
));

return $param->getDefaultValue();
}

$value = $params[$queryName];
if ($type === null) {
return $value;
}

foreach (($type instanceof \ReflectionUnionType ? $type->getTypes() : [$type]) as $t) {
$typeString = \ltrim($t?->getName() ?? '', '?');
switch (true) {
case $typeString === 'mixed':
return $value;
case $typeString === 'array':
return (array) $value;
case $typeString === 'int':
return (int) (\is_array($value)
? throw new \InvalidArgumentException(
\sprintf(
'Query parameter `%s` must be an integer, array given.',
$queryName,
)
)
: $value);
case $typeString === 'string':
return (string) (\is_array($value)
? throw new \InvalidArgumentException(
\sprintf(
'Query parameter `%s` must be a string, array given.',
$queryName,
)
)
: $value);
default:
continue 2;
}
}

throw new \InvalidArgumentException(\sprintf(
'Query parameter `%s` must be of type `%s`, `%s` given.',
$queryName,
$type,
\gettype($value),
));
}

private static function doNothing(mixed ...$args): array
{
return $args;
Expand Down
1 change: 0 additions & 1 deletion src/Module/Frontend/Http/Router.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@
use Buggregator\Trap\Handler\Router\Method;
use Buggregator\Trap\Handler\Router\Router as CommonRouter;
use Buggregator\Trap\Logger;
use Buggregator\Trap\Module\Frontend\EventStorage;
use Buggregator\Trap\Module\Frontend\Service;
use Buggregator\Trap\Support\Json;
use Nyholm\Psr7\Response;
Expand Down
24 changes: 0 additions & 24 deletions src/Module/Frontend/Mapper/Profiler.php

This file was deleted.

8 changes: 5 additions & 3 deletions src/Module/Frontend/Module/Profiler/ApiController.php
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,9 @@
trait ApiController
{
private readonly Mapper $mapper;

private readonly Logger $logger;

private readonly EventStorage $eventsStorage;

#[RegexpRoute(Method::Get, '#^api/profiler/(?<uuid>[a-f0-9-]++)/top$#i')]
Expand All @@ -27,7 +29,7 @@ trait ApiController
[
'uuid' => '0190402f-7eb2-7287-82a8-897a0091f58e',
'metric' => 'excl_wt',
]
],
),
]
public function profilerTop(string $uuid, #[QueryParam] string $metric = ''): Message\TopFunctions
Expand All @@ -47,7 +49,7 @@ public function profilerTop(string $uuid, #[QueryParam] string $metric = ''): Me
AssertSuccess(
Method::Get,
'api/profiler/0190402f-7eb2-7287-82a8-897a0091f58e/call-graph',
['uuid' => '0190402f-7eb2-7287-82a8-897a0091f58e']
['uuid' => '0190402f-7eb2-7287-82a8-897a0091f58e'],
),
]
public function profilerCallGraph(string $uuid): Message\CallGraph
Expand All @@ -65,7 +67,7 @@ public function profilerCallGraph(string $uuid): Message\CallGraph
AssertSuccess(
Method::Get,
'api/profiler/0190402f-7eb2-7287-82a8-897a0091f58e/flame-chart',
['uuid' => '0190402f-7eb2-7287-82a8-897a0091f58e']
['uuid' => '0190402f-7eb2-7287-82a8-897a0091f58e'],
),
]
public function profilerFlameChart(string $uuid): Message\FlameChart
Expand Down
73 changes: 72 additions & 1 deletion src/Module/Frontend/Module/Profiler/Mapper.php
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,78 @@ public function frameToEvent(\Buggregator\Trap\Proto\Frame\Profiler $frame): Eve
*/
public function topFunctions(Event $event): TopFunctions
{
return new TopFunctions();
$profile = $event->payload->getProfile();

// Get top
$top = [];
foreach ($profile->calls->all as $branch) {
// todo: limit with 100 and sort
$top[] = TopFunctions\Func::fromEdge($branch->item);
}

// Schema
$schema = new TopFunctions\Schema([
new TopFunctions\Column(
key: 'function',
label: 'Function',
sortable: false,
description: 'Function that was called',
values: [new TopFunctions\Value(key: 'function', format: 'string')],
),
new TopFunctions\Column(
key: 'ct',
label: 'CT',
sortable: true,
description: 'Calls',
values: [new TopFunctions\Value(key: 'ct', format: 'number')],
),
new TopFunctions\Column(
key: 'cpu',
label: 'CPU',
sortable: true,
description: 'CPU time (ms)',
values: [
new TopFunctions\Value(key: 'cpu', format: 'ms'),
new TopFunctions\Value(key: 'p_cpu', format: 'percent', type: 'sub'),
],
),
new TopFunctions\Column(
key: 'wt',
label: 'WT',
sortable: true,
description: 'Wall time (ms)',
values: [
new TopFunctions\Value(key: 'wt', format: 'ms'),
new TopFunctions\Value(key: 'p_wt', format: 'percent', type: 'sub'),
],
),
new TopFunctions\Column(
key: 'mu',
label: 'MU',
sortable: true,
description: 'Memory usage (bytes)',
values: [
new TopFunctions\Value(key: 'mu', format: 'bytes'),
new TopFunctions\Value(key: 'p_mu', format: 'percent', type: 'sub'),
],
),
new TopFunctions\Column(
key: 'pmu',
label: 'PMU',
sortable: true,
description: 'Peak memory usage (bytes)',
values: [
new TopFunctions\Value(key: 'pmu', format: 'bytes'),
new TopFunctions\Value(key: 'p_pmu', format: 'percent', type: 'sub'),
],
),
]);

return new TopFunctions(
functions: $top,
overallTotals: $profile->peaks,
schema: $schema,
);
}

/**
Expand Down
12 changes: 11 additions & 1 deletion src/Module/Frontend/Module/Profiler/Message/TopFunctions.php
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,21 @@
*/
final class TopFunctions implements \JsonSerializable
{
/**
* @param list<TopFunctions\Func> $functions
*/
public function __construct(
private readonly array $functions,
private readonly \Buggregator\Trap\Module\Profiler\Struct\Peaks $overallTotals,
private readonly TopFunctions\Schema $schema,
) {}

public function jsonSerialize(): array
{
return [];
return [
'functions' => $this->functions,
'overall_totals' => $this->overallTotals,
'schema' => $this->schema,
];
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<?php

declare(strict_types=1);

namespace Buggregator\Trap\Module\Frontend\Module\Profiler\Message\TopFunctions;

/**
* @internal
*/
final class Column implements \JsonSerializable
{
/**
* @param list<Value> $values
*/
public function __construct(
public readonly string $key,
public readonly string $label,
public readonly bool $sortable,
public readonly string $description,
public readonly array $values,
) {}

public function jsonSerialize(): array
{
return [
'key' => $this->key,
'label' => $this->label,
'sortable' => $this->sortable,
'description' => $this->description,
'values' => $this->values,
];
}
}
Loading

0 comments on commit 48762ad

Please sign in to comment.