Skip to content

Instantly share code, notes, and snippets.

@sebastianbergmann
Last active May 12, 2026 05:25
Show Gist options
  • Select an option

  • Save sebastianbergmann/ed1d1620b99320ef6c47f01a15b7a545 to your computer and use it in GitHub Desktop.

Select an option

Save sebastianbergmann/ed1d1620b99320ef6c47f01a15b7a545 to your computer and use it in GitHub Desktop.
#!/usr/bin/env php
<?php declare(strict_types=1);
namespace SebastianBergmann\SlowestTests;
use const STDERR;
use function array_filter;
use function array_slice;
use function array_sum;
use function array_values;
use function arsort;
use function count;
use function fwrite;
use function is_readable;
use function printf;
use DOMDocument;
use DOMXPath;
$args = array_slice($argv, 1);
$showMean = false;
foreach ($args as $i => $arg) {
if ($arg === '--mean') {
$showMean = true;
unset($args[$i]);
}
}
$args = array_values($args);
if (count($args) !== 1) {
fwrite(STDERR, "Usage: {$argv[0]} [--mean] <otr.xml>\n");
exit(1);
}
$file = $args[0];
if (!is_readable($file)) {
fwrite(STDERR, "Cannot read {$file}\n");
exit(1);
}
$dom = new DOMDocument;
$dom->load($file);
$xpath = new DOMXPath($dom);
$xpath->registerNamespace('e', 'https://schemas.opentest4j.org/reporting/events/0.2.0');
$xpath->registerNamespace('phpunit', 'https://schema.phpunit.de/otr/phpunit/0.2.0');
$tests = [];
foreach ($xpath->query('//e:started[.//phpunit:methodSource]') as $started) {
$id = $started->getAttribute('id');
$source = $xpath->query('.//phpunit:methodSource', $started)->item(0);
$className = $source->getAttribute('className');
$name = $started->getAttribute('name');
$tests[$id] = $className . '::' . $name;
}
$runtimes = [];
foreach ($xpath->query('//e:finished') as $finished) {
$id = $finished->getAttribute('id');
if (!isset($tests[$id])) {
continue;
}
$usage = $xpath->query('.//phpunit:resourceUsage', $finished)->item(0);
if ($usage === null) {
continue;
}
$runtimes[$tests[$id]] = (float) $usage->getAttribute('time');
}
if ($runtimes === []) {
fwrite(STDERR, "No tests found in {$file}\n");
exit(1);
}
arsort($runtimes);
if ($showMean) {
$mean = array_sum($runtimes) / count($runtimes);
$slower = array_filter($runtimes, static fn (float $t): bool => $t > $mean);
$slowest = array_slice($slower, 0, 10, true);
printf("Mean test runtime: %.6f s (%d tests, %d slower than mean)\n\n", $mean, count($runtimes), count($slower));
printf("%-8s %-8s %s\n", 'Time(s)', 'x mean', 'Test');
printf("%-8s %-8s %s\n", '-------', '------', '----');
foreach ($slowest as $id => $time) {
printf("%8.6f %7.2fx %s\n", $time, $time / $mean, $id);
}
exit;
}
$slowest = array_slice($runtimes, 0, 10, true);
printf("%-8s %s\n", 'Time(s)', 'Test');
printf("%-8s %s\n", '-------', '----');
foreach ($slowest as $id => $time) {
printf("%8.6f %s\n", $time, $id);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment