Profiler code cleanup
[lhc/web/wiklou.git] / includes / profiler / Profiler.php
1 <?php
2 /**
3 * Base class for profiling.
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 * http://www.gnu.org/copyleft/gpl.html
19 *
20 * @file
21 * @ingroup Profiler
22 * @defgroup Profiler Profiler
23 */
24
25 /**
26 * Profiler base class that defines the interface and some trivial
27 * functionality
28 *
29 * @ingroup Profiler
30 */
31 abstract class Profiler {
32 /** @var string|bool Profiler ID for bucketing data */
33 protected $mProfileID = false;
34 /** @var bool Whether MediaWiki is in a SkinTemplate output context */
35 protected $mTemplated = false;
36
37 /** @var TransactionProfiler */
38 protected $trxProfiler;
39
40 // @codingStandardsIgnoreStart PSR2.Classes.PropertyDeclaration.Underscore
41 /** @var Profiler Do not call this outside Profiler and ProfileSection */
42 public static $__instance = null;
43 // @codingStandardsIgnoreEnd
44
45 /**
46 * @param array $params
47 */
48 public function __construct( array $params ) {
49 if ( isset( $params['profileID'] ) ) {
50 $this->mProfileID = $params['profileID'];
51 }
52 $this->trxProfiler = new TransactionProfiler();
53 }
54
55 /**
56 * Singleton
57 * @return Profiler
58 */
59 final public static function instance() {
60 if ( self::$__instance === null ) {
61 global $wgProfiler;
62 if ( is_array( $wgProfiler ) ) {
63 if ( !isset( $wgProfiler['class'] ) ) {
64 $class = 'ProfilerStub';
65 } else {
66 $class = $wgProfiler['class'];
67 }
68 self::$__instance = new $class( $wgProfiler );
69 } else {
70 self::$__instance = new ProfilerStub( array() );
71 }
72 }
73 return self::$__instance;
74 }
75
76 /**
77 * Set the profiler to a specific profiler instance. Mostly for dumpHTML
78 * @param Profiler $p
79 */
80 final public static function setInstance( Profiler $p ) {
81 self::$__instance = $p;
82 }
83
84 /**
85 * Return whether this a stub profiler
86 *
87 * @return bool
88 */
89 abstract public function isStub();
90
91 /**
92 * Return whether this profiler stores data
93 *
94 * Called by Parser::braceSubstitution. If true, the parser will not
95 * generate per-title profiling sections, to avoid overloading the
96 * profiling data collector.
97 *
98 * @see Profiler::logData()
99 * @return bool
100 */
101 abstract public function isPersistent();
102
103 /**
104 * @param string $id
105 */
106 public function setProfileID( $id ) {
107 $this->mProfileID = $id;
108 }
109
110 /**
111 * @return string
112 */
113 public function getProfileID() {
114 if ( $this->mProfileID === false ) {
115 return wfWikiID();
116 } else {
117 return $this->mProfileID;
118 }
119 }
120
121 /**
122 * Called by wfProfieIn()
123 *
124 * @param string $functionname
125 */
126 abstract public function profileIn( $functionname );
127
128 /**
129 * Called by wfProfieOut()
130 *
131 * @param string $functionname
132 */
133 abstract public function profileOut( $functionname );
134
135 /**
136 * Mark a DB as in a transaction with one or more writes pending
137 *
138 * Note that there can be multiple connections to a single DB.
139 *
140 * @param string $server DB server
141 * @param string $db DB name
142 * @param string $id Resource ID string of connection
143 */
144 public function transactionWritingIn( $server, $db, $id = '' ) {
145 $this->trxProfiler->transactionWritingIn( $server, $db, $id );
146 }
147
148 /**
149 * Mark a DB as no longer in a transaction
150 *
151 * This will check if locks are possibly held for longer than
152 * needed and log any affected transactions to a special DB log.
153 * Note that there can be multiple connections to a single DB.
154 *
155 * @param string $server DB server
156 * @param string $db DB name
157 * @param string $id Resource ID string of connection
158 */
159 public function transactionWritingOut( $server, $db, $id = '' ) {
160 $this->trxProfiler->transactionWritingOut( $server, $db, $id );
161 }
162
163 /**
164 * Close opened profiling sections
165 */
166 abstract public function close();
167
168 /**
169 * Log the data to some store or even the page output
170 */
171 abstract public function logData();
172
173 /**
174 * Mark this call as templated or not
175 *
176 * @param bool $t
177 */
178 public function setTemplated( $t ) {
179 $this->mTemplated = $t;
180 }
181
182 /**
183 * Returns a profiling output to be stored in debug file
184 *
185 * @return string
186 */
187 abstract public function getOutput();
188
189 /**
190 * @return array
191 */
192 abstract public function getRawData();
193
194 /**
195 * Get the initial time of the request, based either on $wgRequestTime or
196 * $wgRUstart. Will return null if not able to find data.
197 *
198 * @param string|bool $metric Metric to use, with the following possibilities:
199 * - user: User CPU time (without system calls)
200 * - cpu: Total CPU time (user and system calls)
201 * - wall (or any other string): elapsed time
202 * - false (default): will fall back to default metric
203 * @return float|null
204 */
205 protected function getTime( $metric = 'wall' ) {
206 if ( $metric === 'cpu' || $metric === 'user' ) {
207 $ru = wfGetRusage();
208 if ( !$ru ) {
209 return 0;
210 }
211 $time = $ru['ru_utime.tv_sec'] + $ru['ru_utime.tv_usec'] / 1e6;
212 if ( $metric === 'cpu' ) {
213 # This is the time of system calls, added to the user time
214 # it gives the total CPU time
215 $time += $ru['ru_stime.tv_sec'] + $ru['ru_stime.tv_usec'] / 1e6;
216 }
217 return $time;
218 } else {
219 return microtime( true );
220 }
221 }
222
223 /**
224 * Get the initial time of the request, based either on $wgRequestTime or
225 * $wgRUstart. Will return null if not able to find data.
226 *
227 * @param string|bool $metric Metric to use, with the following possibilities:
228 * - user: User CPU time (without system calls)
229 * - cpu: Total CPU time (user and system calls)
230 * - wall (or any other string): elapsed time
231 * - false (default): will fall back to default metric
232 * @return float|null
233 */
234 protected function getInitialTime( $metric = 'wall' ) {
235 global $wgRequestTime, $wgRUstart;
236
237 if ( $metric === 'cpu' || $metric === 'user' ) {
238 if ( !count( $wgRUstart ) ) {
239 return null;
240 }
241
242 $time = $wgRUstart['ru_utime.tv_sec'] + $wgRUstart['ru_utime.tv_usec'] / 1e6;
243 if ( $metric === 'cpu' ) {
244 # This is the time of system calls, added to the user time
245 # it gives the total CPU time
246 $time += $wgRUstart['ru_stime.tv_sec'] + $wgRUstart['ru_stime.tv_usec'] / 1e6;
247 }
248 return $time;
249 } else {
250 if ( empty( $wgRequestTime ) ) {
251 return null;
252 } else {
253 return $wgRequestTime;
254 }
255 }
256 }
257
258 /**
259 * Add an entry in the debug log file
260 *
261 * @param string $s String to output
262 */
263 protected function debug( $s ) {
264 if ( function_exists( 'wfDebug' ) ) {
265 wfDebug( $s );
266 }
267 }
268
269 /**
270 * Add an entry in the debug log group
271 *
272 * @param string $group Group to send the message to
273 * @param string $s String to output
274 */
275 protected function debugGroup( $group, $s ) {
276 if ( function_exists( 'wfDebugLog' ) ) {
277 wfDebugLog( $group, $s );
278 }
279 }
280 }