123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440 |
- <?php
- // Copyright (c) 2009 Facebook
- //
- // Licensed under the Apache License, Version 2.0 (the "License");
- // you may not use this file except in compliance with the License.
- // You may obtain a copy of the License at
- //
- // http://www.apache.org/licenses/LICENSE-2.0
- //
- // Unless required by applicable law or agreed to in writing, software
- // distributed under the License is distributed on an "AS IS" BASIS,
- // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- // See the License for the specific language governing permissions and
- // limitations under the License.
- //
- //
- // XHProf: A Hierarchical Profiler for PHP
- //
- // XHProf has two components:
- //
- // * This module is the UI/reporting component, used
- // for viewing results of XHProf runs from a browser.
- //
- // * Data collection component: This is implemented
- // as a PHP extension (XHProf).
- //
- // @author Kannan Muthukkaruppan
- //
- if (!isset($GLOBALS['XHPROF_LIB_ROOT'])) {
- // by default, the parent directory is XHPROF lib root
- $GLOBALS['XHPROF_LIB_ROOT'] = realpath(__DIR__.'/..');
- }
- require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_lib.php';
- require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/callgraph_utils.php';
- require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_runs.php';
- /**
- * Our coding convention disallows relative paths in hrefs.
- * Get the base URL path from the SCRIPT_NAME.
- */
- $base_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
- /**
- * Generate references to required stylesheets & javascript.
- *
- * If the calling script (such as index.php) resides in
- * a different location that than 'xhprof_html' directory the
- * caller must provide the URL path to 'xhprof_html' directory
- * so that the correct location of the style sheets/javascript
- * can be specified in the generated HTML.
- *
- */
- function xhprof_include_js_css($ui_dir_url_path = null) {
- if (empty($ui_dir_url_path)) {
- $ui_dir_url_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
- }
- // style sheets
- echo "<link href='$ui_dir_url_path/css/xhprof.css' rel='stylesheet' ".
- " type='text/css' />";
- echo "<link href='$ui_dir_url_path/jquery/jquery.tooltip.css' ".
- " rel='stylesheet' type='text/css' />";
- echo "<link href='$ui_dir_url_path/jquery/jquery.autocomplete.css' ".
- " rel='stylesheet' type='text/css' />";
- // javascript
- echo "<script src='$ui_dir_url_path/jquery/jquery-1.2.6.js'>".
- "</script>";
- echo "<script src='$ui_dir_url_path/jquery/jquery.tooltip.js'>".
- "</script>";
- echo "<script src='$ui_dir_url_path/jquery/jquery.autocomplete.js'>"
- ."</script>";
- echo "<script src='$ui_dir_url_path/js/xhprof_report.js'></script>";
- }
- /*
- * Formats call counts for XHProf reports.
- *
- * Description:
- * Call counts in single-run reports are integer values.
- * However, call counts for aggregated reports can be
- * fractional. This function will print integer values
- * without decimal point, but with commas etc.
- *
- * 4000 ==> 4,000
- *
- * It'll round fractional values to decimal precision of 3
- * 4000.1212 ==> 4,000.121
- * 4000.0001 ==> 4,000
- *
- */
- function xhprof_count_format($num) {
- $num = round($num, 3);
- if (round($num) == $num) {
- return number_format($num);
- } else {
- return number_format($num, 3);
- }
- }
- function xhprof_percent_format($s, $precision = 1) {
- return sprintf('%.'.$precision.'f%%', 100 * $s);
- }
- /**
- * Implodes the text for a bunch of actions (such as links, forms,
- * into a HTML list and returns the text.
- */
- function xhprof_render_actions($actions) {
- $out = array();
- if (count($actions)) {
- $out[] = '<ul class="xhprof_actions">';
- foreach ($actions as $action) {
- $out[] = '<li>'.$action.'</li>';
- }
- $out[] = '</ul>';
- }
- return implode('', $out);
- }
- /**
- * @param html-str $content the text/image/innerhtml/whatever for the link
- * @param raw-str $href
- * @param raw-str $class
- * @param raw-str $id
- * @param raw-str $title
- * @param raw-str $target
- * @param raw-str $onclick
- * @param raw-str $style
- * @param raw-str $access
- * @param raw-str $onmouseover
- * @param raw-str $onmouseout
- * @param raw-str $onmousedown
- * @param raw-str $dir
- * @param raw-str $rel
- */
- function xhprof_render_link($content, $href, $class='', $id='', $title='',
- $target='',
- $onclick='', $style='', $access='', $onmouseover='',
- $onmouseout='', $onmousedown='') {
- if (!$content) {
- return '';
- }
- if ($href) {
- $link = '<a href="' . ($href) . '"';
- } else {
- $link = '<span';
- }
- if ($class) {
- $link .= ' class="' . ($class) . '"';
- }
- if ($id) {
- $link .= ' id="' . ($id) . '"';
- }
- if ($title) {
- $link .= ' title="' . ($title) . '"';
- }
- if ($target) {
- $link .= ' target="' . ($target) . '"';
- }
- if ($onclick && $href) {
- $link .= ' onclick="' . ($onclick) . '"';
- }
- if ($style && $href) {
- $link .= ' style="' . ($style) . '"';
- }
- if ($access && $href) {
- $link .= ' accesskey="' . ($access) . '"';
- }
- if ($onmouseover) {
- $link .= ' onmouseover="' . ($onmouseover) . '"';
- }
- if ($onmouseout) {
- $link .= ' onmouseout="' . ($onmouseout) . '"';
- }
- if ($onmousedown) {
- $link .= ' onmousedown="' . ($onmousedown) . '"';
- }
- $link .= '>';
- $link .= $content;
- if ($href) {
- $link .= '</a>';
- } else {
- $link .= '</span>';
- }
- return $link;
- }
- // default column to sort on -- wall time
- $sort_col = "wt";
- // default is "single run" report
- $diff_mode = false;
- // call count data present?
- $display_calls = true;
- // The following column headers are sortable
- $sortable_columns = array("fn" => 1,
- "ct" => 1,
- "wt" => 1,
- "excl_wt" => 1,
- "ut" => 1,
- "excl_ut" => 1,
- "st" => 1,
- "excl_st" => 1,
- "mu" => 1,
- "excl_mu" => 1,
- "pmu" => 1,
- "excl_pmu" => 1,
- "cpu" => 1,
- "excl_cpu" => 1,
- "samples" => 1,
- "excl_samples" => 1
- );
- // Textual descriptions for column headers in "single run" mode
- $descriptions = array(
- "fn" => "Function Name",
- "ct" => "Calls",
- "Calls%" => "Calls%",
- "wt" => "Incl. Wall Time<br>(microsec)",
- "IWall%" => "IWall%",
- "excl_wt" => "Excl. Wall Time<br>(microsec)",
- "EWall%" => "EWall%",
- "ut" => "Incl. User<br>(microsecs)",
- "IUser%" => "IUser%",
- "excl_ut" => "Excl. User<br>(microsec)",
- "EUser%" => "EUser%",
- "st" => "Incl. Sys <br>(microsec)",
- "ISys%" => "ISys%",
- "excl_st" => "Excl. Sys <br>(microsec)",
- "ESys%" => "ESys%",
- "cpu" => "Incl. CPU<br>(microsecs)",
- "ICpu%" => "ICpu%",
- "excl_cpu" => "Excl. CPU<br>(microsec)",
- "ECpu%" => "ECPU%",
- "mu" => "Incl.<br>MemUse<br>(bytes)",
- "IMUse%" => "IMemUse%",
- "excl_mu" => "Excl.<br>MemUse<br>(bytes)",
- "EMUse%" => "EMemUse%",
- "pmu" => "Incl.<br> PeakMemUse<br>(bytes)",
- "IPMUse%" => "IPeakMemUse%",
- "excl_pmu" => "Excl.<br>PeakMemUse<br>(bytes)",
- "EPMUse%" => "EPeakMemUse%",
- "samples" => "Incl. Samples",
- "ISamples%" => "ISamples%",
- "excl_samples" => "Excl. Samples",
- "ESamples%" => "ESamples%",
- );
- // Formatting Callback Functions...
- $format_cbk = array(
- "fn" => "",
- "ct" => "xhprof_count_format",
- "Calls%" => "xhprof_percent_format",
- "wt" => "number_format",
- "IWall%" => "xhprof_percent_format",
- "excl_wt" => "number_format",
- "EWall%" => "xhprof_percent_format",
- "ut" => "number_format",
- "IUser%" => "xhprof_percent_format",
- "excl_ut" => "number_format",
- "EUser%" => "xhprof_percent_format",
- "st" => "number_format",
- "ISys%" => "xhprof_percent_format",
- "excl_st" => "number_format",
- "ESys%" => "xhprof_percent_format",
- "cpu" => "number_format",
- "ICpu%" => "xhprof_percent_format",
- "excl_cpu" => "number_format",
- "ECpu%" => "xhprof_percent_format",
- "mu" => "number_format",
- "IMUse%" => "xhprof_percent_format",
- "excl_mu" => "number_format",
- "EMUse%" => "xhprof_percent_format",
- "pmu" => "number_format",
- "IPMUse%" => "xhprof_percent_format",
- "excl_pmu" => "number_format",
- "EPMUse%" => "xhprof_percent_format",
- "samples" => "number_format",
- "ISamples%" => "xhprof_percent_format",
- "excl_samples" => "number_format",
- "ESamples%" => "xhprof_percent_format",
- );
- // Textual descriptions for column headers in "diff" mode
- $diff_descriptions = array(
- "fn" => "Function Name",
- "ct" => "Calls Diff",
- "Calls%" => "Calls<br>Diff%",
- "wt" => "Incl. Wall<br>Diff<br>(microsec)",
- "IWall%" => "IWall<br> Diff%",
- "excl_wt" => "Excl. Wall<br>Diff<br>(microsec)",
- "EWall%" => "EWall<br>Diff%",
- "ut" => "Incl. User Diff<br>(microsec)",
- "IUser%" => "IUser<br>Diff%",
- "excl_ut" => "Excl. User<br>Diff<br>(microsec)",
- "EUser%" => "EUser<br>Diff%",
- "cpu" => "Incl. CPU Diff<br>(microsec)",
- "ICpu%" => "ICpu<br>Diff%",
- "excl_cpu" => "Excl. CPU<br>Diff<br>(microsec)",
- "ECpu%" => "ECpu<br>Diff%",
- "st" => "Incl. Sys Diff<br>(microsec)",
- "ISys%" => "ISys<br>Diff%",
- "excl_st" => "Excl. Sys Diff<br>(microsec)",
- "ESys%" => "ESys<br>Diff%",
- "mu" => "Incl.<br>MemUse<br>Diff<br>(bytes)",
- "IMUse%" => "IMemUse<br>Diff%",
- "excl_mu" => "Excl.<br>MemUse<br>Diff<br>(bytes)",
- "EMUse%" => "EMemUse<br>Diff%",
- "pmu" => "Incl.<br> PeakMemUse<br>Diff<br>(bytes)",
- "IPMUse%" => "IPeakMemUse<br>Diff%",
- "excl_pmu" => "Excl.<br>PeakMemUse<br>Diff<br>(bytes)",
- "EPMUse%" => "EPeakMemUse<br>Diff%",
- "samples" => "Incl. Samples Diff",
- "ISamples%" => "ISamples Diff%",
- "excl_samples" => "Excl. Samples Diff",
- "ESamples%" => "ESamples Diff%",
- );
- // columns that'll be displayed in a top-level report
- $stats = array();
- // columns that'll be displayed in a function's parent/child report
- $pc_stats = array();
- // Various total counts
- $totals = 0;
- $totals_1 = 0;
- $totals_2 = 0;
- /*
- * The subset of $possible_metrics that is present in the raw profile data.
- */
- $metrics = null;
- /**
- * Callback comparison operator (passed to usort() for sorting array of
- * tuples) that compares array elements based on the sort column
- * specified in $sort_col (global parameter).
- *
- * @author Kannan
- */
- function sort_cbk($a, $b) {
- global $sort_col;
- global $diff_mode;
- if ($sort_col == "fn") {
- // case insensitive ascending sort for function names
- $left = strtoupper($a["fn"]);
- $right = strtoupper($b["fn"]);
- if ($left == $right)
- return 0;
- return ($left < $right) ? -1 : 1;
- } else {
- // descending sort for all others
- $left = $a[$sort_col];
- $right = $b[$sort_col];
- // if diff mode, sort by absolute value of regression/improvement
- if ($diff_mode) {
- $left = abs($left);
- $right = abs($right);
- }
- if ($left == $right)
- return 0;
- return ($left > $right) ? -1 : 1;
- }
- }
- /**
- * Get the appropriate description for a statistic
- * (depending upon whether we are in diff report mode
- * or single run report mode).
- *
- * @author Kannan
- */
- function stat_description($stat) {
- global $descriptions;
- global $diff_descriptions;
- global $diff_mode;
- if ($diff_mode) {
- return $diff_descriptions[$stat];
- } else {
- return $descriptions[$stat];
- }
- }
- /**
- * Analyze raw data & generate the profiler report
- * (common for both single run mode and diff mode).
- *
- * @author: Kannan
- */
- function profiler_report ($url_params,
- $rep_symbol,
- $sort,
- $run1,
- $run1_desc,
- $run1_data,
- $run2 = 0,
- $run2_desc = "",
- $run2_data = array()) {
- global $totals;
- global $totals_1;
- global $totals_2;
- global $stats;
- global $pc_stats;
- global $diff_mode;
- global $base_path;
- // if we are reporting on a specific function, we can trim down
- // the report(s) to just stuff that is relevant to this function.
- // That way compute_flat_info()/compute_diff() etc. do not have
- // to needlessly work hard on churning irrelevant data.
- if (!empty($rep_symbol)) {
- $run1_data = xhprof_trim_run($run1_data, array($rep_symbol));
- if ($diff_mode) {
- $run2_data = xhprof_trim_run($run2_data, array($rep_symbol));
- }
- }
- if ($diff_mode) {
- $run_delta = xhprof_compute_diff($run1_data, $run2_data);
- $symbol_tab = xhprof_compute_flat_info($run_delta, $totals);
- $symbol_tab1 = xhprof_compute_flat_info($run1_data, $totals_1);
- $symbol_tab2 = xhprof_compute_flat_info($run2_data, $totals_2);
- } else {
- $symbol_tab = xhprof_compute_flat_info($run1_data, $totals);
- }
- $run1_txt = sprintf("<b>Run #%s:</b> %s",
- $run1, $run1_desc);
- $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
- 'symbol'),
- 'all');
- $top_link_query_string = "$base_path/?" . http_build_query($base_url_params);
- if ($diff_mode) {
- $diff_text = "Diff";
- $base_url_params = xhprof_array_unset($base_url_params, 'run1');
- $base_url_params = xhprof_array_unset($base_url_params, 'run2');
- $run1_link = xhprof_render_link('View Run #' . $run1,
- "$base_path/?" .
- http_build_query(xhprof_array_set($base_url_params,
- 'run',
- $run1)));
- $run2_txt = sprintf("<b>Run #%s:</b> %s",
- $run2, $run2_desc);
- $run2_link = xhprof_render_link('View Run #' . $run2,
- "$base_path/?" .
- http_build_query(xhprof_array_set($base_url_params,
- 'run',
- $run2)));
- } else {
- $diff_text = "Run";
- }
- // set up the action links for operations that can be done on this report
- $links = array();
- $links [] = xhprof_render_link("View Top Level $diff_text Report",
- $top_link_query_string);
- if ($diff_mode) {
- $inverted_params = $url_params;
- $inverted_params['run1'] = $url_params['run2'];
- $inverted_params['run2'] = $url_params['run1'];
- // view the different runs or invert the current diff
- $links [] = $run1_link;
- $links [] = $run2_link;
- $links [] = xhprof_render_link('Invert ' . $diff_text . ' Report',
- "$base_path/?".
- http_build_query($inverted_params));
- }
- // lookup function typeahead form
- $links [] = '<input class="function_typeahead" ' .
- ' type="input" size="40" maxlength="100" />';
- echo xhprof_render_actions($links);
- echo
- '<dl class=phprof_report_info>' .
- ' <dt>' . $diff_text . ' Report</dt>' .
- ' <dd>' . ($diff_mode ?
- $run1_txt . '<br><b>vs.</b><br>' . $run2_txt :
- $run1_txt) .
- ' </dd>' .
- ' <dt>Tip</dt>' .
- ' <dd>Click a function name below to drill down.</dd>' .
- '</dl>' .
- '<div style="clear: both; margin: 3em 0em;"></div>';
- // data tables
- if (!empty($rep_symbol)) {
- if (!isset($symbol_tab[$rep_symbol])) {
- echo "<hr>Symbol <b>$rep_symbol</b> not found in XHProf run</b><hr>";
- return;
- }
- /* single function report with parent/child information */
- if ($diff_mode) {
- $info1 = isset($symbol_tab1[$rep_symbol]) ?
- $symbol_tab1[$rep_symbol] : null;
- $info2 = isset($symbol_tab2[$rep_symbol]) ?
- $symbol_tab2[$rep_symbol] : null;
- symbol_report($url_params, $run_delta, $symbol_tab[$rep_symbol],
- $sort, $rep_symbol,
- $run1, $info1,
- $run2, $info2);
- } else {
- symbol_report($url_params, $run1_data, $symbol_tab[$rep_symbol],
- $sort, $rep_symbol, $run1);
- }
- } else {
- /* flat top-level report of all functions */
- full_report($url_params, $symbol_tab, $sort, $run1, $run2);
- }
- }
- /**
- * Computes percentage for a pair of values, and returns it
- * in string format.
- */
- function pct($a, $b) {
- if ($b == 0) {
- return "N/A";
- } else {
- $res = (round(($a * 1000 / $b)) / 10);
- return $res;
- }
- }
- /**
- * Given a number, returns the td class to use for display.
- *
- * For instance, negative numbers in diff reports comparing two runs (run1 & run2)
- * represent improvement from run1 to run2. We use green to display those deltas,
- * and red for regression deltas.
- */
- function get_print_class($num, $bold) {
- global $vbar;
- global $vbbar;
- global $vrbar;
- global $vgbar;
- global $diff_mode;
- if ($bold) {
- if ($diff_mode) {
- if ($num <= 0) {
- $class = $vgbar; // green (improvement)
- } else {
- $class = $vrbar; // red (regression)
- }
- } else {
- $class = $vbbar; // blue
- }
- }
- else {
- $class = $vbar; // default (black)
- }
- return $class;
- }
- /**
- * Prints a <td> element with a numeric value.
- */
- function print_td_num($num, $fmt_func, $bold=false, $attributes=null) {
- $class = get_print_class($num, $bold);
- if (!empty($fmt_func) && is_numeric($num) ) {
- $num = call_user_func($fmt_func, $num);
- }
- print("<td $attributes $class>$num</td>\n");
- }
- /**
- * Prints a <td> element with a pecentage.
- */
- function print_td_pct($numer, $denom, $bold=false, $attributes=null) {
- global $vbar;
- global $vbbar;
- global $diff_mode;
- $class = get_print_class($numer, $bold);
- if ($denom == 0) {
- $pct = "N/A%";
- } else {
- $pct = xhprof_percent_format($numer / abs($denom));
- }
- print("<td $attributes $class>$pct</td>\n");
- }
- /**
- * Print "flat" data corresponding to one function.
- *
- * @author Kannan
- */
- function print_function_info($url_params, $info, $sort, $run1, $run2) {
- static $odd_even = 0;
- global $totals;
- global $sort_col;
- global $metrics;
- global $format_cbk;
- global $display_calls;
- global $base_path;
- // Toggle $odd_or_even
- $odd_even = 1 - $odd_even;
- if ($odd_even) {
- print("<tr>");
- }
- else {
- print('<tr bgcolor="#e5e5e5">');
- }
- $href = "$base_path/?" .
- http_build_query(xhprof_array_set($url_params,
- 'symbol', $info["fn"]));
- print('<td>');
- print(xhprof_render_link($info["fn"], $href));
- print_source_link($info);
- print("</td>\n");
- if ($display_calls) {
- // Call Count..
- print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"));
- print_td_pct($info["ct"], $totals["ct"], ($sort_col == "ct"));
- }
- // Other metrics..
- foreach ($metrics as $metric) {
- // Inclusive metric
- print_td_num($info[$metric], $format_cbk[$metric],
- ($sort_col == $metric));
- print_td_pct($info[$metric], $totals[$metric],
- ($sort_col == $metric));
- // Exclusive Metric
- print_td_num($info["excl_" . $metric],
- $format_cbk["excl_" . $metric],
- ($sort_col == "excl_" . $metric));
- print_td_pct($info["excl_" . $metric],
- $totals[$metric],
- ($sort_col == "excl_" . $metric));
- }
- print("</tr>\n");
- }
- /**
- * Print non-hierarchical (flat-view) of profiler data.
- *
- * @author Kannan
- */
- function print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit) {
- global $stats;
- global $sortable_columns;
- global $vwbar;
- global $base_path;
- $size = count($flat_data);
- if (!$limit) { // no limit
- $limit = $size;
- $display_link = "";
- } else {
- $display_link = xhprof_render_link(" [ <b class=bubble>display all </b>]",
- "$base_path/?" .
- http_build_query(xhprof_array_set($url_params,
- 'all', 1)));
- }
- print("<h3 align=center>$title $display_link</h3><br>");
- print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
- .'rules=rows bordercolor="#bdc7d8" align=center>');
- print('<tr bgcolor="#bdc7d8" align=right>');
- foreach ($stats as $stat) {
- $desc = stat_description($stat);
- if (array_key_exists($stat, $sortable_columns)) {
- $href = "$base_path/?"
- . http_build_query(xhprof_array_set($url_params, 'sort', $stat));
- $header = xhprof_render_link($desc, $href);
- } else {
- $header = $desc;
- }
- if ($stat == "fn")
- print("<th align=left><nobr>$header</th>");
- else print("<th " . $vwbar . "><nobr>$header</th>");
- }
- print("</tr>\n");
- if ($limit >= 0) {
- $limit = min($size, $limit);
- for ($i = 0; $i < $limit; $i++) {
- print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2);
- }
- } else {
- // if $limit is negative, print abs($limit) items starting from the end
- $limit = min($size, abs($limit));
- for ($i = 0; $i < $limit; $i++) {
- print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2);
- }
- }
- print("</table>");
- // let's print the display all link at the bottom as well...
- if ($display_link) {
- echo '<div style="text-align: left; padding: 2em">' . $display_link . '</div>';
- }
- }
- /**
- * Generates a tabular report for all functions. This is the top-level report.
- *
- * @author Kannan
- */
- function full_report($url_params, $symbol_tab, $sort, $run1, $run2) {
- global $vwbar;
- global $vbar;
- global $totals;
- global $totals_1;
- global $totals_2;
- global $metrics;
- global $diff_mode;
- global $descriptions;
- global $sort_col;
- global $format_cbk;
- global $display_calls;
- global $base_path;
- $possible_metrics = xhprof_get_possible_metrics();
- if ($diff_mode) {
- $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
- 'run1'),
- 'run2');
- $href1 = "$base_path/?" .
- http_build_query(xhprof_array_set($base_url_params,
- 'run', $run1));
- $href2 = "$base_path/?" .
- http_build_query(xhprof_array_set($base_url_params,
- 'run', $run2));
- print("<h3><center>Overall Diff Summary</center></h3>");
- print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
- .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
- print('<tr bgcolor="#bdc7d8" align=right>');
- print("<th></th>");
- print("<th $vwbar>" . xhprof_render_link("Run #$run1", $href1) . "</th>");
- print("<th $vwbar>" . xhprof_render_link("Run #$run2", $href2) . "</th>");
- print("<th $vwbar>Diff</th>");
- print("<th $vwbar>Diff%</th>");
- print('</tr>');
- if ($display_calls) {
- print('<tr>');
- print("<td>Number of Function Calls</td>");
- print_td_num($totals_1["ct"], $format_cbk["ct"]);
- print_td_num($totals_2["ct"], $format_cbk["ct"]);
- print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true);
- print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true);
- print('</tr>');
- }
- foreach ($metrics as $metric) {
- $m = $metric;
- print('<tr>');
- print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
- print_td_num($totals_1[$m], $format_cbk[$m]);
- print_td_num($totals_2[$m], $format_cbk[$m]);
- print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true);
- print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true);
- print('<tr>');
- }
- print('</table>');
- $callgraph_report_title = '[View Regressions/Improvements using Callgraph Diff]';
- } else {
- print("<p><center>\n");
- print('<table cellpadding=2 cellspacing=1 width="30%" '
- .'bgcolor="#bdc7d8" align=center>' . "\n");
- echo "<tr>";
- echo "<th style='text-align:right'>Overall Summary</th>";
- echo "<th></th>";
- echo "</tr>";
- foreach ($metrics as $metric) {
- echo "<tr>";
- echo "<td style='text-align:right; font-weight:bold'>Total "
- . str_replace("<br>", " ", stat_description($metric)) . ":</td>";
- echo "<td>" . number_format($totals[$metric]) . " "
- . $possible_metrics[$metric][1] . "</td>";
- echo "</tr>";
- }
- if ($display_calls) {
- echo "<tr>";
- echo "<td style='text-align:right; font-weight:bold'>Number of Function Calls:</td>";
- echo "<td>" . number_format($totals['ct']) . "</td>";
- echo "</tr>";
- }
- echo "</table>";
- print("</center></p>\n");
- $callgraph_report_title = '[View Full Callgraph]';
- }
- print("<center><br><h3>" .
- xhprof_render_link($callgraph_report_title,
- "$base_path/callgraph.php" . "?" . http_build_query($url_params))
- . "</h3></center>");
- $flat_data = array();
- foreach ($symbol_tab as $symbol => $info) {
- $tmp = $info;
- $tmp["fn"] = $symbol;
- $flat_data[] = $tmp;
- }
- usort($flat_data, 'sort_cbk');
- print("<br>");
- if (!empty($url_params['all'])) {
- $all = true;
- $limit = 0; // display all rows
- } else {
- $all = false;
- $limit = 100; // display only limited number of rows
- }
- $desc = str_replace("<br>", " ", $descriptions[$sort_col]);
- if ($diff_mode) {
- if ($all) {
- $title = "Total Diff Report: '
- .'Sorted by absolute value of regression/improvement in $desc";
- } else {
- $title = "Top 100 <i style='color:red'>Regressions</i>/"
- . "<i style='color:green'>Improvements</i>: "
- . "Sorted by $desc Diff";
- }
- } else {
- if ($all) {
- $title = "Sorted by $desc";
- } else {
- $title = "Displaying top $limit functions: Sorted by $desc";
- }
- }
- print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit);
- }
- /**
- * Return attribute names and values to be used by javascript tooltip.
- */
- function get_tooltip_attributes($type, $metric) {
- return "type='$type' metric='$metric'";
- }
- /**
- * Print info for a parent or child function in the
- * parent & children report.
- *
- * @author Kannan
- */
- function pc_info($info, $base_ct, $base_info, $parent) {
- global $sort_col;
- global $metrics;
- global $format_cbk;
- global $display_calls;
- if ($parent)
- $type = "Parent";
- else $type = "Child";
- if ($display_calls) {
- $mouseoverct = get_tooltip_attributes($type, "ct");
- /* call count */
- print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"), $mouseoverct);
- print_td_pct($info["ct"], $base_ct, ($sort_col == "ct"), $mouseoverct);
- }
- /* Inclusive metric values */
- foreach ($metrics as $metric) {
- print_td_num($info[$metric], $format_cbk[$metric],
- ($sort_col == $metric),
- get_tooltip_attributes($type, $metric));
- print_td_pct($info[$metric], $base_info[$metric], ($sort_col == $metric),
- get_tooltip_attributes($type, $metric));
- }
- }
- function print_pc_array($url_params, $results, $base_ct, $base_info, $parent,
- $run1, $run2) {
- global $base_path;
- // Construct section title
- if ($parent) {
- $title = 'Parent function';
- }
- else {
- $title = 'Child function';
- }
- if (count($results) > 1) {
- $title .= 's';
- }
- print("<tr bgcolor='#e0e0ff'><td>");
- print("<b><i><center>" . $title . "</center></i></b>");
- print("</td></tr>");
- $odd_even = 0;
- foreach ($results as $info) {
- $href = "$base_path/?" .
- http_build_query(xhprof_array_set($url_params,
- 'symbol', $info["fn"]));
- $odd_even = 1 - $odd_even;
- if ($odd_even) {
- print('<tr>');
- }
- else {
- print('<tr bgcolor="#e5e5e5">');
- }
- print("<td>" . xhprof_render_link($info["fn"], $href));
- print_source_link($info);
- print("</td>");
- pc_info($info, $base_ct, $base_info, $parent);
- print("</tr>");
- }
- }
- function print_source_link($info) {
- if (strncmp($info['fn'], 'run_init', 8) && $info['fn'] !== 'main()') {
- if (defined('XHPROF_SYMBOL_LOOKUP_URL')) {
- $link = xhprof_render_link(
- 'source',
- XHPROF_SYMBOL_LOOKUP_URL . '?symbol='.rawurlencode($info["fn"]));
- print(' ('.$link.')');
- }
- }
- }
- function print_symbol_summary($symbol_info, $stat, $base) {
- $val = $symbol_info[$stat];
- $desc = str_replace("<br>", " ", stat_description($stat));
- print("$desc: </td>");
- print(number_format($val));
- print(" (" . pct($val, $base) . "% of overall)");
- if (substr($stat, 0, 4) == "excl") {
- $func_base = $symbol_info[str_replace("excl_", "", $stat)];
- print(" (" . pct($val, $func_base) . "% of this function)");
- }
- print("<br>");
- }
- /**
- * Generates a report for a single function/symbol.
- *
- * @author Kannan
- */
- function symbol_report($url_params,
- $run_data, $symbol_info, $sort, $rep_symbol,
- $run1,
- $symbol_info1 = null,
- $run2 = 0,
- $symbol_info2 = null) {
- global $vwbar;
- global $vbar;
- global $totals;
- global $pc_stats;
- global $sortable_columns;
- global $metrics;
- global $diff_mode;
- global $descriptions;
- global $format_cbk;
- global $sort_col;
- global $display_calls;
- global $base_path;
- $possible_metrics = xhprof_get_possible_metrics();
- if ($diff_mode) {
- $diff_text = "<b>Diff</b>";
- $regr_impr = "<i style='color:red'>Regression</i>/<i style='color:green'>Improvement</i>";
- } else {
- $diff_text = "";
- $regr_impr = "";
- }
- if ($diff_mode) {
- $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
- 'run1'),
- 'run2');
- $href1 = "$base_path?"
- . http_build_query(xhprof_array_set($base_url_params, 'run', $run1));
- $href2 = "$base_path?"
- . http_build_query(xhprof_array_set($base_url_params, 'run', $run2));
- print("<h3 align=center>$regr_impr summary for $rep_symbol<br><br></h3>");
- print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
- .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
- print('<tr bgcolor="#bdc7d8" align=right>');
- print("<th align=left>$rep_symbol</th>");
- print("<th $vwbar><a href=" . $href1 . ">Run #$run1</a></th>");
- print("<th $vwbar><a href=" . $href2 . ">Run #$run2</a></th>");
- print("<th $vwbar>Diff</th>");
- print("<th $vwbar>Diff%</th>");
- print('</tr>');
- print('<tr>');
- if ($display_calls) {
- print("<td>Number of Function Calls</td>");
- print_td_num($symbol_info1["ct"], $format_cbk["ct"]);
- print_td_num($symbol_info2["ct"], $format_cbk["ct"]);
- print_td_num($symbol_info2["ct"] - $symbol_info1["ct"],
- $format_cbk["ct"], true);
- print_td_pct($symbol_info2["ct"] - $symbol_info1["ct"],
- $symbol_info1["ct"], true);
- print('</tr>');
- }
- foreach ($metrics as $metric) {
- $m = $metric;
- // Inclusive stat for metric
- print('<tr>');
- print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
- print_td_num($symbol_info1[$m], $format_cbk[$m]);
- print_td_num($symbol_info2[$m], $format_cbk[$m]);
- print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
- print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
- print('</tr>');
- // AVG (per call) Inclusive stat for metric
- print('<tr>');
- print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . " per call </td>");
- $avg_info1 = 'N/A';
- $avg_info2 = 'N/A';
- if ($symbol_info1['ct'] > 0) {
- $avg_info1 = ($symbol_info1[$m] / $symbol_info1['ct']);
- }
- if ($symbol_info2['ct'] > 0) {
- $avg_info2 = ($symbol_info2[$m] / $symbol_info2['ct']);
- }
- print_td_num($avg_info1, $format_cbk[$m]);
- print_td_num($avg_info2, $format_cbk[$m]);
- print_td_num($avg_info2 - $avg_info1, $format_cbk[$m], true);
- print_td_pct($avg_info2 - $avg_info1, $avg_info1, true);
- print('</tr>');
- // Exclusive stat for metric
- $m = "excl_" . $metric;
- print('<tr style="border-bottom: 1px solid black;">');
- print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
- print_td_num($symbol_info1[$m], $format_cbk[$m]);
- print_td_num($symbol_info2[$m], $format_cbk[$m]);
- print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
- print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
- print('</tr>');
- }
- print('</table>');
- }
- print("<br><h4><center>");
- print("Parent/Child $regr_impr report for <b>$rep_symbol</b>");
- $callgraph_href = "$base_path/callgraph.php?"
- . http_build_query(xhprof_array_set($url_params, 'func', $rep_symbol));
- print(" <a href='$callgraph_href'>[View Callgraph $diff_text]</a><br>");
- print("</center></h4><br>");
- print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
- .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
- print('<tr bgcolor="#bdc7d8" align=right>');
- foreach ($pc_stats as $stat) {
- $desc = stat_description($stat);
- if (array_key_exists($stat, $sortable_columns)) {
- $href = "$base_path/?" .
- http_build_query(xhprof_array_set($url_params,
- 'sort', $stat));
- $header = xhprof_render_link($desc, $href);
- } else {
- $header = $desc;
- }
- if ($stat == "fn")
- print("<th align=left><nobr>$header</th>");
- else print("<th " . $vwbar . "><nobr>$header</th>");
- }
- print("</tr>");
- print("<tr bgcolor='#e0e0ff'><td>");
- print("<b><i><center>Current Function</center></i></b>");
- print("</td></tr>");
- print("<tr>");
- // make this a self-reference to facilitate copy-pasting snippets to e-mails
- print("<td><a href=''>$rep_symbol</a>");
- print_source_link(array('fn' => $rep_symbol));
- print("</td>");
- if ($display_calls) {
- // Call Count
- print_td_num($symbol_info["ct"], $format_cbk["ct"]);
- print_td_pct($symbol_info["ct"], $totals["ct"]);
- }
- // Inclusive Metrics for current function
- foreach ($metrics as $metric) {
- print_td_num($symbol_info[$metric], $format_cbk[$metric], ($sort_col == $metric));
- print_td_pct($symbol_info[$metric], $totals[$metric], ($sort_col == $metric));
- }
- print("</tr>");
- print("<tr bgcolor='#ffffff'>");
- print("<td style='text-align:right;color:blue'>"
- ."Exclusive Metrics $diff_text for Current Function</td>");
- if ($display_calls) {
- // Call Count
- print("<td $vbar></td>");
- print("<td $vbar></td>");
- }
- // Exclusive Metrics for current function
- foreach ($metrics as $metric) {
- print_td_num($symbol_info["excl_" . $metric], $format_cbk["excl_" . $metric],
- ($sort_col == $metric),
- get_tooltip_attributes("Child", $metric));
- print_td_pct($symbol_info["excl_" . $metric], $symbol_info[$metric],
- ($sort_col == $metric),
- get_tooltip_attributes("Child", $metric));
- }
- print("</tr>");
- // list of callers/parent functions
- $results = array();
- if ($display_calls) {
- $base_ct = $symbol_info["ct"];
- } else {
- $base_ct = 0;
- }
- foreach ($metrics as $metric) {
- $base_info[$metric] = $symbol_info[$metric];
- }
- foreach ($run_data as $parent_child => $info) {
- list($parent, $child) = xhprof_parse_parent_child($parent_child);
- if (($child == $rep_symbol) && ($parent)) {
- $info_tmp = $info;
- $info_tmp["fn"] = $parent;
- $results[] = $info_tmp;
- }
- }
- usort($results, 'sort_cbk');
- if (count($results) > 0) {
- print_pc_array($url_params, $results, $base_ct, $base_info, true,
- $run1, $run2);
- }
- // list of callees/child functions
- $results = array();
- $base_ct = 0;
- foreach ($run_data as $parent_child => $info) {
- list($parent, $child) = xhprof_parse_parent_child($parent_child);
- if ($parent == $rep_symbol) {
- $info_tmp = $info;
- $info_tmp["fn"] = $child;
- $results[] = $info_tmp;
- if ($display_calls) {
- $base_ct += $info["ct"];
- }
- }
- }
- usort($results, 'sort_cbk');
- if (count($results)) {
- print_pc_array($url_params, $results, $base_ct, $base_info, false,
- $run1, $run2);
- }
- print("</table>");
- // These will be used for pop-up tips/help.
- // Related javascript code is in: xhprof_report.js
- print("\n");
- print('<script language="javascript">' . "\n");
- print("var func_name = '\"" . $rep_symbol . "\"';\n");
- print("var total_child_ct = " . $base_ct . ";\n");
- if ($display_calls) {
- print("var func_ct = " . $symbol_info["ct"] . ";\n");
- }
- print("var func_metrics = new Array();\n");
- print("var metrics_col = new Array();\n");
- print("var metrics_desc = new Array();\n");
- if ($diff_mode) {
- print("var diff_mode = true;\n");
- } else {
- print("var diff_mode = false;\n");
- }
- $column_index = 3; // First three columns are Func Name, Calls, Calls%
- foreach ($metrics as $metric) {
- print("func_metrics[\"" . $metric . "\"] = " . round($symbol_info[$metric]) . ";\n");
- print("metrics_col[\"". $metric . "\"] = " . $column_index . ";\n");
- print("metrics_desc[\"". $metric . "\"] = \"" . $possible_metrics[$metric][2] . "\";\n");
- // each metric has two columns..
- $column_index += 2;
- }
- print('</script>');
- print("\n");
- }
- /**
- * Generate the profiler report for a single run.
- *
- * @author Kannan
- */
- function profiler_single_run_report ($url_params,
- $xhprof_data,
- $run_desc,
- $rep_symbol,
- $sort,
- $run) {
- init_metrics($xhprof_data, $rep_symbol, $sort, false);
- profiler_report($url_params, $rep_symbol, $sort, $run, $run_desc,
- $xhprof_data);
- }
- /**
- * Generate the profiler report for diff mode (delta between two runs).
- *
- * @author Kannan
- */
- function profiler_diff_report($url_params,
- $xhprof_data1,
- $run1_desc,
- $xhprof_data2,
- $run2_desc,
- $rep_symbol,
- $sort,
- $run1,
- $run2) {
- // Initialize what metrics we'll display based on data in Run2
- init_metrics($xhprof_data2, $rep_symbol, $sort, true);
- profiler_report($url_params,
- $rep_symbol,
- $sort,
- $run1,
- $run1_desc,
- $xhprof_data1,
- $run2,
- $run2_desc,
- $xhprof_data2);
- }
- /**
- * Generate a XHProf Display View given the various URL parameters
- * as arguments. The first argument is an object that implements
- * the iXHProfRuns interface.
- *
- * @param object $xhprof_runs_impl An object that implements
- * the iXHProfRuns interface
- *.
- * @param array $url_params Array of non-default URL params.
- *
- * @param string $source Category/type of the run. The source in
- * combination with the run id uniquely
- * determines a profiler run.
- *
- * @param string $run run id, or comma separated sequence of
- * run ids. The latter is used if an aggregate
- * report of the runs is desired.
- *
- * @param string $wts Comma separate list of integers.
- * Represents the weighted ratio in
- * which which a set of runs will be
- * aggregated. [Used only for aggregate
- * reports.]
- *
- * @param string $symbol Function symbol. If non-empty then the
- * parent/child view of this function is
- * displayed. If empty, a flat-profile view
- * of the functions is displayed.
- *
- * @param string $run1 Base run id (for diff reports)
- *
- * @param string $run2 New run id (for diff reports)
- *
- */
- function displayXHProfReport($xhprof_runs_impl, $url_params, $source,
- $run, $wts, $symbol, $sort, $run1, $run2) {
- if ($run) { // specific run to display?
- // run may be a single run or a comma separate list of runs
- // that'll be aggregated. If "wts" (a comma separated list
- // of integral weights is specified), the runs will be
- // aggregated in that ratio.
- //
- $runs_array = explode(",", $run);
- if (count($runs_array) == 1) {
- $xhprof_data = $xhprof_runs_impl->get_run($runs_array[0],
- $source,
- $description);
- } else {
- if (!empty($wts)) {
- $wts_array = explode(",", $wts);
- } else {
- $wts_array = null;
- }
- $data = xhprof_aggregate_runs($xhprof_runs_impl,
- $runs_array, $wts_array, $source, false);
- $xhprof_data = $data['raw'];
- $description = $data['description'];
- }
- profiler_single_run_report($url_params,
- $xhprof_data,
- $description,
- $symbol,
- $sort,
- $run);
- } else if ($run1 && $run2) { // diff report for two runs
- $xhprof_data1 = $xhprof_runs_impl->get_run($run1, $source, $description1);
- $xhprof_data2 = $xhprof_runs_impl->get_run($run2, $source, $description2);
- profiler_diff_report($url_params,
- $xhprof_data1,
- $description1,
- $xhprof_data2,
- $description2,
- $symbol,
- $sort,
- $run1,
- $run2);
- } else {
- echo "No XHProf runs specified in the URL.";
- if (method_exists($xhprof_runs_impl, 'list_runs')) {
- $xhprof_runs_impl->list_runs();
- }
- }
- }
|