Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ProfilerExcimer
0.00% covered (danger)
0.00%
0 / 101
0.00% covered (danger)
0.00%
0 / 5
380
0.00% covered (danger)
0.00%
0 / 1
 __construct
0.00% covered (danger)
0.00%
0 / 18
0.00% covered (danger)
0.00%
0 / 1
12
 scopedProfileIn
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
 close
0.00% covered (danger)
0.00%
0 / 2
0.00% covered (danger)
0.00%
0 / 1
2
 getFunctionStats
0.00% covered (danger)
0.00%
0 / 43
0.00% covered (danger)
0.00%
0 / 1
20
 getOutput
0.00% covered (danger)
0.00%
0 / 37
0.00% covered (danger)
0.00%
0 / 1
110
1<?php
2/**
3 * This program is free software; you can redistribute it and/or modify
4 * it under the terms of the GNU General Public License as published by
5 * the Free Software Foundation; either version 2 of the License, or
6 * (at your option) any later version.
7 *
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
12 *
13 * You should have received a copy of the GNU General Public License along
14 * with this program; if not, write to the Free Software Foundation, Inc.,
15 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
16 * http://www.gnu.org/copyleft/gpl.html
17 *
18 * @file
19 */
20
21/**
22 * @ingroup Profiler
23 * @since 1.33
24 * @see $wgProfiler
25 */
26class ProfilerExcimer extends Profiler {
27    /** @var ExcimerProfiler */
28    private $cpuProf;
29    /** @var ExcimerProfiler */
30    private $realProf;
31    private $period;
32
33    /**
34     * @param array $params Associative array of parameters:
35     *    - period: The sampling period
36     *    - maxDepth: The maximum stack depth collected
37     *    - cpuProfiler: A pre-started ExcimerProfiler instance for CPU
38     *      profiling of the entire request including configuration.
39     *    - realProfiler: A pre-started ExcimerProfiler instance for wall
40     *      clock profiling of the entire request.
41     */
42    public function __construct( array $params = [] ) {
43        parent::__construct( $params );
44
45        $this->period = $params['period'] ?? 0.01;
46        $maxDepth = $params['maxDepth'] ?? 100;
47
48        if ( isset( $params['cpuProfiler'] ) ) {
49            $this->cpuProf = $params['cpuProfiler'];
50        } else {
51            $this->cpuProf = new ExcimerProfiler;
52            $this->cpuProf->setEventType( EXCIMER_CPU );
53            $this->cpuProf->setPeriod( $this->period );
54            $this->cpuProf->setMaxDepth( $maxDepth );
55            $this->cpuProf->start();
56        }
57
58        if ( isset( $params['realProfiler'] ) ) {
59            $this->realProf = $params['realProfiler'];
60        } else {
61            $this->realProf = new ExcimerProfiler;
62            $this->realProf->setEventType( EXCIMER_REAL );
63            $this->realProf->setPeriod( $this->period );
64            $this->realProf->setMaxDepth( $maxDepth );
65            $this->realProf->start();
66        }
67    }
68
69    public function scopedProfileIn( $section ) {
70    }
71
72    public function close() {
73        $this->cpuProf->stop();
74        $this->realProf->stop();
75    }
76
77    public function getFunctionStats() {
78        $this->close();
79        $cpuStats = $this->cpuProf->getLog()->aggregateByFunction();
80        '@phan-var array $cpuStats';
81        $realStats = $this->realProf->getLog()->aggregateByFunction();
82        '@phan-var array $realStats';
83        $allNames = array_keys( $realStats + $cpuStats );
84        $cpuSamples = $this->cpuProf->getLog()->getEventCount();
85        $realSamples = $this->realProf->getLog()->getEventCount();
86
87        $resultStats = [ [
88            'name' => '-total',
89            'calls' => 1,
90            'memory' => 0,
91            '%memory' => 0,
92            'min_real' => 0,
93            'max_real' => 0,
94            'cpu' => $cpuSamples * $this->period * 1000,
95            '%cpu' => 100,
96            'real' => $realSamples * $this->period * 1000,
97            '%real' => 100,
98        ] ];
99
100        foreach ( $allNames as $funcName ) {
101            $cpuEntry = $cpuStats[$funcName] ?? false;
102            $realEntry = $realStats[$funcName] ?? false;
103            $resultEntry = [
104                'name' => $funcName,
105                'calls' => 0,
106                'memory' => 0,
107                '%memory' => 0,
108                'min_real' => 0,
109                'max_real' => 0,
110            ];
111
112            if ( $cpuEntry ) {
113                $resultEntry['cpu'] = $cpuEntry['inclusive'] * $this->period * 1000;
114                $resultEntry['%cpu'] = $cpuEntry['inclusive'] / $cpuSamples * 100;
115            } else {
116                $resultEntry['cpu'] = 0;
117                $resultEntry['%cpu'] = 0;
118            }
119            if ( $realEntry ) {
120                $resultEntry['real'] = $realEntry['inclusive'] * $this->period * 1000;
121                $resultEntry['%real'] = $realEntry['inclusive'] / $realSamples * 100;
122            } else {
123                $resultEntry['real'] = 0;
124                $resultEntry['%real'] = 0;
125            }
126
127            $resultStats[] = $resultEntry;
128        }
129        return $resultStats;
130    }
131
132    public function getOutput() {
133        $this->close();
134        $cpuLog = $this->cpuProf->getLog();
135        $realLog = $this->realProf->getLog();
136        $cpuStats = $cpuLog->aggregateByFunction();
137        '@phan-var array $cpuStats';
138        $realStats = $realLog->aggregateByFunction();
139        '@phan-var array $realStats';
140        $allNames = array_keys( $cpuStats + $realStats );
141        $cpuSamples = $cpuLog->getEventCount();
142        $realSamples = $realLog->getEventCount();
143
144        $result = '';
145
146        $titleFormat = "%-70s %10s %11s %10s %11s %10s %11s %10s %11s\n";
147        $statsFormat = "%-70s %10d %10.1f%% %10d %10.1f%% %10d %10.1f%% %10d %10.1f%%\n";
148        $result .= sprintf( $titleFormat,
149            'Name',
150            'CPU incl', 'CPU incl%', 'CPU self', 'CPU self%',
151            'Real incl', 'Real incl%', 'Real self', 'Real self%'
152        );
153
154        foreach ( $allNames as $funcName ) {
155            $realEntry = $realStats[$funcName] ?? false;
156            $cpuEntry = $cpuStats[$funcName] ?? false;
157            $realIncl = $realEntry ? $realEntry['inclusive'] : 0;
158            $realSelf = $realEntry ? $realEntry['self'] : 0;
159            $cpuIncl = $cpuEntry ? $cpuEntry['inclusive'] : 0;
160            $cpuSelf = $cpuEntry ? $cpuEntry['self'] : 0;
161            $result .= sprintf( $statsFormat,
162                $funcName,
163                $cpuIncl * $this->period * 1000,
164                $cpuIncl == 0 ? 0 : $cpuIncl / $cpuSamples * 100,
165                $cpuSelf * $this->period * 1000,
166                $cpuSelf == 0 ? 0 : $cpuSelf / $cpuSamples * 100,
167                $realIncl * $this->period * 1000,
168                $realIncl == 0 ? 0 : $realIncl / $realSamples * 100,
169                $realSelf * $this->period * 1000,
170                $realSelf == 0 ? 0 : $realSelf / $realSamples * 100
171            );
172        }
173
174        return $result;
175    }
176}