milliseconds since the turn began. * * @var array */ private $at = []; /** * Durations: label => milliseconds spent, summed over every call. * * @var array */ private $took = []; /** * Plain numbers worth printing beside the times: bytes, characters, counts. * * @var array */ private $notes = []; /** * Constructor. * * @param float $began Start mark. Defaults to now. */ public function __construct( float $began = 0.0 ) { $this->began = $began > 0.0 ? $began : microtime( true ); } /** * The turn's start mark, for anyone who needs to measure against it. * * @return float */ public function began(): float { return $this->began; } /** * Take a mark now, to be closed later by took(). * * @return float */ public function mark(): float { return microtime( true ); } /** * Record a milestone: how far into the turn we are, right now. * * Only the first call is saved. A step that runs twice does not move it. * * @param string $label Short name, no spaces. * @return int Milliseconds since the turn began. */ public function at( string $label ): int { $ms = (int) round( ( microtime( true ) - $this->began ) * 1000 ); if ( ! isset( $this->at[ $label ] ) ) { $this->at[ $label ] = $ms; } return $ms; } /** * Record how long a step ran, adding to anything already recorded for it. * * @param string $label Short name, no spaces. * @param float $since Mark taken before the step, from mark(). * @return int Milliseconds this call added. */ public function took( string $label, float $since ): int { $ms = (int) round( ( microtime( true ) - $since ) * 1000 ); $this->took[ $label ] = ( $this->took[ $label ] ?? 0 ) + $ms; return $ms; } /** * Add a duration that was measured somewhere else. * * For example, times that cURL reports after a request is finished. * * @param string $label Short name, no spaces. * @param int $ms Milliseconds to add. * @return void */ public function add( string $label, int $ms ): void { $this->took[ $label ] = ( $this->took[ $label ] ?? 0 ) + $ms; } /** * Record a plain number or word beside the times. * * @param string $label Short name, no spaces. * @param int|string $value Bytes, characters, a count or a model name. * @return void */ public function note( string $label, $value ): void { $this->notes[ $label ] = $value; } /** * Add one to a counter. * * @param string $label Short name, no spaces. * @return void */ public function count( string $label ): void { $this->notes[ $label ] = ( (int) ( $this->notes[ $label ] ?? 0 ) ) + 1; } /** * Read back a milestone, or 0 when it never happened. * * @param string $label Short name. * @return int */ public function get( string $label ): int { return (int) ( $this->at[ $label ] ?? 0 ); } /** * Write the whole turn as one line. * * @param string $what Which turn this was: "stream", "turn", "greet". * @return void */ public function write( string $what ): void { $this->at( 'end' ); $parts = []; foreach ( $this->at as $label => $ms ) { $parts[] = "@{$label} {$ms}ms"; } foreach ( $this->took as $label => $ms ) { $parts[] = "+{$label} {$ms}ms"; } foreach ( $this->notes as $label => $value ) { $parts[] = "{$label}={$value}"; } Log::debug( 'Voice TIMING ' . $what . ' — ' . implode( ', ', $parts ) ); } }