Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
5.56% covered (danger)
5.56%
1 / 18
20.00% covered (danger)
20.00%
1 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
Timing
5.56% covered (danger)
5.56%
1 / 18
20.00% covered (danger)
20.00%
1 / 5
77.24
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
6
 millis
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 end
0.00% covered (danger)
0.00%
0 / 8
0.00% covered (danger)
0.00%
0 / 1
20
 fakeTiming
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 start
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
1<?php
2declare( strict_types = 1 );
3
4namespace Wikimedia\Parsoid\Utils;
5
6use Wikimedia\Assert\Assert;
7use Wikimedia\Parsoid\Config\SiteConfig;
8
9/**
10 * A helper class to make it easier to compute timing metrics.
11 */
12class Timing {
13    /**
14     * This is typically a StatsdDataFactoryInterface, but really could be
15     * anything which has a `timing()` method.  Set it to `null` to disable
16     * metrics.
17     *
18     * @var ?object
19     */
20    private ?object $metrics;
21
22    /**
23     * @var float
24     */
25    private float $startTime;
26
27    /**
28     * @var ?SiteConfig
29     */
30    private ?SiteConfig $siteConfig;
31
32    private ?float $elapsed;
33
34    private function __construct( ?object $configOrMetrics, ?float $elapsed = null ) {
35        if ( $configOrMetrics instanceof SiteConfig ) {
36            $this->siteConfig = $configOrMetrics;
37            $this->metrics = $configOrMetrics->metrics();
38        } else {
39            $this->siteConfig = null;
40            $this->metrics = $configOrMetrics;
41        }
42        $this->startTime = self::millis();
43        $this->elapsed = $elapsed;
44    }
45
46    /**
47     * Return the current number of milliseconds since the epoch, as a float.
48     */
49    public static function millis(): float {
50        return 1000 * microtime( true );
51    }
52
53    /**
54     * End this timing measurement, reporting it under the given `name`.
55     * @param ?string $statsdCompat
56     * @param ?string $name
57     * @param ?array $labels
58     * @return float Number of milliseconds reported
59     */
60    public function end(
61        ?string $statsdCompat = null,
62        ?string $name = null,
63        ?array $labels = []
64    ): float {
65        if ( $this->elapsed === null ) {
66            $this->elapsed = self::millis() - $this->startTime;
67        }
68        if ( $this->metrics ) {
69            Assert::invariant( $statsdCompat !== null, 'Recording metric without a key.' );
70            $this->metrics->timing( $statsdCompat, $this->elapsed );
71        }
72        if ( $this->siteConfig ) {
73            // Note that observeTiming takes a value in *milliseconds*
74            // despite the name of the metric ending in `_seconds`
75            $this->siteConfig->observeTiming( $name, $this->elapsed, $labels );
76        }
77        return $this->elapsed;
78    }
79
80    /**
81     * Override elapsed time of a timing instance
82     * @param SiteConfig $siteConfig
83     * @param float $value Value to measure in the metrics (milliseconds if timing)
84     * @return Timing
85     */
86    public static function fakeTiming( SiteConfig $siteConfig, float $value ): Timing {
87        return new Timing( $siteConfig, $value );
88    }
89
90    /**
91     * Start a timing measurement, logging it to the given `$metrics` object
92     * (which just needs to have a `timing()` method).
93     * @param ?object $configOrMetrics
94     * @return Timing
95     */
96    public static function start( ?object $configOrMetrics = null ): Timing {
97        return new Timing( $configOrMetrics );
98    }
99}