|
Moodle
2.2.1
http://www.collinsharper.com
|
00001 <?php 00002 // Copyright (c) 2009 Facebook 00003 // 00004 // Licensed under the Apache License, Version 2.0 (the "License"); 00005 // you may not use this file except in compliance with the License. 00006 // You may obtain a copy of the License at 00007 // 00008 // http://www.apache.org/licenses/LICENSE-2.0 00009 // 00010 // Unless required by applicable law or agreed to in writing, software 00011 // distributed under the License is distributed on an "AS IS" BASIS, 00012 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 00013 // See the License for the specific language governing permissions and 00014 // limitations under the License. 00015 // 00016 00017 // 00018 // XHProf: A Hierarchical Profiler for PHP 00019 // 00020 // XHProf has two components: 00021 // 00022 // * This module is the UI/reporting component, used 00023 // for viewing results of XHProf runs from a browser. 00024 // 00025 // * Data collection component: This is implemented 00026 // as a PHP extension (XHProf). 00027 // 00028 // @author Kannan Muthukkaruppan 00029 // 00030 00031 if (!isset($GLOBALS['XHPROF_LIB_ROOT'])) { 00032 // by default, the parent directory is XHPROF lib root 00033 $GLOBALS['XHPROF_LIB_ROOT'] = realpath(dirname(__FILE__) . '/..'); 00034 } 00035 00036 require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_lib.php'; 00037 require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/callgraph_utils.php'; 00038 require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_runs.php'; 00039 00040 00045 $base_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), "/"); 00046 00047 00058 function xhprof_include_js_css($ui_dir_url_path = null) { 00059 00060 if (empty($ui_dir_url_path)) { 00061 $ui_dir_url_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), "/"); 00062 } 00063 00064 // style sheets 00065 echo "<link href='$ui_dir_url_path/css/xhprof.css' rel='stylesheet' ". 00066 " type='text/css' />"; 00067 echo "<link href='$ui_dir_url_path/jquery/jquery.tooltip.css' ". 00068 " rel='stylesheet' type='text/css' />"; 00069 echo "<link href='$ui_dir_url_path/jquery/jquery.autocomplete.css' ". 00070 " rel='stylesheet' type='text/css' />"; 00071 00072 // javascript 00073 echo "<script src='$ui_dir_url_path/jquery/jquery-1.2.6.js'>". 00074 "</script>"; 00075 echo "<script src='$ui_dir_url_path/jquery/jquery.tooltip.js'>". 00076 "</script>"; 00077 echo "<script src='$ui_dir_url_path/jquery/jquery.autocomplete.js'>" 00078 ."</script>"; 00079 echo "<script src='$ui_dir_url_path/js/xhprof_report.js'></script>"; 00080 } 00081 00082 00083 /* 00084 * Formats call counts for XHProf reports. 00085 * 00086 * Description: 00087 * Call counts in single-run reports are integer values. 00088 * However, call counts for aggregated reports can be 00089 * fractional. This function will print integer values 00090 * without decimal point, but with commas etc. 00091 * 00092 * 4000 ==> 4,000 00093 * 00094 * It'll round fractional values to decimal precision of 3 00095 * 4000.1212 ==> 4,000.121 00096 * 4000.0001 ==> 4,000 00097 * 00098 */ 00099 function xhprof_count_format($num) { 00100 $num = round($num, 3); 00101 if (round($num) == $num) { 00102 return number_format($num); 00103 } else { 00104 return number_format($num, 3); 00105 } 00106 } 00107 00108 function xhprof_percent_format($s, $precision = 1) { 00109 return sprintf('%.'.$precision.'f%%', 100 * $s); 00110 } 00111 00116 function xhprof_render_actions($actions) { 00117 $out = array(); 00118 00119 if (count($actions)) { 00120 $out[] = '<ul class="xhprof_actions">'; 00121 foreach ($actions as $action) { 00122 $out[] = '<li>'.$action.'</li>'; 00123 } 00124 $out[] = '</ul>'; 00125 } 00126 00127 return implode('', $out); 00128 } 00129 00130 00147 function xhprof_render_link($content, $href, $class='', $id='', $title='', 00148 $target='', 00149 $onclick='', $style='', $access='', $onmouseover='', 00150 $onmouseout='', $onmousedown='') { 00151 00152 if (!$content) { 00153 return ''; 00154 } 00155 00156 if ($href) { 00157 $link = '<a href="' . ($href) . '"'; 00158 } else { 00159 $link = '<span'; 00160 } 00161 00162 if ($class) { 00163 $link .= ' class="' . ($class) . '"'; 00164 } 00165 if ($id) { 00166 $link .= ' id="' . ($id) . '"'; 00167 } 00168 if ($title) { 00169 $link .= ' title="' . ($title) . '"'; 00170 } 00171 if ($target) { 00172 $link .= ' target="' . ($target) . '"'; 00173 } 00174 if ($onclick && $href) { 00175 $link .= ' onclick="' . ($onclick) . '"'; 00176 } 00177 if ($style && $href) { 00178 $link .= ' style="' . ($style) . '"'; 00179 } 00180 if ($access && $href) { 00181 $link .= ' accesskey="' . ($access) . '"'; 00182 } 00183 if ($onmouseover) { 00184 $link .= ' onmouseover="' . ($onmouseover) . '"'; 00185 } 00186 if ($onmouseout) { 00187 $link .= ' onmouseout="' . ($onmouseout) . '"'; 00188 } 00189 if ($onmousedown) { 00190 $link .= ' onmousedown="' . ($onmousedown) . '"'; 00191 } 00192 00193 $link .= '>'; 00194 $link .= $content; 00195 if ($href) { 00196 $link .= '</a>'; 00197 } else { 00198 $link .= '</span>'; 00199 } 00200 00201 return $link; 00202 } 00203 00204 00205 // default column to sort on -- wall time 00206 $sort_col = "wt"; 00207 00208 // default is "single run" report 00209 $diff_mode = false; 00210 00211 // call count data present? 00212 $display_calls = true; 00213 00214 // The following column headers are sortable 00215 $sortable_columns = array("fn" => 1, 00216 "ct" => 1, 00217 "wt" => 1, 00218 "excl_wt" => 1, 00219 "ut" => 1, 00220 "excl_ut" => 1, 00221 "st" => 1, 00222 "excl_st" => 1, 00223 "mu" => 1, 00224 "excl_mu" => 1, 00225 "pmu" => 1, 00226 "excl_pmu" => 1, 00227 "cpu" => 1, 00228 "excl_cpu" => 1, 00229 "samples" => 1, 00230 "excl_samples" => 1 00231 ); 00232 00233 // Textual descriptions for column headers in "single run" mode 00234 $descriptions = array( 00235 "fn" => "Function Name", 00236 "ct" => "Calls", 00237 "Calls%" => "Calls%", 00238 00239 "wt" => "Incl. Wall Time<br>(microsec)", 00240 "IWall%" => "IWall%", 00241 "excl_wt" => "Excl. Wall Time<br>(microsec)", 00242 "EWall%" => "EWall%", 00243 00244 "ut" => "Incl. User<br>(microsecs)", 00245 "IUser%" => "IUser%", 00246 "excl_ut" => "Excl. User<br>(microsec)", 00247 "EUser%" => "EUser%", 00248 00249 "st" => "Incl. Sys <br>(microsec)", 00250 "ISys%" => "ISys%", 00251 "excl_st" => "Excl. Sys <br>(microsec)", 00252 "ESys%" => "ESys%", 00253 00254 "cpu" => "Incl. CPU<br>(microsecs)", 00255 "ICpu%" => "ICpu%", 00256 "excl_cpu" => "Excl. CPU<br>(microsec)", 00257 "ECpu%" => "ECPU%", 00258 00259 "mu" => "Incl.<br>MemUse<br>(bytes)", 00260 "IMUse%" => "IMemUse%", 00261 "excl_mu" => "Excl.<br>MemUse<br>(bytes)", 00262 "EMUse%" => "EMemUse%", 00263 00264 "pmu" => "Incl.<br> PeakMemUse<br>(bytes)", 00265 "IPMUse%" => "IPeakMemUse%", 00266 "excl_pmu" => "Excl.<br>PeakMemUse<br>(bytes)", 00267 "EPMUse%" => "EPeakMemUse%", 00268 00269 "samples" => "Incl. Samples", 00270 "ISamples%" => "ISamples%", 00271 "excl_samples" => "Excl. Samples", 00272 "ESamples%" => "ESamples%", 00273 ); 00274 00275 // Formatting Callback Functions... 00276 $format_cbk = array( 00277 "fn" => "", 00278 "ct" => "xhprof_count_format", 00279 "Calls%" => "xhprof_percent_format", 00280 00281 "wt" => "number_format", 00282 "IWall%" => "xhprof_percent_format", 00283 "excl_wt" => "number_format", 00284 "EWall%" => "xhprof_percent_format", 00285 00286 "ut" => "number_format", 00287 "IUser%" => "xhprof_percent_format", 00288 "excl_ut" => "number_format", 00289 "EUser%" => "xhprof_percent_format", 00290 00291 "st" => "number_format", 00292 "ISys%" => "xhprof_percent_format", 00293 "excl_st" => "number_format", 00294 "ESys%" => "xhprof_percent_format", 00295 00296 "cpu" => "number_format", 00297 "ICpu%" => "xhprof_percent_format", 00298 "excl_cpu" => "number_format", 00299 "ECpu%" => "xhprof_percent_format", 00300 00301 "mu" => "number_format", 00302 "IMUse%" => "xhprof_percent_format", 00303 "excl_mu" => "number_format", 00304 "EMUse%" => "xhprof_percent_format", 00305 00306 "pmu" => "number_format", 00307 "IPMUse%" => "xhprof_percent_format", 00308 "excl_pmu" => "number_format", 00309 "EPMUse%" => "xhprof_percent_format", 00310 00311 "samples" => "number_format", 00312 "ISamples%" => "xhprof_percent_format", 00313 "excl_samples" => "number_format", 00314 "ESamples%" => "xhprof_percent_format", 00315 ); 00316 00317 00318 // Textual descriptions for column headers in "diff" mode 00319 $diff_descriptions = array( 00320 "fn" => "Function Name", 00321 "ct" => "Calls Diff", 00322 "Calls%" => "Calls<br>Diff%", 00323 00324 "wt" => "Incl. Wall<br>Diff<br>(microsec)", 00325 "IWall%" => "IWall<br> Diff%", 00326 "excl_wt" => "Excl. Wall<br>Diff<br>(microsec)", 00327 "EWall%" => "EWall<br>Diff%", 00328 00329 "ut" => "Incl. User Diff<br>(microsec)", 00330 "IUser%" => "IUser<br>Diff%", 00331 "excl_ut" => "Excl. User<br>Diff<br>(microsec)", 00332 "EUser%" => "EUser<br>Diff%", 00333 00334 "cpu" => "Incl. CPU Diff<br>(microsec)", 00335 "ICpu%" => "ICpu<br>Diff%", 00336 "excl_cpu" => "Excl. CPU<br>Diff<br>(microsec)", 00337 "ECpu%" => "ECpu<br>Diff%", 00338 00339 "st" => "Incl. Sys Diff<br>(microsec)", 00340 "ISys%" => "ISys<br>Diff%", 00341 "excl_st" => "Excl. Sys Diff<br>(microsec)", 00342 "ESys%" => "ESys<br>Diff%", 00343 00344 "mu" => "Incl.<br>MemUse<br>Diff<br>(bytes)", 00345 "IMUse%" => "IMemUse<br>Diff%", 00346 "excl_mu" => "Excl.<br>MemUse<br>Diff<br>(bytes)", 00347 "EMUse%" => "EMemUse<br>Diff%", 00348 00349 "pmu" => "Incl.<br> PeakMemUse<br>Diff<br>(bytes)", 00350 "IPMUse%" => "IPeakMemUse<br>Diff%", 00351 "excl_pmu" => "Excl.<br>PeakMemUse<br>Diff<br>(bytes)", 00352 "EPMUse%" => "EPeakMemUse<br>Diff%", 00353 00354 "samples" => "Incl. Samples Diff", 00355 "ISamples%" => "ISamples Diff%", 00356 "excl_samples" => "Excl. Samples Diff", 00357 "ESamples%" => "ESamples Diff%", 00358 ); 00359 00360 // columns that'll be displayed in a top-level report 00361 $stats = array(); 00362 00363 // columns that'll be displayed in a function's parent/child report 00364 $pc_stats = array(); 00365 00366 // Various total counts 00367 $totals = 0; 00368 $totals_1 = 0; 00369 $totals_2 = 0; 00370 00371 /* 00372 * The subset of $possible_metrics that is present in the raw profile data. 00373 */ 00374 $metrics = null; 00375 00383 function sort_cbk($a, $b) { 00384 global $sort_col; 00385 global $diff_mode; 00386 00387 if ($sort_col == "fn") { 00388 00389 // case insensitive ascending sort for function names 00390 $left = strtoupper($a["fn"]); 00391 $right = strtoupper($b["fn"]); 00392 00393 if ($left == $right) 00394 return 0; 00395 return ($left < $right) ? -1 : 1; 00396 00397 } else { 00398 00399 // descending sort for all others 00400 $left = $a[$sort_col]; 00401 $right = $b[$sort_col]; 00402 00403 // if diff mode, sort by absolute value of regression/improvement 00404 if ($diff_mode) { 00405 $left = abs($left); 00406 $right = abs($right); 00407 } 00408 00409 if ($left == $right) 00410 return 0; 00411 return ($left > $right) ? -1 : 1; 00412 } 00413 } 00414 00422 function stat_description($stat) { 00423 global $descriptions; 00424 global $diff_descriptions; 00425 global $diff_mode; 00426 00427 if ($diff_mode) { 00428 return $diff_descriptions[$stat]; 00429 } else { 00430 return $descriptions[$stat]; 00431 } 00432 } 00433 00434 00441 function profiler_report ($url_params, 00442 $rep_symbol, 00443 $sort, 00444 $run1, 00445 $run1_desc, 00446 $run1_data, 00447 $run2 = 0, 00448 $run2_desc = "", 00449 $run2_data = array()) { 00450 global $totals; 00451 global $totals_1; 00452 global $totals_2; 00453 global $stats; 00454 global $pc_stats; 00455 global $diff_mode; 00456 global $base_path; 00457 00458 // if we are reporting on a specific function, we can trim down 00459 // the report(s) to just stuff that is relevant to this function. 00460 // That way compute_flat_info()/compute_diff() etc. do not have 00461 // to needlessly work hard on churning irrelevant data. 00462 if (!empty($rep_symbol)) { 00463 $run1_data = xhprof_trim_run($run1_data, array($rep_symbol)); 00464 if ($diff_mode) { 00465 $run2_data = xhprof_trim_run($run2_data, array($rep_symbol)); 00466 } 00467 } 00468 00469 if ($diff_mode) { 00470 $run_delta = xhprof_compute_diff($run1_data, $run2_data); 00471 $symbol_tab = xhprof_compute_flat_info($run_delta, $totals); 00472 $symbol_tab1 = xhprof_compute_flat_info($run1_data, $totals_1); 00473 $symbol_tab2 = xhprof_compute_flat_info($run2_data, $totals_2); 00474 } else { 00475 $symbol_tab = xhprof_compute_flat_info($run1_data, $totals); 00476 } 00477 00478 $run1_txt = sprintf("<b>Run #%s:</b> %s", 00479 $run1, $run1_desc); 00480 00481 $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params, 00482 'symbol'), 00483 'all'); 00484 00485 $top_link_query_string = "$base_path/?" . http_build_query($base_url_params); 00486 00487 if ($diff_mode) { 00488 $diff_text = "Diff"; 00489 $base_url_params = xhprof_array_unset($base_url_params, 'run1'); 00490 $base_url_params = xhprof_array_unset($base_url_params, 'run2'); 00491 $run1_link = xhprof_render_link('View Run #' . $run1, 00492 "$base_path/?" . 00493 http_build_query(xhprof_array_set($base_url_params, 00494 'run', 00495 $run1))); 00496 $run2_txt = sprintf("<b>Run #%s:</b> %s", 00497 $run2, $run2_desc); 00498 00499 $run2_link = xhprof_render_link('View Run #' . $run2, 00500 "$base_path/?" . 00501 http_build_query(xhprof_array_set($base_url_params, 00502 'run', 00503 $run2))); 00504 } else { 00505 $diff_text = "Run"; 00506 } 00507 00508 // set up the action links for operations that can be done on this report 00509 $links = array(); 00510 $links [] = xhprof_render_link("View Top Level $diff_text Report", 00511 $top_link_query_string); 00512 00513 if ($diff_mode) { 00514 $inverted_params = $url_params; 00515 $inverted_params['run1'] = $url_params['run2']; 00516 $inverted_params['run2'] = $url_params['run1']; 00517 00518 // view the different runs or invert the current diff 00519 $links [] = $run1_link; 00520 $links [] = $run2_link; 00521 $links [] = xhprof_render_link('Invert ' . $diff_text . ' Report', 00522 "$base_path/?". 00523 http_build_query($inverted_params)); 00524 } 00525 00526 // lookup function typeahead form 00527 $links [] = '<input class="function_typeahead" ' . 00528 ' type="input" size="40" maxlength="100" />'; 00529 00530 echo xhprof_render_actions($links); 00531 00532 00533 echo 00534 '<dl class=phprof_report_info>' . 00535 ' <dt>' . $diff_text . ' Report</dt>' . 00536 ' <dd>' . ($diff_mode ? 00537 $run1_txt . '<br><b>vs.</b><br>' . $run2_txt : 00538 $run1_txt) . 00539 ' </dd>' . 00540 ' <dt>Tip</dt>' . 00541 ' <dd>Click a function name below to drill down.</dd>' . 00542 '</dl>' . 00543 '<div style="clear: both; margin: 3em 0em;"></div>'; 00544 00545 // data tables 00546 if (!empty($rep_symbol)) { 00547 if (!isset($symbol_tab[$rep_symbol])) { 00548 echo "<hr>Symbol <b>$rep_symbol</b> not found in XHProf run</b><hr>"; 00549 return; 00550 } 00551 00552 /* single function report with parent/child information */ 00553 if ($diff_mode) { 00554 $info1 = isset($symbol_tab1[$rep_symbol]) ? 00555 $symbol_tab1[$rep_symbol] : null; 00556 $info2 = isset($symbol_tab2[$rep_symbol]) ? 00557 $symbol_tab2[$rep_symbol] : null; 00558 symbol_report($url_params, $run_delta, $symbol_tab[$rep_symbol], 00559 $sort, $rep_symbol, 00560 $run1, $info1, 00561 $run2, $info2); 00562 } else { 00563 symbol_report($url_params, $run1_data, $symbol_tab[$rep_symbol], 00564 $sort, $rep_symbol, $run1); 00565 } 00566 } else { 00567 /* flat top-level report of all functions */ 00568 full_report($url_params, $symbol_tab, $sort, $run1, $run2); 00569 } 00570 } 00571 00576 function pct($a, $b) { 00577 if ($b == 0) { 00578 return "N/A"; 00579 } else { 00580 $res = (round(($a * 1000 / $b)) / 10); 00581 return $res; 00582 } 00583 } 00584 00592 function get_print_class($num, $bold) { 00593 global $vbar; 00594 global $vbbar; 00595 global $vrbar; 00596 global $vgbar; 00597 global $diff_mode; 00598 00599 if ($bold) { 00600 if ($diff_mode) { 00601 if ($num <= 0) { 00602 $class = $vgbar; // green (improvement) 00603 } else { 00604 $class = $vrbar; // red (regression) 00605 } 00606 } else { 00607 $class = $vbbar; // blue 00608 } 00609 } 00610 else { 00611 $class = $vbar; // default (black) 00612 } 00613 00614 return $class; 00615 } 00616 00620 function print_td_num($num, $fmt_func, $bold=false, $attributes=null) { 00621 00622 $class = get_print_class($num, $bold); 00623 00624 if (!empty($fmt_func)) { 00625 $num = call_user_func($fmt_func, $num); 00626 } 00627 00628 print("<td $attributes $class>$num</td>\n"); 00629 } 00630 00634 function print_td_pct($numer, $denom, $bold=false, $attributes=null) { 00635 global $vbar; 00636 global $vbbar; 00637 global $diff_mode; 00638 00639 $class = get_print_class($numer, $bold); 00640 00641 if ($denom == 0) { 00642 $pct = "N/A%"; 00643 } else { 00644 $pct = xhprof_percent_format($numer / abs($denom)); 00645 } 00646 00647 print("<td $attributes $class>$pct</td>\n"); 00648 } 00649 00655 function print_function_info($url_params, $info, $sort, $run1, $run2) { 00656 static $odd_even = 0; 00657 00658 global $totals; 00659 global $sort_col; 00660 global $metrics; 00661 global $format_cbk; 00662 global $display_calls; 00663 global $base_path; 00664 00665 // Toggle $odd_or_even 00666 $odd_even = 1 - $odd_even; 00667 00668 if ($odd_even) { 00669 print("<tr>"); 00670 } 00671 else { 00672 print('<tr bgcolor="#e5e5e5">'); 00673 } 00674 00675 $href = "$base_path/?" . 00676 http_build_query(xhprof_array_set($url_params, 00677 'symbol', $info["fn"])); 00678 00679 print('<td>'); 00680 print(xhprof_render_link($info["fn"], $href)); 00681 print_source_link($info); 00682 print("</td>\n"); 00683 00684 if ($display_calls) { 00685 // Call Count.. 00686 print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct")); 00687 print_td_pct($info["ct"], $totals["ct"], ($sort_col == "ct")); 00688 } 00689 00690 // Other metrics.. 00691 foreach ($metrics as $metric) { 00692 // Inclusive metric 00693 print_td_num($info[$metric], $format_cbk[$metric], 00694 ($sort_col == $metric)); 00695 print_td_pct($info[$metric], $totals[$metric], 00696 ($sort_col == $metric)); 00697 00698 // Exclusive Metric 00699 print_td_num($info["excl_" . $metric], 00700 $format_cbk["excl_" . $metric], 00701 ($sort_col == "excl_" . $metric)); 00702 print_td_pct($info["excl_" . $metric], 00703 $totals[$metric], 00704 ($sort_col == "excl_" . $metric)); 00705 } 00706 00707 print("</tr>\n"); 00708 } 00709 00715 function print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit) { 00716 00717 global $stats; 00718 global $sortable_columns; 00719 global $vwbar; 00720 global $base_path; 00721 00722 $size = count($flat_data); 00723 if (!$limit) { // no limit 00724 $limit = $size; 00725 $display_link = ""; 00726 } else { 00727 $display_link = xhprof_render_link(" [ <b class=bubble>display all </b>]", 00728 "$base_path/?" . 00729 http_build_query(xhprof_array_set($url_params, 00730 'all', 1))); 00731 } 00732 00733 print("<h3 align=center>$title $display_link</h3><br>"); 00734 00735 print('<table border=1 cellpadding=2 cellspacing=1 width="90%" ' 00736 .'rules=rows bordercolor="#bdc7d8" align=center>'); 00737 print('<tr bgcolor="#bdc7d8" align=right>'); 00738 00739 foreach ($stats as $stat) { 00740 $desc = stat_description($stat); 00741 if (array_key_exists($stat, $sortable_columns)) { 00742 $href = "$base_path/?" 00743 . http_build_query(xhprof_array_set($url_params, 'sort', $stat)); 00744 $header = xhprof_render_link($desc, $href); 00745 } else { 00746 $header = $desc; 00747 } 00748 00749 if ($stat == "fn") 00750 print("<th align=left><nobr>$header</th>"); 00751 else print("<th " . $vwbar . "><nobr>$header</th>"); 00752 } 00753 print("</tr>\n"); 00754 00755 if ($limit >= 0) { 00756 $limit = min($size, $limit); 00757 for ($i = 0; $i < $limit; $i++) { 00758 print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2); 00759 } 00760 } else { 00761 // if $limit is negative, print abs($limit) items starting from the end 00762 $limit = min($size, abs($limit)); 00763 for ($i = 0; $i < $limit; $i++) { 00764 print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2); 00765 } 00766 } 00767 print("</table>"); 00768 00769 // let's print the display all link at the bottom as well... 00770 if ($display_link) { 00771 echo '<div style="text-align: left; padding: 2em">' . $display_link . '</div>'; 00772 } 00773 00774 } 00775 00781 function full_report($url_params, $symbol_tab, $sort, $run1, $run2) { 00782 global $vwbar; 00783 global $vbar; 00784 global $totals; 00785 global $totals_1; 00786 global $totals_2; 00787 global $metrics; 00788 global $diff_mode; 00789 global $descriptions; 00790 global $sort_col; 00791 global $format_cbk; 00792 global $display_calls; 00793 global $base_path; 00794 00795 $possible_metrics = xhprof_get_possible_metrics(); 00796 00797 if ($diff_mode) { 00798 00799 $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params, 00800 'run1'), 00801 'run2'); 00802 $href1 = "$base_path/?" . 00803 http_build_query(xhprof_array_set($base_url_params, 00804 'run', $run1)); 00805 $href2 = "$base_path/?" . 00806 http_build_query(xhprof_array_set($base_url_params, 00807 'run', $run2)); 00808 00809 print("<h3><center>Overall Diff Summary</center></h3>"); 00810 print('<table border=1 cellpadding=2 cellspacing=1 width="30%" ' 00811 .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n"); 00812 print('<tr bgcolor="#bdc7d8" align=right>'); 00813 print("<th></th>"); 00814 print("<th $vwbar>" . xhprof_render_link("Run #$run1", $href1) . "</th>"); 00815 print("<th $vwbar>" . xhprof_render_link("Run #$run2", $href2) . "</th>"); 00816 print("<th $vwbar>Diff</th>"); 00817 print("<th $vwbar>Diff%</th>"); 00818 print('</tr>'); 00819 00820 if ($display_calls) { 00821 print('<tr>'); 00822 print("<td>Number of Function Calls</td>"); 00823 print_td_num($totals_1["ct"], $format_cbk["ct"]); 00824 print_td_num($totals_2["ct"], $format_cbk["ct"]); 00825 print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true); 00826 print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true); 00827 print('</tr>'); 00828 } 00829 00830 foreach ($metrics as $metric) { 00831 $m = $metric; 00832 print('<tr>'); 00833 print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>"); 00834 print_td_num($totals_1[$m], $format_cbk[$m]); 00835 print_td_num($totals_2[$m], $format_cbk[$m]); 00836 print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true); 00837 print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true); 00838 print('<tr>'); 00839 } 00840 print('</table>'); 00841 00842 $callgraph_report_title = '[View Regressions/Improvements using Callgraph Diff]'; 00843 00844 } else { 00845 print("<p><center>\n"); 00846 00847 print('<table cellpadding=2 cellspacing=1 width="30%" ' 00848 .'bgcolor="#bdc7d8" align=center>' . "\n"); 00849 echo "<tr>"; 00850 echo "<th style='text-align:right'>Overall Summary</th>"; 00851 echo "<th></th>"; 00852 echo "</tr>"; 00853 00854 foreach ($metrics as $metric) { 00855 echo "<tr>"; 00856 echo "<td style='text-align:right; font-weight:bold'>Total " 00857 . str_replace("<br>", " ", stat_description($metric)) . ":</td>"; 00858 echo "<td>" . number_format($totals[$metric]) . " " 00859 . $possible_metrics[$metric][1] . "</td>"; 00860 echo "</tr>"; 00861 } 00862 00863 if ($display_calls) { 00864 echo "<tr>"; 00865 echo "<td style='text-align:right; font-weight:bold'>Number of Function Calls:</td>"; 00866 echo "<td>" . number_format($totals['ct']) . "</td>"; 00867 echo "</tr>"; 00868 } 00869 00870 echo "</table>"; 00871 print("</center></p>\n"); 00872 00873 $callgraph_report_title = '[View Full Callgraph]'; 00874 } 00875 00876 print("<center><br><h3>" . 00877 xhprof_render_link($callgraph_report_title, 00878 "$base_path/callgraph.php" . "?" . http_build_query($url_params)) 00879 . "</h3></center>"); 00880 00881 00882 $flat_data = array(); 00883 foreach ($symbol_tab as $symbol => $info) { 00884 $tmp = $info; 00885 $tmp["fn"] = $symbol; 00886 $flat_data[] = $tmp; 00887 } 00888 usort($flat_data, 'sort_cbk'); 00889 00890 print("<br>"); 00891 00892 if (!empty($url_params['all'])) { 00893 $all = true; 00894 $limit = 0; // display all rows 00895 } else { 00896 $all = false; 00897 $limit = 100; // display only limited number of rows 00898 } 00899 00900 $desc = str_replace("<br>", " ", $descriptions[$sort_col]); 00901 00902 if ($diff_mode) { 00903 if ($all) { 00904 $title = "Total Diff Report: ' 00905 .'Sorted by absolute value of regression/improvement in $desc"; 00906 } else { 00907 $title = "Top 100 <i style='color:red'>Regressions</i>/" 00908 . "<i style='color:green'>Improvements</i>: " 00909 . "Sorted by $desc Diff"; 00910 } 00911 } else { 00912 if ($all) { 00913 $title = "Sorted by $desc"; 00914 } else { 00915 $title = "Displaying top $limit functions: Sorted by $desc"; 00916 } 00917 } 00918 print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit); 00919 } 00920 00921 00925 function get_tooltip_attributes($type, $metric) { 00926 return "type='$type' metric='$metric'"; 00927 } 00928 00935 function pc_info($info, $base_ct, $base_info, $parent) { 00936 global $sort_col; 00937 global $metrics; 00938 global $format_cbk; 00939 global $display_calls; 00940 00941 if ($parent) 00942 $type = "Parent"; 00943 else $type = "Child"; 00944 00945 if ($display_calls) { 00946 $mouseoverct = get_tooltip_attributes($type, "ct"); 00947 /* call count */ 00948 print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"), $mouseoverct); 00949 print_td_pct($info["ct"], $base_ct, ($sort_col == "ct"), $mouseoverct); 00950 } 00951 00952 /* Inclusive metric values */ 00953 foreach ($metrics as $metric) { 00954 print_td_num($info[$metric], $format_cbk[$metric], 00955 ($sort_col == $metric), 00956 get_tooltip_attributes($type, $metric)); 00957 print_td_pct($info[$metric], $base_info[$metric], ($sort_col == $metric), 00958 get_tooltip_attributes($type, $metric)); 00959 } 00960 } 00961 00962 function print_pc_array($url_params, $results, $base_ct, $base_info, $parent, 00963 $run1, $run2) { 00964 global $base_path; 00965 00966 // Construct section title 00967 if ($parent) { 00968 $title = 'Parent function'; 00969 } 00970 else { 00971 $title = 'Child function'; 00972 } 00973 if (count($results) > 1) { 00974 $title .= 's'; 00975 } 00976 00977 print("<tr bgcolor='#e0e0ff'><td>"); 00978 print("<b><i><center>" . $title . "</center></i></b>"); 00979 print("</td></tr>"); 00980 00981 $odd_even = 0; 00982 foreach ($results as $info) { 00983 $href = "$base_path/?" . 00984 http_build_query(xhprof_array_set($url_params, 00985 'symbol', $info["fn"])); 00986 00987 $odd_even = 1 - $odd_even; 00988 00989 if ($odd_even) { 00990 print('<tr>'); 00991 } 00992 else { 00993 print('<tr bgcolor="#e5e5e5">'); 00994 } 00995 00996 print("<td>" . xhprof_render_link($info["fn"], $href)); 00997 print_source_link($info); 00998 print("</td>"); 00999 pc_info($info, $base_ct, $base_info, $parent); 01000 print("</tr>"); 01001 } 01002 } 01003 01004 function print_source_link($info) { 01005 if (strncmp($info['fn'], 'run_init', 8) && $info['fn'] !== 'main()') { 01006 if (defined('XHPROF_SYMBOL_LOOKUP_URL')) { 01007 $link = xhprof_render_link( 01008 'source', 01009 XHPROF_SYMBOL_LOOKUP_URL . '?symbol='.rawurlencode($info["fn"])); 01010 print(' ('.$link.')'); 01011 } 01012 } 01013 } 01014 01015 01016 function print_symbol_summary($symbol_info, $stat, $base) { 01017 01018 $val = $symbol_info[$stat]; 01019 $desc = str_replace("<br>", " ", stat_description($stat)); 01020 01021 print("$desc: </td>"); 01022 print(number_format($val)); 01023 print(" (" . pct($val, $base) . "% of overall)"); 01024 if (substr($stat, 0, 4) == "excl") { 01025 $func_base = $symbol_info[str_replace("excl_", "", $stat)]; 01026 print(" (" . pct($val, $func_base) . "% of this function)"); 01027 } 01028 print("<br>"); 01029 } 01030 01036 function symbol_report($url_params, 01037 $run_data, $symbol_info, $sort, $rep_symbol, 01038 $run1, 01039 $symbol_info1 = null, 01040 $run2 = 0, 01041 $symbol_info2 = null) { 01042 global $vwbar; 01043 global $vbar; 01044 global $totals; 01045 global $pc_stats; 01046 global $sortable_columns; 01047 global $metrics; 01048 global $diff_mode; 01049 global $descriptions; 01050 global $format_cbk; 01051 global $sort_col; 01052 global $display_calls; 01053 global $base_path; 01054 01055 $possible_metrics = xhprof_get_possible_metrics(); 01056 01057 if ($diff_mode) { 01058 $diff_text = "<b>Diff</b>"; 01059 $regr_impr = "<i style='color:red'>Regression</i>/<i style='color:green'>Improvement</i>"; 01060 } else { 01061 $diff_text = ""; 01062 $regr_impr = ""; 01063 } 01064 01065 if ($diff_mode) { 01066 01067 $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params, 01068 'run1'), 01069 'run2'); 01070 $href1 = "$base_path?" 01071 . http_build_query(xhprof_array_set($base_url_params, 'run', $run1)); 01072 $href2 = "$base_path?" 01073 . http_build_query(xhprof_array_set($base_url_params, 'run', $run2)); 01074 01075 print("<h3 align=center>$regr_impr summary for $rep_symbol<br><br></h3>"); 01076 print('<table border=1 cellpadding=2 cellspacing=1 width="30%" ' 01077 .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n"); 01078 print('<tr bgcolor="#bdc7d8" align=right>'); 01079 print("<th align=left>$rep_symbol</th>"); 01080 print("<th $vwbar><a href=" . $href1 . ">Run #$run1</a></th>"); 01081 print("<th $vwbar><a href=" . $href2 . ">Run #$run2</a></th>"); 01082 print("<th $vwbar>Diff</th>"); 01083 print("<th $vwbar>Diff%</th>"); 01084 print('</tr>'); 01085 print('<tr>'); 01086 01087 if ($display_calls) { 01088 print("<td>Number of Function Calls</td>"); 01089 print_td_num($symbol_info1["ct"], $format_cbk["ct"]); 01090 print_td_num($symbol_info2["ct"], $format_cbk["ct"]); 01091 print_td_num($symbol_info2["ct"] - $symbol_info1["ct"], 01092 $format_cbk["ct"], true); 01093 print_td_pct($symbol_info2["ct"] - $symbol_info1["ct"], 01094 $symbol_info1["ct"], true); 01095 print('</tr>'); 01096 } 01097 01098 01099 foreach ($metrics as $metric) { 01100 $m = $metric; 01101 01102 // Inclusive stat for metric 01103 print('<tr>'); 01104 print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>"); 01105 print_td_num($symbol_info1[$m], $format_cbk[$m]); 01106 print_td_num($symbol_info2[$m], $format_cbk[$m]); 01107 print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true); 01108 print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true); 01109 print('</tr>'); 01110 01111 // AVG (per call) Inclusive stat for metric 01112 print('<tr>'); 01113 print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . " per call </td>"); 01114 $avg_info1 = 'N/A'; 01115 $avg_info2 = 'N/A'; 01116 if ($symbol_info1['ct'] > 0) { 01117 $avg_info1 = ($symbol_info1[$m] / $symbol_info1['ct']); 01118 } 01119 if ($symbol_info2['ct'] > 0) { 01120 $avg_info2 = ($symbol_info2[$m] / $symbol_info2['ct']); 01121 } 01122 print_td_num($avg_info1, $format_cbk[$m]); 01123 print_td_num($avg_info2, $format_cbk[$m]); 01124 print_td_num($avg_info2 - $avg_info1, $format_cbk[$m], true); 01125 print_td_pct($avg_info2 - $avg_info1, $avg_info1, true); 01126 print('</tr>'); 01127 01128 // Exclusive stat for metric 01129 $m = "excl_" . $metric; 01130 print('<tr style="border-bottom: 1px solid black;">'); 01131 print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>"); 01132 print_td_num($symbol_info1[$m], $format_cbk[$m]); 01133 print_td_num($symbol_info2[$m], $format_cbk[$m]); 01134 print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true); 01135 print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true); 01136 print('</tr>'); 01137 } 01138 01139 print('</table>'); 01140 } 01141 01142 print("<br><h4><center>"); 01143 print("Parent/Child $regr_impr report for <b>$rep_symbol</b>"); 01144 01145 $callgraph_href = "$base_path/callgraph.php?" 01146 . http_build_query(xhprof_array_set($url_params, 'func', $rep_symbol)); 01147 01148 print(" <a href='$callgraph_href'>[View Callgraph $diff_text]</a><br>"); 01149 01150 print("</center></h4><br>"); 01151 01152 print('<table border=1 cellpadding=2 cellspacing=1 width="90%" ' 01153 .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n"); 01154 print('<tr bgcolor="#bdc7d8" align=right>'); 01155 01156 foreach ($pc_stats as $stat) { 01157 $desc = stat_description($stat); 01158 if (array_key_exists($stat, $sortable_columns)) { 01159 01160 $href = "$base_path/?" . 01161 http_build_query(xhprof_array_set($url_params, 01162 'sort', $stat)); 01163 $header = xhprof_render_link($desc, $href); 01164 } else { 01165 $header = $desc; 01166 } 01167 01168 if ($stat == "fn") 01169 print("<th align=left><nobr>$header</th>"); 01170 else print("<th " . $vwbar . "><nobr>$header</th>"); 01171 } 01172 print("</tr>"); 01173 01174 print("<tr bgcolor='#e0e0ff'><td>"); 01175 print("<b><i><center>Current Function</center></i></b>"); 01176 print("</td></tr>"); 01177 01178 print("<tr>"); 01179 // make this a self-reference to facilitate copy-pasting snippets to e-mails 01180 print("<td><a href=''>$rep_symbol</a>"); 01181 print_source_link(array('fn' => $rep_symbol)); 01182 print("</td>"); 01183 01184 if ($display_calls) { 01185 // Call Count 01186 print_td_num($symbol_info["ct"], $format_cbk["ct"]); 01187 print_td_pct($symbol_info["ct"], $totals["ct"]); 01188 } 01189 01190 // Inclusive Metrics for current function 01191 foreach ($metrics as $metric) { 01192 print_td_num($symbol_info[$metric], $format_cbk[$metric], ($sort_col == $metric)); 01193 print_td_pct($symbol_info[$metric], $totals[$metric], ($sort_col == $metric)); 01194 } 01195 print("</tr>"); 01196 01197 print("<tr bgcolor='#ffffff'>"); 01198 print("<td style='text-align:right;color:blue'>" 01199 ."Exclusive Metrics $diff_text for Current Function</td>"); 01200 01201 if ($display_calls) { 01202 // Call Count 01203 print("<td $vbar></td>"); 01204 print("<td $vbar></td>"); 01205 } 01206 01207 // Exclusive Metrics for current function 01208 foreach ($metrics as $metric) { 01209 print_td_num($symbol_info["excl_" . $metric], $format_cbk["excl_" . $metric], 01210 ($sort_col == $metric), 01211 get_tooltip_attributes("Child", $metric)); 01212 print_td_pct($symbol_info["excl_" . $metric], $symbol_info[$metric], 01213 ($sort_col == $metric), 01214 get_tooltip_attributes("Child", $metric)); 01215 } 01216 print("</tr>"); 01217 01218 // list of callers/parent functions 01219 $results = array(); 01220 if ($display_calls) { 01221 $base_ct = $symbol_info["ct"]; 01222 } else { 01223 $base_ct = 0; 01224 } 01225 foreach ($metrics as $metric) { 01226 $base_info[$metric] = $symbol_info[$metric]; 01227 } 01228 foreach ($run_data as $parent_child => $info) { 01229 list($parent, $child) = xhprof_parse_parent_child($parent_child); 01230 if (($child == $rep_symbol) && ($parent)) { 01231 $info_tmp = $info; 01232 $info_tmp["fn"] = $parent; 01233 $results[] = $info_tmp; 01234 } 01235 } 01236 usort($results, 'sort_cbk'); 01237 01238 if (count($results) > 0) { 01239 print_pc_array($url_params, $results, $base_ct, $base_info, true, 01240 $run1, $run2); 01241 } 01242 01243 // list of callees/child functions 01244 $results = array(); 01245 $base_ct = 0; 01246 foreach ($run_data as $parent_child => $info) { 01247 list($parent, $child) = xhprof_parse_parent_child($parent_child); 01248 if ($parent == $rep_symbol) { 01249 $info_tmp = $info; 01250 $info_tmp["fn"] = $child; 01251 $results[] = $info_tmp; 01252 if ($display_calls) { 01253 $base_ct += $info["ct"]; 01254 } 01255 } 01256 } 01257 usort($results, 'sort_cbk'); 01258 01259 if (count($results)) { 01260 print_pc_array($url_params, $results, $base_ct, $base_info, false, 01261 $run1, $run2); 01262 } 01263 01264 print("</table>"); 01265 01266 // These will be used for pop-up tips/help. 01267 // Related javascript code is in: xhprof_report.js 01268 print("\n"); 01269 print('<script language="javascript">' . "\n"); 01270 print("var func_name = '\"" . $rep_symbol . "\"';\n"); 01271 print("var total_child_ct = " . $base_ct . ";\n"); 01272 if ($display_calls) { 01273 print("var func_ct = " . $symbol_info["ct"] . ";\n"); 01274 } 01275 print("var func_metrics = new Array();\n"); 01276 print("var metrics_col = new Array();\n"); 01277 print("var metrics_desc = new Array();\n"); 01278 if ($diff_mode) { 01279 print("var diff_mode = true;\n"); 01280 } else { 01281 print("var diff_mode = false;\n"); 01282 } 01283 $column_index = 3; // First three columns are Func Name, Calls, Calls% 01284 foreach ($metrics as $metric) { 01285 print("func_metrics[\"" . $metric . "\"] = " . round($symbol_info[$metric]) . ";\n"); 01286 print("metrics_col[\"". $metric . "\"] = " . $column_index . ";\n"); 01287 print("metrics_desc[\"". $metric . "\"] = \"" . $possible_metrics[$metric][2] . "\";\n"); 01288 01289 // each metric has two columns.. 01290 $column_index += 2; 01291 } 01292 print('</script>'); 01293 print("\n"); 01294 01295 } 01296 01302 function profiler_single_run_report ($url_params, 01303 $xhprof_data, 01304 $run_desc, 01305 $rep_symbol, 01306 $sort, 01307 $run) { 01308 01309 init_metrics($xhprof_data, $rep_symbol, $sort, false); 01310 01311 profiler_report($url_params, $rep_symbol, $sort, $run, $run_desc, 01312 $xhprof_data); 01313 } 01314 01315 01316 01322 function profiler_diff_report($url_params, 01323 $xhprof_data1, 01324 $run1_desc, 01325 $xhprof_data2, 01326 $run2_desc, 01327 $rep_symbol, 01328 $sort, 01329 $run1, 01330 $run2) { 01331 01332 01333 // Initialize what metrics we'll display based on data in Run2 01334 init_metrics($xhprof_data2, $rep_symbol, $sort, true); 01335 01336 profiler_report($url_params, 01337 $rep_symbol, 01338 $sort, 01339 $run1, 01340 $run1_desc, 01341 $xhprof_data1, 01342 $run2, 01343 $run2_desc, 01344 $xhprof_data2); 01345 } 01346 01347 01382 function displayXHProfReport($xhprof_runs_impl, $url_params, $source, 01383 $run, $wts, $symbol, $sort, $run1, $run2) { 01384 01385 if ($run) { // specific run to display? 01386 01387 // run may be a single run or a comma separate list of runs 01388 // that'll be aggregated. If "wts" (a comma separated list 01389 // of integral weights is specified), the runs will be 01390 // aggregated in that ratio. 01391 // 01392 $runs_array = explode(",", $run); 01393 01394 if (count($runs_array) == 1) { 01395 $xhprof_data = $xhprof_runs_impl->get_run($runs_array[0], 01396 $source, 01397 $description); 01398 } else { 01399 if (!empty($wts)) { 01400 $wts_array = explode(",", $wts); 01401 } else { 01402 $wts_array = null; 01403 } 01404 $data = xhprof_aggregate_runs($xhprof_runs_impl, 01405 $runs_array, $wts_array, $source, false); 01406 $xhprof_data = $data['raw']; 01407 $description = $data['description']; 01408 } 01409 01410 01411 profiler_single_run_report($url_params, 01412 $xhprof_data, 01413 $description, 01414 $symbol, 01415 $sort, 01416 $run); 01417 01418 } else if ($run1 && $run2) { // diff report for two runs 01419 01420 $xhprof_data1 = $xhprof_runs_impl->get_run($run1, $source, $description1); 01421 $xhprof_data2 = $xhprof_runs_impl->get_run($run2, $source, $description2); 01422 01423 profiler_diff_report($url_params, 01424 $xhprof_data1, 01425 $description1, 01426 $xhprof_data2, 01427 $description2, 01428 $symbol, 01429 $sort, 01430 $run1, 01431 $run2); 01432 01433 } else { 01434 echo "No XHProf runs specified in the URL."; 01435 if (method_exists($xhprof_runs_impl, 'list_runs')) { 01436 $xhprof_runs_impl->list_runs(); 01437 } 01438 } 01439 }