xhprof.php ➔ symbol_report()   F
last analyzed

Complexity

Conditions 27
Paths > 20000

Size

Total Lines 260
Code Lines 187

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 756
Metric Value
cc 27
eloc 187
nc 429496.7295
nop 9
dl 0
loc 260
ccs 0
cts 212
cp 0
crap 756
rs 2

How to fix   Long Method    Complexity    Many Parameters   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

Many Parameters

Methods with many parameters are not only hard to understand, but their parameters also often become inconsistent when you need more, or different data.

There are several approaches to avoid long parameter lists:

1
<?php
2
if(!defined('sugarEntry') || !sugarEntry) die('Not A Valid Entry Point');
3
//  Copyright (c) 2009 Facebook
4
//
5
//  Licensed under the Apache License, Version 2.0 (the "License");
6
//  you may not use this file except in compliance with the License.
7
//  You may obtain a copy of the License at
8
//
9
//      http://www.apache.org/licenses/LICENSE-2.0
10
//
11
//  Unless required by applicable law or agreed to in writing, software
12
//  distributed under the License is distributed on an "AS IS" BASIS,
13
//  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
//  See the License for the specific language governing permissions and
15
//  limitations under the License.
16
//
17
18
//
19
// XHProf: A Hierarchical Profiler for PHP
20
//
21
// XHProf has two components:
22
//
23
//  * This module is the UI/reporting component, used
24
//    for viewing results of XHProf runs from a browser.
25
//
26
//  * Data collection component: This is implemented
27
//    as a PHP extension (XHProf).
28
//
29
// @author Kannan Muthukkaruppan
30
//
31
32
if (!isset($GLOBALS['XHPROF_LIB_ROOT'])) {
33
  // by default, the parent directory is XHPROF lib root
34
  $GLOBALS['XHPROF_LIB_ROOT'] = realpath(dirname(__FILE__) . '/..');
35
}
36
37
require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_lib.php';
38
require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/callgraph_utils.php';
39
require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_runs.php';
40
41
42
/**
43
 * Our coding convention disallows relative paths in hrefs.
44
 * Get the base URL path from the SCRIPT_NAME.
45
 */
46
$base_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), "/");
47
48
49
/**
50
 * Generate references to required stylesheets & javascript.
51
 *
52
 * If the calling script (such as index.php) resides in
53
 * a different location that than 'xhprof_html' directory the
54
 * caller must provide the URL path to 'xhprof_html' directory
55
 * so that the correct location of the style sheets/javascript
56
 * can be specified in the generated HTML.
57
 *
58
 */
59
function xhprof_include_js_css($ui_dir_url_path = null) {
60
61
  if (empty($ui_dir_url_path)) {
62
    $ui_dir_url_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), "/");
63
  }
64
65
  // style sheets
66
  echo "<link href='$ui_dir_url_path/css/xhprof.css' rel='stylesheet' ".
67
    " type='text/css' />";
68
  echo "<link href='$ui_dir_url_path/jquery/jquery.tooltip.css' ".
69
    " rel='stylesheet' type='text/css' />";
70
  echo "<link href='$ui_dir_url_path/jquery/jquery.autocomplete.css' ".
71
    " rel='stylesheet' type='text/css' />";
72
73
  // javascript
74
  echo "<script src='$ui_dir_url_path/jquery/jquery-1.2.6.js'>".
75
       "</script>";
76
  echo "<script src='$ui_dir_url_path/jquery/jquery.tooltip.js'>".
77
       "</script>";
78
  echo "<script src='$ui_dir_url_path/jquery/jquery.autocomplete.js'>"
79
       ."</script>";
80
  echo "<script src='$ui_dir_url_path/js/xhprof_report.js'></script>";
81
}
82
83
84
/*
85
 * Formats call counts for XHProf reports.
86
 *
87
 * Description:
88
 * Call counts in single-run reports are integer values.
89
 * However, call counts for aggregated reports can be
90
 * fractional. This function will print integer values
91
 * without decimal point, but with commas etc.
92
 *
93
 *   4000 ==> 4,000
94
 *
95
 * It'll round fractional values to decimal precision of 3
96
 *   4000.1212 ==> 4,000.121
97
 *   4000.0001 ==> 4,000
98
 *
99
 */
100
function xhprof_count_format($num) {
101
  $num = round($num, 3);
102
  if (round($num) == $num) {
103
    return number_format($num);
104
  } else {
105
    return number_format($num, 3);
106
  }
107
}
108
109
function xhprof_percent_format($s, $precision = 1) {
110
  return sprintf('%.'.$precision.'f%%', 100 * $s);
111
}
112
113
/**
114
 * Implodes the text for a bunch of actions (such as links, forms,
115
 * into a HTML list and returns the text.
116
 */
117
function xhprof_render_actions($actions) {
118
  $out = array();
119
120
  if (count($actions)) {
121
    $out[] = '<ul class="xhprof_actions">';
122
    foreach ($actions as $action) {
123
      $out[] = '<li>'.$action.'</li>';
124
    }
125
    $out[] = '</ul>';
126
  }
127
128
  return implode('', $out);
129
}
130
131
132
/**
133
 * @param html-str $content  the text/image/innerhtml/whatever for the link
0 ignored issues
show
Documentation introduced by
The doc-type html-str could not be parsed: Unknown type name "html-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
134
 * @param raw-str  $href
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
135
 * @param raw-str  $class
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
136
 * @param raw-str  $id
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
137
 * @param raw-str  $title
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
138
 * @param raw-str  $target
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
139
 * @param raw-str  $onclick
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
140
 * @param raw-str  $style
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
141
 * @param raw-str  $access
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
142
 * @param raw-str  $onmouseover
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
143
 * @param raw-str  $onmouseout
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
144
 * @param raw-str  $onmousedown
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
145
 * @param raw-str  $dir
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
Bug introduced by
There is no parameter named $dir. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
146
 * @param raw-str  $rel
0 ignored issues
show
Documentation introduced by
The doc-type raw-str could not be parsed: Unknown type name "raw-str" at position 0. (view supported doc-types)

This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.

Loading history...
Bug introduced by
There is no parameter named $rel. Was it maybe removed?

This check looks for PHPDoc comments describing methods or function parameters that do not exist on the corresponding method or function.

Consider the following example. The parameter $italy is not defined by the method finale(...).

/**
 * @param array $germany
 * @param array $island
 * @param array $italy
 */
function finale($germany, $island) {
    return "2:1";
}

The most likely cause is that the parameter was removed, but the annotation was not.

Loading history...
147
 */
148
function xhprof_render_link($content, $href, $class='', $id='', $title='',
149
                            $target='',
150
                            $onclick='', $style='', $access='', $onmouseover='',
151
                            $onmouseout='', $onmousedown='') {
152
153
  if (!$content) {
154
    return '';
155
  }
156
157
  if ($href) {
158
    $link = '<a href="' . ($href) . '"';
159
  } else {
160
    $link = '<span';
161
  }
162
163
  if ($class) {
164
    $link .= ' class="' . ($class) . '"';
165
  }
166
  if ($id) {
167
    $link .= ' id="' . ($id) . '"';
168
  }
169
  if ($title) {
170
    $link .= ' title="' . ($title) . '"';
171
  }
172
  if ($target) {
173
    $link .= ' target="' . ($target) . '"';
174
  }
175
  if ($onclick && $href) {
176
    $link .= ' onclick="' . ($onclick) . '"';
177
  }
178
  if ($style && $href) {
179
    $link .= ' style="' . ($style) . '"';
180
  }
181
  if ($access && $href) {
182
    $link .= ' accesskey="' . ($access) . '"';
183
  }
184
  if ($onmouseover) {
185
    $link .= ' onmouseover="' . ($onmouseover) . '"';
186
  }
187
  if ($onmouseout) {
188
    $link .= ' onmouseout="' . ($onmouseout) . '"';
189
  }
190
  if ($onmousedown) {
191
    $link .= ' onmousedown="' . ($onmousedown) . '"';
192
  }
193
194
  $link .= '>';
195
  $link .= $content;
196
  if ($href) {
197
    $link .= '</a>';
198
  } else {
199
    $link .= '</span>';
200
  }
201
202
  return $link;
203
}
204
205
206
// default column to sort on -- wall time
207
$sort_col = "wt";
208
209
// default is "single run" report
210
$diff_mode = false;
211
212
// call count data present?
213
$display_calls = true;
214
215
// The following column headers are sortable
216
$sortable_columns = array("fn" => 1,
217
                          "ct" => 1,
218
                          "wt" => 1,
219
                          "excl_wt" => 1,
220
                          "ut" => 1,
221
                          "excl_ut" => 1,
222
                          "st" => 1,
223
                          "excl_st" => 1,
224
                          "mu" => 1,
225
                          "excl_mu" => 1,
226
                          "pmu" => 1,
227
                          "excl_pmu" => 1,
228
                          "cpu" => 1,
229
                          "excl_cpu" => 1,
230
                          "samples" => 1,
231
                          "excl_samples" => 1
232
                          );
233
234
// Textual descriptions for column headers in "single run" mode
235
$descriptions = array(
236
                      "fn" => "Function Name",
237
                      "ct" =>  "Calls",
238
                      "Calls%" => "Calls%",
239
240
                      "wt" => "Incl. Wall Time<br>(microsec)",
241
                      "IWall%" => "IWall%",
242
                      "excl_wt" => "Excl. Wall Time<br>(microsec)",
243
                      "EWall%" => "EWall%",
244
245
                      "ut" => "Incl. User<br>(microsecs)",
246
                      "IUser%" => "IUser%",
247
                      "excl_ut" => "Excl. User<br>(microsec)",
248
                      "EUser%" => "EUser%",
249
250
                      "st" => "Incl. Sys <br>(microsec)",
251
                      "ISys%" => "ISys%",
252
                      "excl_st" => "Excl. Sys <br>(microsec)",
253
                      "ESys%" => "ESys%",
254
255
                      "cpu" => "Incl. CPU<br>(microsecs)",
256
                      "ICpu%" => "ICpu%",
257
                      "excl_cpu" => "Excl. CPU<br>(microsec)",
258
                      "ECpu%" => "ECPU%",
259
260
                      "mu" => "Incl.<br>MemUse<br>(bytes)",
261
                      "IMUse%" => "IMemUse%",
262
                      "excl_mu" => "Excl.<br>MemUse<br>(bytes)",
263
                      "EMUse%" => "EMemUse%",
264
265
                      "pmu" => "Incl.<br> PeakMemUse<br>(bytes)",
266
                      "IPMUse%" => "IPeakMemUse%",
267
                      "excl_pmu" => "Excl.<br>PeakMemUse<br>(bytes)",
268
                      "EPMUse%" => "EPeakMemUse%",
269
270
                      "samples" => "Incl. Samples",
271
                      "ISamples%" => "ISamples%",
272
                      "excl_samples" => "Excl. Samples",
273
                      "ESamples%" => "ESamples%",
274
                      );
275
276
// Formatting Callback Functions...
277
$format_cbk = array(
278
                      "fn" => "",
279
                      "ct" => "xhprof_count_format",
280
                      "Calls%" => "xhprof_percent_format",
281
282
                      "wt" => "number_format",
283
                      "IWall%" => "xhprof_percent_format",
284
                      "excl_wt" => "number_format",
285
                      "EWall%" => "xhprof_percent_format",
286
287
                      "ut" => "number_format",
288
                      "IUser%" => "xhprof_percent_format",
289
                      "excl_ut" => "number_format",
290
                      "EUser%" => "xhprof_percent_format",
291
292
                      "st" => "number_format",
293
                      "ISys%" => "xhprof_percent_format",
294
                      "excl_st" => "number_format",
295
                      "ESys%" => "xhprof_percent_format",
296
297
                      "cpu" => "number_format",
298
                      "ICpu%" => "xhprof_percent_format",
299
                      "excl_cpu" => "number_format",
300
                      "ECpu%" => "xhprof_percent_format",
301
302
                      "mu" => "number_format",
303
                      "IMUse%" => "xhprof_percent_format",
304
                      "excl_mu" => "number_format",
305
                      "EMUse%" => "xhprof_percent_format",
306
307
                      "pmu" => "number_format",
308
                      "IPMUse%" => "xhprof_percent_format",
309
                      "excl_pmu" => "number_format",
310
                      "EPMUse%" => "xhprof_percent_format",
311
312
                      "samples" => "number_format",
313
                      "ISamples%" => "xhprof_percent_format",
314
                      "excl_samples" => "number_format",
315
                      "ESamples%" => "xhprof_percent_format",
316
                      );
317
318
319
// Textual descriptions for column headers in "diff" mode
320
$diff_descriptions = array(
321
                      "fn" => "Function Name",
322
                      "ct" =>  "Calls Diff",
323
                      "Calls%" => "Calls<br>Diff%",
324
325
                      "wt" => "Incl. Wall<br>Diff<br>(microsec)",
326
                      "IWall%" => "IWall<br> Diff%",
327
                      "excl_wt" => "Excl. Wall<br>Diff<br>(microsec)",
328
                      "EWall%" => "EWall<br>Diff%",
329
330
                      "ut" => "Incl. User Diff<br>(microsec)",
331
                      "IUser%" => "IUser<br>Diff%",
332
                      "excl_ut" => "Excl. User<br>Diff<br>(microsec)",
333
                      "EUser%" => "EUser<br>Diff%",
334
335
                      "cpu" => "Incl. CPU Diff<br>(microsec)",
336
                      "ICpu%" => "ICpu<br>Diff%",
337
                      "excl_cpu" => "Excl. CPU<br>Diff<br>(microsec)",
338
                      "ECpu%" => "ECpu<br>Diff%",
339
340
                      "st" => "Incl. Sys Diff<br>(microsec)",
341
                      "ISys%" => "ISys<br>Diff%",
342
                      "excl_st" => "Excl. Sys Diff<br>(microsec)",
343
                      "ESys%" => "ESys<br>Diff%",
344
345
                      "mu" => "Incl.<br>MemUse<br>Diff<br>(bytes)",
346
                      "IMUse%" => "IMemUse<br>Diff%",
347
                      "excl_mu" => "Excl.<br>MemUse<br>Diff<br>(bytes)",
348
                      "EMUse%" => "EMemUse<br>Diff%",
349
350
                      "pmu" => "Incl.<br> PeakMemUse<br>Diff<br>(bytes)",
351
                      "IPMUse%" => "IPeakMemUse<br>Diff%",
352
                      "excl_pmu" => "Excl.<br>PeakMemUse<br>Diff<br>(bytes)",
353
                      "EPMUse%" => "EPeakMemUse<br>Diff%",
354
355
                      "samples" => "Incl. Samples Diff",
356
                      "ISamples%" => "ISamples Diff%",
357
                      "excl_samples" => "Excl. Samples Diff",
358
                      "ESamples%" => "ESamples Diff%",
359
                      );
360
361
// columns that'll be displayed in a top-level report
362
$stats = array();
363
364
// columns that'll be displayed in a function's parent/child report
365
$pc_stats = array();
366
367
// Various total counts
368
$totals = 0;
369
$totals_1 = 0;
370
$totals_2 = 0;
371
372
/*
373
 * The subset of $possible_metrics that is present in the raw profile data.
374
 */
375
$metrics = null;
376
377
/**
378
 * Callback comparison operator (passed to usort() for sorting array of
379
 * tuples) that compares array elements based on the sort column
380
 * specified in $sort_col (global parameter).
381
 *
382
 * @author Kannan
383
 */
384
function sort_cbk($a, $b) {
385
  global $sort_col;
386
  global $diff_mode;
387
388
  if ($sort_col == "fn") {
389
390
    // case insensitive ascending sort for function names
391
    $left = strtoupper($a["fn"]);
392
    $right = strtoupper($b["fn"]);
393
394
    if ($left == $right)
395
      return 0;
396
    return ($left < $right) ? -1 : 1;
397
398
  } else {
399
400
    // descending sort for all others
401
    $left = $a[$sort_col];
402
    $right = $b[$sort_col];
403
404
    // if diff mode, sort by absolute value of regression/improvement
405
    if ($diff_mode) {
406
      $left = abs($left);
407
      $right = abs($right);
408
    }
409
410
    if ($left == $right)
411
      return 0;
412
    return ($left > $right) ? -1 : 1;
413
  }
414
}
415
416
/**
417
 * Get the appropriate description for a statistic
418
 * (depending upon whether we are in diff report mode
419
 * or single run report mode).
420
 *
421
 * @author Kannan
422
 */
423
function stat_description($stat) {
424
  global $descriptions;
425
  global $diff_descriptions;
426
  global $diff_mode;
427
428
  if ($diff_mode) {
429
    return $diff_descriptions[$stat];
430
  } else {
431
    return $descriptions[$stat];
432
  }
433
}
434
435
436
/**
437
 * Analyze raw data & generate the profiler report
438
 * (common for both single run mode and diff mode).
439
 *
440
 * @author: Kannan
441
 */
442
function profiler_report ($url_params,
443
                          $rep_symbol,
444
                          $sort,
445
                          $run1,
446
                          $run1_desc,
447
                          $run1_data,
448
                          $run2 = 0,
449
                          $run2_desc = "",
450
                          $run2_data = array()) {
451
  global $totals;
452
  global $totals_1;
453
  global $totals_2;
454
  global $stats;
455
  global $pc_stats;
456
  global $diff_mode;
457
  global $base_path;
458
459
  // if we are reporting on a specific function, we can trim down
460
  // the report(s) to just stuff that is relevant to this function.
461
  // That way compute_flat_info()/compute_diff() etc. do not have
462
  // to needlessly work hard on churning irrelevant data.
463
  if (!empty($rep_symbol)) {
464
    $run1_data = xhprof_trim_run($run1_data, array($rep_symbol));
465
    if ($diff_mode) {
466
      $run2_data = xhprof_trim_run($run2_data, array($rep_symbol));
467
    }
468
  }
469
470
  if ($diff_mode) {
471
    $run_delta = xhprof_compute_diff($run1_data, $run2_data);
472
    $symbol_tab  = xhprof_compute_flat_info($run_delta, $totals);
473
    $symbol_tab1 = xhprof_compute_flat_info($run1_data, $totals_1);
474
    $symbol_tab2 = xhprof_compute_flat_info($run2_data, $totals_2);
475
  } else {
476
    $symbol_tab = xhprof_compute_flat_info($run1_data, $totals);
477
  }
478
479
  $run1_txt = sprintf("<b>Run #%s:</b> %s",
480
                      $run1, $run1_desc);
481
482
  $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
483
                                                           'symbol'),
484
                                        'all');
485
486
  $top_link_query_string = "$base_path/?" . http_build_query($base_url_params);
487
488
  if ($diff_mode) {
489
    $diff_text = "Diff";
490
    $base_url_params = xhprof_array_unset($base_url_params, 'run1');
491
    $base_url_params = xhprof_array_unset($base_url_params, 'run2');
492
    $run1_link = xhprof_render_link('View Run #' . $run1,
493
                           "$base_path/?" .
494
                           http_build_query(xhprof_array_set($base_url_params,
495
                                                      'run',
496
                                                      $run1)));
497
    $run2_txt = sprintf("<b>Run #%s:</b> %s",
498
                        $run2, $run2_desc);
499
500
    $run2_link = xhprof_render_link('View Run #' . $run2,
501
                                    "$base_path/?" .
502
                        http_build_query(xhprof_array_set($base_url_params,
503
                                                          'run',
504
                                                          $run2)));
505
  } else {
506
    $diff_text = "Run";
507
  }
508
509
  // set up the action links for operations that can be done on this report
510
  $links = array();
511
  $links [] =  xhprof_render_link("View Top Level $diff_text Report",
512
                                 $top_link_query_string);
513
514
  if ($diff_mode) {
515
    $inverted_params = $url_params;
516
    $inverted_params['run1'] = $url_params['run2'];
517
    $inverted_params['run2'] = $url_params['run1'];
518
519
    // view the different runs or invert the current diff
520
    $links [] = $run1_link;
521
    $links [] = $run2_link;
522
    $links [] = xhprof_render_link('Invert ' . $diff_text . ' Report',
523
                           "$base_path/?".
524
                           http_build_query($inverted_params));
525
  }
526
527
  // lookup function typeahead form
528
  $links [] = '<input class="function_typeahead" ' .
529
              ' type="input" size="40" maxlength="100" />';
530
531
  echo xhprof_render_actions($links);
532
533
534
  echo
535
    '<dl class=phprof_report_info>' .
536
    '  <dt>' . $diff_text . ' Report</dt>' .
537
    '  <dd>' . ($diff_mode ?
538
                $run1_txt . '<br><b>vs.</b><br>' . $run2_txt :
539
                $run1_txt) .
540
    '  </dd>' .
541
    '  <dt>Tip</dt>' .
542
    '  <dd>Click a function name below to drill down.</dd>' .
543
    '</dl>' .
544
    '<div style="clear: both; margin: 3em 0em;"></div>';
545
546
  // data tables
547
  if (!empty($rep_symbol)) {
548
    if (!isset($symbol_tab[$rep_symbol])) {
549
      echo "<hr>Symbol <b>$rep_symbol</b> not found in XHProf run</b><hr>";
550
      return;
551
    }
552
553
    /* single function report with parent/child information */
554
    if ($diff_mode) {
555
      $info1 = isset($symbol_tab1[$rep_symbol]) ?
556
                       $symbol_tab1[$rep_symbol] : null;
557
      $info2 = isset($symbol_tab2[$rep_symbol]) ?
558
                       $symbol_tab2[$rep_symbol] : null;
559
      symbol_report($url_params, $run_delta, $symbol_tab[$rep_symbol],
560
                    $sort, $rep_symbol,
561
                    $run1, $info1,
562
                    $run2, $info2);
563
    } else {
564
      symbol_report($url_params, $run1_data, $symbol_tab[$rep_symbol],
565
                    $sort, $rep_symbol, $run1);
566
    }
567
  } else {
568
    /* flat top-level report of all functions */
569
    full_report($url_params, $symbol_tab, $sort, $run1, $run2);
570
  }
571
}
572
573
/**
574
 * Computes percentage for a pair of values, and returns it
575
 * in string format.
576
 */
577
function pct($a, $b) {
578
  if ($b == 0) {
579
    return "N/A";
580
  } else {
581
    $res = (round(($a * 1000 / $b)) / 10);
582
    return $res;
583
  }
584
}
585
586
/**
587
 * Given a number, returns the td class to use for display.
588
 *
589
 * For instance, negative numbers in diff reports comparing two runs (run1 & run2)
590
 * represent improvement from run1 to run2. We use green to display those deltas,
591
 * and red for regression deltas.
592
 */
593
function get_print_class($num, $bold) {
594
  global $vbar;
595
  global $vbbar;
596
  global $vrbar;
597
  global $vgbar;
598
  global $diff_mode;
599
600
  if ($bold) {
601
    if ($diff_mode) {
602
      if ($num <= 0) {
603
        $class = $vgbar; // green (improvement)
604
      } else {
605
        $class = $vrbar; // red (regression)
606
      }
607
    } else {
608
      $class = $vbbar; // blue
609
    }
610
  }
611
  else {
612
    $class = $vbar;  // default (black)
613
  }
614
615
  return $class;
616
}
617
618
/**
619
 * Prints a <td> element with a numeric value.
620
 */
621
function print_td_num($num, $fmt_func, $bold=false, $attributes=null) {
622
623
  $class = get_print_class($num, $bold);
624
625
  if (!empty($fmt_func)) {
626
    $num = call_user_func($fmt_func, $num);
627
  }
628
629
  print("<td $attributes $class>$num</td>\n");
630
}
631
632
/**
633
 * Prints a <td> element with a pecentage.
634
 */
635
function print_td_pct($numer, $denom, $bold=false, $attributes=null) {
636
  global $vbar;
637
  global $vbbar;
638
  global $diff_mode;
639
640
  $class = get_print_class($numer, $bold);
641
642
  if ($denom == 0) {
643
    $pct = "N/A%";
644
  } else {
645
    $pct = xhprof_percent_format($numer / abs($denom));
646
  }
647
648
  print("<td $attributes $class>$pct</td>\n");
649
}
650
651
/**
652
 * Print "flat" data corresponding to one function.
653
 *
654
 * @author Kannan
655
 */
656
function print_function_info($url_params, $info, $sort, $run1, $run2) {
657
  static $odd_even = 0;
658
659
  global $totals;
660
  global $sort_col;
661
  global $metrics;
662
  global $format_cbk;
663
  global $display_calls;
664
  global $base_path;
665
666
  // Toggle $odd_or_even
667
  $odd_even = 1 - $odd_even;
668
669
  if ($odd_even) {
670
    print("<tr>");
671
  }
672
  else {
673
    print('<tr bgcolor="#e5e5e5">');
674
  }
675
676
  $href = "$base_path/?" .
677
           http_build_query(xhprof_array_set($url_params,
678
                                             'symbol', $info["fn"]));
679
680
  print('<td>');
681
  print(xhprof_render_link($info["fn"], $href));
682
  print_source_link($info);
683
  print("</td>\n");
684
685
  if ($display_calls) {
686
    // Call Count..
687
    print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"));
688
    print_td_pct($info["ct"], $totals["ct"], ($sort_col == "ct"));
689
  }
690
691
  // Other metrics..
692
  foreach ($metrics as $metric) {
693
    // Inclusive metric
694
    print_td_num($info[$metric], $format_cbk[$metric],
695
                 ($sort_col == $metric));
696
    print_td_pct($info[$metric], $totals[$metric],
697
                 ($sort_col == $metric));
698
699
    // Exclusive Metric
700
    print_td_num($info["excl_" . $metric],
701
                 $format_cbk["excl_" . $metric],
702
                 ($sort_col == "excl_" . $metric));
703
    print_td_pct($info["excl_" . $metric],
704
                 $totals[$metric],
705
                 ($sort_col == "excl_" . $metric));
706
  }
707
708
  print("</tr>\n");
709
}
710
711
/**
712
 * Print non-hierarchical (flat-view) of profiler data.
713
 *
714
 * @author Kannan
715
 */
716
function print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit) {
717
718
  global $stats;
719
  global $sortable_columns;
720
  global $vwbar;
721
  global $base_path;
722
723
  $size  = count($flat_data);
724
  if (!$limit) {              // no limit
725
    $limit = $size;
726
    $display_link = "";
727
  } else {
728
    $display_link = xhprof_render_link(" [ <b class=bubble>display all </b>]",
729
                                       "$base_path/?" .
730
                                       http_build_query(xhprof_array_set($url_params,
731
                                                                         'all', 1)));
732
  }
733
734
  print("<h3 align=center>$title $display_link</h3><br>");
735
736
  print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
737
        .'rules=rows bordercolor="#bdc7d8" align=center>');
738
  print('<tr bgcolor="#bdc7d8" align=right>');
739
740
  foreach ($stats as $stat) {
741
    $desc = stat_description($stat);
742
    if (array_key_exists($stat, $sortable_columns)) {
743
      $href = "$base_path/?"
744
              . http_build_query(xhprof_array_set($url_params, 'sort', $stat));
745
      $header = xhprof_render_link($desc, $href);
746
    } else {
747
      $header = $desc;
748
    }
749
750
    if ($stat == "fn")
751
      print("<th align=left><nobr>$header</th>");
752
    else print("<th " . $vwbar . "><nobr>$header</th>");
753
  }
754
  print("</tr>\n");
755
756
  if ($limit >= 0) {
757
    $limit = min($size, $limit);
758
    for ($i = 0; $i < $limit; $i++) {
759
      print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2);
760
    }
761
  } else {
762
    // if $limit is negative, print abs($limit) items starting from the end
763
    $limit = min($size, abs($limit));
764
    for ($i = 0; $i < $limit; $i++) {
765
      print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2);
766
    }
767
  }
768
  print("</table>");
769
770
  // let's print the display all link at the bottom as well...
771
  if ($display_link) {
772
    echo '<div style="text-align: left; padding: 2em">' . $display_link . '</div>';
773
  }
774
775
}
776
777
/**
778
 * Generates a tabular report for all functions. This is the top-level report.
779
 *
780
 * @author Kannan
781
 */
782
function full_report($url_params, $symbol_tab, $sort, $run1, $run2) {
783
  global $vwbar;
784
  global $vbar;
785
  global $totals;
786
  global $totals_1;
787
  global $totals_2;
788
  global $metrics;
789
  global $diff_mode;
790
  global $descriptions;
791
  global $sort_col;
792
  global $format_cbk;
793
  global $display_calls;
794
  global $base_path;
795
796
  $possible_metrics = xhprof_get_possible_metrics();
797
798
  if ($diff_mode) {
799
800
    $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
801
                                                             'run1'),
802
                                          'run2');
803
    $href1 = "$base_path/?" .
804
      http_build_query(xhprof_array_set($base_url_params,
805
                                        'run', $run1));
806
    $href2 = "$base_path/?" .
807
      http_build_query(xhprof_array_set($base_url_params,
808
                                        'run', $run2));
809
810
    print("<h3><center>Overall Diff Summary</center></h3>");
811
    print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
812
          .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
813
    print('<tr bgcolor="#bdc7d8" align=right>');
814
    print("<th></th>");
815
    print("<th $vwbar>" . xhprof_render_link("Run #$run1", $href1) . "</th>");
816
    print("<th $vwbar>" . xhprof_render_link("Run #$run2", $href2) . "</th>");
817
    print("<th $vwbar>Diff</th>");
818
    print("<th $vwbar>Diff%</th>");
819
    print('</tr>');
820
821
    if ($display_calls) {
822
      print('<tr>');
823
      print("<td>Number of Function Calls</td>");
824
      print_td_num($totals_1["ct"], $format_cbk["ct"]);
825
      print_td_num($totals_2["ct"], $format_cbk["ct"]);
826
      print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true);
827
      print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true);
828
      print('</tr>');
829
    }
830
831
    foreach ($metrics as $metric) {
832
      $m = $metric;
833
      print('<tr>');
834
      print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
835
      print_td_num($totals_1[$m], $format_cbk[$m]);
836
      print_td_num($totals_2[$m], $format_cbk[$m]);
837
      print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true);
838
      print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true);
839
      print('<tr>');
840
    }
841
    print('</table>');
842
843
    $callgraph_report_title = '[View Regressions/Improvements using Callgraph Diff]';
844
845
  } else {
846
    print("<p><center>\n");
847
848
    print('<table cellpadding=2 cellspacing=1 width="30%" '
849
          .'bgcolor="#bdc7d8" align=center>' . "\n");
850
    echo "<tr>";
851
    echo "<th style='text-align:right'>Overall Summary</th>";
852
    echo "<th></th>";
853
    echo "</tr>";
854
855
    foreach ($metrics as $metric) {
856
      echo "<tr>";
857
      echo "<td style='text-align:right; font-weight:bold'>Total "
858
            . str_replace("<br>", " ", stat_description($metric)) . ":</td>";
859
      echo "<td>" . number_format($totals[$metric]) .  " "
860
           . $possible_metrics[$metric][1] . "</td>";
861
      echo "</tr>";
862
    }
863
864
    if ($display_calls) {
865
      echo "<tr>";
866
      echo "<td style='text-align:right; font-weight:bold'>Number of Function Calls:</td>";
867
      echo "<td>" . number_format($totals['ct']) . "</td>";
868
      echo "</tr>";
869
    }
870
871
    echo "</table>";
872
    print("</center></p>\n");
873
874
    $callgraph_report_title = '[View Full Callgraph]';
875
  }
876
877
  print("<center><br><h3>" .
878
        xhprof_render_link($callgraph_report_title,
879
                    "$base_path/callgraph.php" . "?" . http_build_query($url_params))
880
        . "</h3></center>");
881
882
883
  $flat_data = array();
884
  foreach ($symbol_tab as $symbol => $info) {
885
    $tmp = $info;
886
    $tmp["fn"] = $symbol;
887
    $flat_data[] = $tmp;
888
  }
889
  usort($flat_data, 'sort_cbk');
890
891
  print("<br>");
892
893
  if (!empty($url_params['all'])) {
894
    $all = true;
895
    $limit = 0;    // display all rows
896
  } else {
897
    $all = false;
898
    $limit = 100;  // display only limited number of rows
899
  }
900
901
  $desc = str_replace("<br>", " ", $descriptions[$sort_col]);
902
903
  if ($diff_mode) {
904
    if ($all) {
905
      $title = "Total Diff Report: '
906
               .'Sorted by absolute value of regression/improvement in $desc";
907
    } else {
908
      $title = "Top 100 <i style='color:red'>Regressions</i>/"
909
               . "<i style='color:green'>Improvements</i>: "
910
               . "Sorted by $desc Diff";
911
    }
912
  } else {
913
    if ($all) {
914
      $title = "Sorted by $desc";
915
    } else {
916
      $title = "Displaying top $limit functions: Sorted by $desc";
917
    }
918
  }
919
  print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit);
920
}
921
922
923
/**
924
 * Return attribute names and values to be used by javascript tooltip.
925
 */
926
function get_tooltip_attributes($type, $metric) {
927
  return "type='$type' metric='$metric'";
928
}
929
930
/**
931
 * Print info for a parent or child function in the
932
 * parent & children report.
933
 *
934
 * @author Kannan
935
 */
936
function pc_info($info, $base_ct, $base_info, $parent) {
937
  global $sort_col;
938
  global $metrics;
939
  global $format_cbk;
940
  global $display_calls;
941
942
  if ($parent)
943
    $type = "Parent";
944
  else $type = "Child";
945
946
  if ($display_calls) {
947
    $mouseoverct = get_tooltip_attributes($type, "ct");
948
    /* call count */
949
    print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"), $mouseoverct);
950
    print_td_pct($info["ct"], $base_ct, ($sort_col == "ct"), $mouseoverct);
951
  }
952
953
  /* Inclusive metric values  */
954
  foreach ($metrics as $metric) {
955
    print_td_num($info[$metric], $format_cbk[$metric],
956
                 ($sort_col == $metric),
957
                 get_tooltip_attributes($type, $metric));
958
    print_td_pct($info[$metric], $base_info[$metric], ($sort_col == $metric),
959
                 get_tooltip_attributes($type, $metric));
960
  }
961
}
962
963
function print_pc_array($url_params, $results, $base_ct, $base_info, $parent,
964
                        $run1, $run2) {
965
  global $base_path;
966
967
  // Construct section title
968
  if ($parent) {
969
    $title = 'Parent function';
970
  }
971
  else {
972
    $title = 'Child function';
973
  }
974
  if (count($results) > 1) {
975
    $title .= 's';
976
  }
977
978
  print("<tr bgcolor='#e0e0ff'><td>");
979
  print("<b><i><center>" . $title . "</center></i></b>");
980
  print("</td></tr>");
981
982
  $odd_even = 0;
983
  foreach ($results as $info) {
984
    $href = "$base_path/?" .
985
      http_build_query(xhprof_array_set($url_params,
986
                                        'symbol', $info["fn"]));
987
988
    $odd_even = 1 - $odd_even;
989
990
    if ($odd_even) {
991
      print('<tr>');
992
    }
993
    else {
994
      print('<tr bgcolor="#e5e5e5">');
995
    }
996
997
    print("<td>" . xhprof_render_link($info["fn"], $href));
998
    print_source_link($info);
999
    print("</td>");
1000
    pc_info($info, $base_ct, $base_info, $parent);
1001
    print("</tr>");
1002
  }
1003
}
1004
1005
function print_source_link($info) {
1006
  if (strncmp($info['fn'], 'run_init', 8) && $info['fn'] !== 'main()') {
1007
	if (defined('XHPROF_SYMBOL_LOOKUP_URL')) {
1008
      $link = xhprof_render_link(
1009
        'source',
1010
        XHPROF_SYMBOL_LOOKUP_URL . '?symbol='.rawurlencode($info["fn"]));
1011
      print(' ('.$link.')');
1012
    }
1013
  }
1014
}
1015
1016
1017
function print_symbol_summary($symbol_info, $stat, $base) {
1018
1019
  $val = $symbol_info[$stat];
1020
  $desc = str_replace("<br>", " ", stat_description($stat));
1021
1022
  print("$desc: </td>");
1023
  print(number_format($val));
1024
  print(" (" . pct($val, $base) . "% of overall)");
1025
  if (substr($stat, 0, 4) == "excl") {
1026
    $func_base = $symbol_info[str_replace("excl_", "", $stat)];
1027
    print(" (" . pct($val, $func_base) . "% of this function)");
1028
  }
1029
  print("<br>");
1030
}
1031
1032
/**
1033
 * Generates a report for a single function/symbol.
1034
 *
1035
 * @author Kannan
1036
 */
1037
function symbol_report($url_params,
1038
                       $run_data, $symbol_info, $sort, $rep_symbol,
1039
                       $run1,
1040
                       $symbol_info1 = null,
1041
                       $run2 = 0,
1042
                       $symbol_info2 = null) {
1043
  global $vwbar;
1044
  global $vbar;
1045
  global $totals;
1046
  global $pc_stats;
1047
  global $sortable_columns;
1048
  global $metrics;
1049
  global $diff_mode;
1050
  global $descriptions;
1051
  global $format_cbk;
1052
  global $sort_col;
1053
  global $display_calls;
1054
  global $base_path;
1055
1056
  $possible_metrics = xhprof_get_possible_metrics();
1057
1058
  if ($diff_mode) {
1059
    $diff_text = "<b>Diff</b>";
1060
    $regr_impr = "<i style='color:red'>Regression</i>/<i style='color:green'>Improvement</i>";
1061
  } else {
1062
    $diff_text = "";
1063
    $regr_impr = "";
1064
  }
1065
1066
  if ($diff_mode) {
1067
1068
    $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
1069
                                                             'run1'),
1070
                                          'run2');
1071
    $href1 = "$base_path?"
1072
      . http_build_query(xhprof_array_set($base_url_params, 'run', $run1));
1073
    $href2 = "$base_path?"
1074
      . http_build_query(xhprof_array_set($base_url_params, 'run', $run2));
1075
1076
    print("<h3 align=center>$regr_impr summary for $rep_symbol<br><br></h3>");
1077
    print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
1078
          .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
1079
    print('<tr bgcolor="#bdc7d8" align=right>');
1080
    print("<th align=left>$rep_symbol</th>");
1081
    print("<th $vwbar><a href=" . $href1 . ">Run #$run1</a></th>");
1082
    print("<th $vwbar><a href=" . $href2 . ">Run #$run2</a></th>");
1083
    print("<th $vwbar>Diff</th>");
1084
    print("<th $vwbar>Diff%</th>");
1085
    print('</tr>');
1086
    print('<tr>');
1087
1088
    if ($display_calls) {
1089
      print("<td>Number of Function Calls</td>");
1090
      print_td_num($symbol_info1["ct"], $format_cbk["ct"]);
1091
      print_td_num($symbol_info2["ct"], $format_cbk["ct"]);
1092
      print_td_num($symbol_info2["ct"] - $symbol_info1["ct"],
1093
                   $format_cbk["ct"], true);
1094
      print_td_pct($symbol_info2["ct"] - $symbol_info1["ct"],
1095
                   $symbol_info1["ct"], true);
1096
      print('</tr>');
1097
    }
1098
1099
1100
    foreach ($metrics as $metric) {
1101
      $m = $metric;
1102
1103
      // Inclusive stat for metric
1104
      print('<tr>');
1105
      print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
1106
      print_td_num($symbol_info1[$m], $format_cbk[$m]);
1107
      print_td_num($symbol_info2[$m], $format_cbk[$m]);
1108
      print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
1109
      print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
1110
      print('</tr>');
1111
1112
      // AVG (per call) Inclusive stat for metric
1113
      print('<tr>');
1114
      print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . " per call </td>");
1115
      $avg_info1 = 'N/A';
1116
      $avg_info2 = 'N/A';
1117
      if ($symbol_info1['ct'] > 0) {
1118
        $avg_info1 = ($symbol_info1[$m] / $symbol_info1['ct']);
1119
      }
1120
      if ($symbol_info2['ct'] > 0) {
1121
        $avg_info2 = ($symbol_info2[$m] / $symbol_info2['ct']);
1122
      }
1123
      print_td_num($avg_info1, $format_cbk[$m]);
1124
      print_td_num($avg_info2, $format_cbk[$m]);
1125
      print_td_num($avg_info2 - $avg_info1, $format_cbk[$m], true);
1126
      print_td_pct($avg_info2 - $avg_info1, $avg_info1, true);
1127
      print('</tr>');
1128
1129
      // Exclusive stat for metric
1130
      $m = "excl_" . $metric;
1131
      print('<tr style="border-bottom: 1px solid black;">');
1132
      print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
1133
      print_td_num($symbol_info1[$m], $format_cbk[$m]);
1134
      print_td_num($symbol_info2[$m], $format_cbk[$m]);
1135
      print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
1136
      print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
1137
      print('</tr>');
1138
    }
1139
1140
    print('</table>');
1141
  }
1142
1143
  print("<br><h4><center>");
1144
  print("Parent/Child $regr_impr report for <b>$rep_symbol</b>");
1145
1146
  $callgraph_href = "$base_path/callgraph.php?"
1147
    . http_build_query(xhprof_array_set($url_params, 'func', $rep_symbol));
1148
1149
  print(" <a href='$callgraph_href'>[View Callgraph $diff_text]</a><br>");
1150
1151
  print("</center></h4><br>");
1152
1153
  print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
1154
        .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
1155
  print('<tr bgcolor="#bdc7d8" align=right>');
1156
1157
  foreach ($pc_stats as $stat) {
1158
    $desc = stat_description($stat);
1159
    if (array_key_exists($stat, $sortable_columns)) {
1160
1161
      $href = "$base_path/?" .
1162
        http_build_query(xhprof_array_set($url_params,
1163
                                          'sort', $stat));
1164
      $header = xhprof_render_link($desc, $href);
1165
    } else {
1166
      $header = $desc;
1167
    }
1168
1169
    if ($stat == "fn")
1170
      print("<th align=left><nobr>$header</th>");
1171
    else print("<th " . $vwbar . "><nobr>$header</th>");
1172
  }
1173
  print("</tr>");
1174
1175
  print("<tr bgcolor='#e0e0ff'><td>");
1176
  print("<b><i><center>Current Function</center></i></b>");
1177
  print("</td></tr>");
1178
1179
  print("<tr>");
1180
  // make this a self-reference to facilitate copy-pasting snippets to e-mails
1181
  print("<td><a href=''>$rep_symbol</a>");
1182
  print_source_link(array('fn' => $rep_symbol));
1183
  print("</td>");
1184
1185
  if ($display_calls) {
1186
    // Call Count
1187
    print_td_num($symbol_info["ct"], $format_cbk["ct"]);
1188
    print_td_pct($symbol_info["ct"], $totals["ct"]);
1189
  }
1190
1191
  // Inclusive Metrics for current function
1192
  foreach ($metrics as $metric) {
1193
    print_td_num($symbol_info[$metric], $format_cbk[$metric], ($sort_col == $metric));
1194
    print_td_pct($symbol_info[$metric], $totals[$metric], ($sort_col == $metric));
1195
  }
1196
  print("</tr>");
1197
1198
  print("<tr bgcolor='#ffffff'>");
1199
  print("<td style='text-align:right;color:blue'>"
1200
        ."Exclusive Metrics $diff_text for Current Function</td>");
1201
1202
  if ($display_calls) {
1203
    // Call Count
1204
    print("<td $vbar></td>");
1205
    print("<td $vbar></td>");
1206
  }
1207
1208
  // Exclusive Metrics for current function
1209
  foreach ($metrics as $metric) {
1210
    print_td_num($symbol_info["excl_" . $metric], $format_cbk["excl_" . $metric],
1211
                 ($sort_col == $metric),
1212
                 get_tooltip_attributes("Child", $metric));
1213
    print_td_pct($symbol_info["excl_" . $metric], $symbol_info[$metric],
1214
                 ($sort_col == $metric),
1215
                 get_tooltip_attributes("Child", $metric));
1216
  }
1217
  print("</tr>");
1218
1219
  // list of callers/parent functions
1220
  $results = array();
1221
  if ($display_calls) {
1222
    $base_ct = $symbol_info["ct"];
1223
  } else {
1224
    $base_ct = 0;
1225
  }
1226
  foreach ($metrics as $metric) {
1227
    $base_info[$metric] = $symbol_info[$metric];
1228
  }
1229
  foreach ($run_data as $parent_child => $info) {
1230
    list($parent, $child) = xhprof_parse_parent_child($parent_child);
1231
    if (($child == $rep_symbol) && ($parent)) {
1232
      $info_tmp = $info;
1233
      $info_tmp["fn"] = $parent;
1234
      $results[] = $info_tmp;
1235
    }
1236
  }
1237
  usort($results, 'sort_cbk');
1238
1239
  if (count($results) > 0) {
1240
    print_pc_array($url_params, $results, $base_ct, $base_info, true,
1241
                   $run1, $run2);
1242
  }
1243
1244
  // list of callees/child functions
1245
  $results = array();
1246
  $base_ct = 0;
1247
  foreach ($run_data as $parent_child => $info) {
1248
    list($parent, $child) = xhprof_parse_parent_child($parent_child);
1249
    if ($parent == $rep_symbol) {
1250
      $info_tmp = $info;
1251
      $info_tmp["fn"] = $child;
1252
      $results[] = $info_tmp;
1253
      if ($display_calls) {
1254
        $base_ct += $info["ct"];
1255
      }
1256
    }
1257
  }
1258
  usort($results, 'sort_cbk');
1259
1260
  if (count($results)) {
1261
    print_pc_array($url_params, $results, $base_ct, $base_info, false,
1262
                   $run1, $run2);
1263
  }
1264
1265
  print("</table>");
1266
1267
  // These will be used for pop-up tips/help.
1268
  // Related javascript code is in: xhprof_report.js
1269
  print("\n");
1270
  print('<script language="javascript">' . "\n");
1271
  print("var func_name = '\"" . $rep_symbol . "\"';\n");
1272
  print("var total_child_ct  = " . $base_ct . ";\n");
1273
  if ($display_calls) {
1274
    print("var func_ct   = " . $symbol_info["ct"] . ";\n");
1275
  }
1276
  print("var func_metrics = new Array();\n");
1277
  print("var metrics_col  = new Array();\n");
1278
  print("var metrics_desc  = new Array();\n");
1279
  if ($diff_mode) {
1280
    print("var diff_mode = true;\n");
1281
  } else {
1282
    print("var diff_mode = false;\n");
1283
  }
1284
  $column_index = 3; // First three columns are Func Name, Calls, Calls%
1285
  foreach ($metrics as $metric) {
1286
    print("func_metrics[\"" . $metric . "\"] = " . round($symbol_info[$metric]) . ";\n");
1287
    print("metrics_col[\"". $metric . "\"] = " . $column_index . ";\n");
1288
    print("metrics_desc[\"". $metric . "\"] = \"" . $possible_metrics[$metric][2] . "\";\n");
1289
1290
    // each metric has two columns..
1291
    $column_index += 2;
1292
  }
1293
  print('</script>');
1294
  print("\n");
1295
1296
}
1297
1298
/**
1299
 * Generate the profiler report for a single run.
1300
 *
1301
 * @author Kannan
1302
 */
1303
function profiler_single_run_report ($url_params,
1304
                                     $xhprof_data,
1305
                                     $run_desc,
1306
                                     $rep_symbol,
1307
                                     $sort,
1308
                                     $run) {
1309
1310
  init_metrics($xhprof_data, $rep_symbol, $sort, false);
1311
1312
  profiler_report($url_params, $rep_symbol, $sort, $run, $run_desc,
1313
                  $xhprof_data);
1314
}
1315
1316
1317
1318
/**
1319
 * Generate the profiler report for diff mode (delta between two runs).
1320
 *
1321
 * @author Kannan
1322
 */
1323
function profiler_diff_report($url_params,
1324
                              $xhprof_data1,
1325
                              $run1_desc,
1326
                              $xhprof_data2,
1327
                              $run2_desc,
1328
                              $rep_symbol,
1329
                              $sort,
1330
                              $run1,
1331
                              $run2) {
1332
1333
1334
  // Initialize what metrics we'll display based on data in Run2
1335
  init_metrics($xhprof_data2, $rep_symbol, $sort, true);
1336
1337
  profiler_report($url_params,
1338
                  $rep_symbol,
1339
                  $sort,
1340
                  $run1,
1341
                  $run1_desc,
1342
                  $xhprof_data1,
1343
                  $run2,
1344
                  $run2_desc,
1345
                  $xhprof_data2);
1346
}
1347
1348
1349
/**
1350
 * Generate a XHProf Display View given the various URL parameters
1351
 * as arguments. The first argument is an object that implements
1352
 * the iXHProfRuns interface.
1353
 *
1354
 * @param object  $xhprof_runs_impl  An object that implements
1355
 *                                   the iXHProfRuns interface
1356
 *.
1357
 * @param array   $url_params   Array of non-default URL params.
1358
 *
1359
 * @param string  $source       Category/type of the run. The source in
1360
 *                              combination with the run id uniquely
1361
 *                              determines a profiler run.
1362
 *
1363
 * @param string  $run          run id, or comma separated sequence of
1364
 *                              run ids. The latter is used if an aggregate
1365
 *                              report of the runs is desired.
1366
 *
1367
 * @param string  $wts          Comma separate list of integers.
1368
 *                              Represents the weighted ratio in
1369
 *                              which which a set of runs will be
1370
 *                              aggregated. [Used only for aggregate
1371
 *                              reports.]
1372
 *
1373
 * @param string  $symbol       Function symbol. If non-empty then the
1374
 *                              parent/child view of this function is
1375
 *                              displayed. If empty, a flat-profile view
1376
 *                              of the functions is displayed.
1377
 *
1378
 * @param string  $run1         Base run id (for diff reports)
1379
 *
1380
 * @param string  $run2         New run id (for diff reports)
1381
 *
1382
 */
1383
function displayXHProfReport($xhprof_runs_impl, $url_params, $source,
1384
                             $run, $wts, $symbol, $sort, $run1, $run2) {
1385
1386
  if ($run) {                              // specific run to display?
1387
1388
    // run may be a single run or a comma separate list of runs
1389
    // that'll be aggregated. If "wts" (a comma separated list
1390
    // of integral weights is specified), the runs will be
1391
    // aggregated in that ratio.
1392
    //
1393
    $runs_array = explode(",", $run);
1394
1395
    if (count($runs_array) == 1) {
1396
      $xhprof_data = $xhprof_runs_impl->get_run($runs_array[0],
1397
                                                $source,
1398
                                                $description);
0 ignored issues
show
Bug introduced by
The variable $description seems only to be defined at a later point. Did you maybe move this code here without moving the variable definition?

This error can happen if you refactor code and forget to move the variable initialization.

Let’s take a look at a simple example:

function someFunction() {
    $x = 5;
    echo $x;
}

The above code is perfectly fine. Now imagine that we re-order the statements:

function someFunction() {
    echo $x;
    $x = 5;
}

In that case, $x would be read before it is initialized. This was a very basic example, however the principle is the same for the found issue.

Loading history...
1399
    } else {
1400
      if (!empty($wts)) {
1401
        $wts_array  = explode(",", $wts);
1402
      } else {
1403
        $wts_array = null;
1404
      }
1405
      $data = xhprof_aggregate_runs($xhprof_runs_impl,
1406
                                    $runs_array, $wts_array, $source, false);
0 ignored issues
show
Bug introduced by
It seems like $wts_array defined by null on line 1403 can also be of type null; however, xhprof_aggregate_runs() does only seem to accept array, maybe add an additional type check?

If a method or function can return multiple different values and unless you are sure that you only can receive a single value in this context, we recommend to add an additional type check:

/**
 * @return array|string
 */
function returnsDifferentValues($x) {
    if ($x) {
        return 'foo';
    }

    return array();
}

$x = returnsDifferentValues($y);
if (is_array($x)) {
    // $x is an array.
}

If this a common case that PHP Analyzer should handle natively, please let us know by opening an issue.

Loading history...
1407
      $xhprof_data = $data['raw'];
1408
      $description = $data['description'];
1409
    }
1410
1411
1412
    profiler_single_run_report($url_params,
1413
                               $xhprof_data,
1414
                               $description,
1415
                               $symbol,
1416
                               $sort,
1417
                               $run);
1418
1419
  } else if ($run1 && $run2) {                  // diff report for two runs
1420
1421
    $xhprof_data1 = $xhprof_runs_impl->get_run($run1, $source, $description1);
1422
    $xhprof_data2 = $xhprof_runs_impl->get_run($run2, $source, $description2);
1423
1424
    profiler_diff_report($url_params,
1425
                         $xhprof_data1,
1426
                         $description1,
1427
                         $xhprof_data2,
1428
                         $description2,
1429
                         $symbol,
1430
                         $sort,
1431
                         $run1,
1432
                         $run2);
1433
1434
  } else {
1435
    echo "No XHProf runs specified in the URL.";
1436
    if (method_exists($xhprof_runs_impl, 'list_runs')) {
1437
      $xhprof_runs_impl->list_runs();
1438
    }
1439
  }
1440
}
1441