xhprof.php 44 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436
  1. <?php
  2. // Copyright (c) 2009 Facebook
  3. //
  4. // Licensed under the Apache License, Version 2.0 (the "License");
  5. // you may not use this file except in compliance with the License.
  6. // You may obtain a copy of the License at
  7. //
  8. // http://www.apache.org/licenses/LICENSE-2.0
  9. //
  10. // Unless required by applicable law or agreed to in writing, software
  11. // distributed under the License is distributed on an "AS IS" BASIS,
  12. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13. // See the License for the specific language governing permissions and
  14. // limitations under the License.
  15. //
  16. //
  17. // XHProf: A Hierarchical Profiler for PHP
  18. //
  19. // XHProf has two components:
  20. //
  21. // * This module is the UI/reporting component, used
  22. // for viewing results of XHProf runs from a browser.
  23. //
  24. // * Data collection component: This is implemented
  25. // as a PHP extension (XHProf).
  26. //
  27. // @author Kannan Muthukkaruppan
  28. //
  29. if (!isset($GLOBALS['XHPROF_LIB_ROOT'])) {
  30. // by default, the parent directory is XHPROF lib root
  31. $GLOBALS['XHPROF_LIB_ROOT'] = realpath(__DIR__.'/..');
  32. }
  33. require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_lib.php';
  34. require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/callgraph_utils.php';
  35. require_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_runs.php';
  36. /**
  37. * Our coding convention disallows relative paths in hrefs.
  38. * Get the base URL path from the SCRIPT_NAME.
  39. */
  40. $base_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
  41. /**
  42. * Generate references to required stylesheets & javascript.
  43. *
  44. * If the calling script (such as index.php) resides in
  45. * a different location that than 'xhprof_html' directory the
  46. * caller must provide the URL path to 'xhprof_html' directory
  47. * so that the correct location of the style sheets/javascript
  48. * can be specified in the generated HTML.
  49. *
  50. */
  51. function xhprof_include_js_css($ui_dir_url_path = null) {
  52. if (empty($ui_dir_url_path)) {
  53. $ui_dir_url_path = rtrim(dirname($_SERVER['SCRIPT_NAME']), '/\\');
  54. }
  55. // style sheets
  56. echo "<link href='$ui_dir_url_path/css/xhprof.css' rel='stylesheet' ".
  57. " type='text/css' />";
  58. echo "<link href='$ui_dir_url_path/jquery/jquery.tooltip.css' ".
  59. " rel='stylesheet' type='text/css' />";
  60. // javascript
  61. echo "<script src='$ui_dir_url_path/jquery/jquery-1.2.6.js'>".
  62. "</script>";
  63. echo "<script src='$ui_dir_url_path/jquery/jquery.tooltip.js'>".
  64. "</script>";
  65. echo "<script src='$ui_dir_url_path/jquery/jquery.autocomplete.js'>"
  66. ."</script>";
  67. echo "<script src='$ui_dir_url_path/js/xhprof_report.js'></script>";
  68. }
  69. /*
  70. * Formats call counts for XHProf reports.
  71. *
  72. * Description:
  73. * Call counts in single-run reports are integer values.
  74. * However, call counts for aggregated reports can be
  75. * fractional. This function will print integer values
  76. * without decimal point, but with commas etc.
  77. *
  78. * 4000 ==> 4,000
  79. *
  80. * It'll round fractional values to decimal precision of 3
  81. * 4000.1212 ==> 4,000.121
  82. * 4000.0001 ==> 4,000
  83. *
  84. */
  85. function xhprof_count_format($num) {
  86. $num = round($num, 3);
  87. if (round($num) == $num) {
  88. return number_format($num);
  89. } else {
  90. return number_format($num, 3);
  91. }
  92. }
  93. function xhprof_percent_format($s, $precision = 1) {
  94. return sprintf('%.'.$precision.'f%%', 100 * $s);
  95. }
  96. /**
  97. * Implodes the text for a bunch of actions (such as links, forms,
  98. * into a HTML list and returns the text.
  99. */
  100. function xhprof_render_actions($actions) {
  101. $out = array();
  102. if (count($actions)) {
  103. $out[] = '<ul class="xhprof_actions">';
  104. foreach ($actions as $action) {
  105. $out[] = '<li>'.$action.'</li>';
  106. }
  107. $out[] = '</ul>';
  108. }
  109. return implode('', $out);
  110. }
  111. /**
  112. * @param html-str $content the text/image/innerhtml/whatever for the link
  113. * @param raw-str $href
  114. * @param raw-str $class
  115. * @param raw-str $id
  116. * @param raw-str $title
  117. * @param raw-str $target
  118. * @param raw-str $onclick
  119. * @param raw-str $style
  120. * @param raw-str $access
  121. * @param raw-str $onmouseover
  122. * @param raw-str $onmouseout
  123. * @param raw-str $onmousedown
  124. * @param raw-str $dir
  125. * @param raw-str $rel
  126. */
  127. function xhprof_render_link($content, $href, $class='', $id='', $title='',
  128. $target='',
  129. $onclick='', $style='', $access='', $onmouseover='',
  130. $onmouseout='', $onmousedown='') {
  131. if (!$content) {
  132. return '';
  133. }
  134. if ($href) {
  135. $link = '<a href="' . ($href) . '"';
  136. } else {
  137. $link = '<span';
  138. }
  139. if ($class) {
  140. $link .= ' class="' . ($class) . '"';
  141. }
  142. if ($id) {
  143. $link .= ' id="' . ($id) . '"';
  144. }
  145. if ($title) {
  146. $link .= ' title="' . ($title) . '"';
  147. }
  148. if ($target) {
  149. $link .= ' target="' . ($target) . '"';
  150. }
  151. if ($onclick && $href) {
  152. $link .= ' onclick="' . ($onclick) . '"';
  153. }
  154. if ($style && $href) {
  155. $link .= ' style="' . ($style) . '"';
  156. }
  157. if ($access && $href) {
  158. $link .= ' accesskey="' . ($access) . '"';
  159. }
  160. if ($onmouseover) {
  161. $link .= ' onmouseover="' . ($onmouseover) . '"';
  162. }
  163. if ($onmouseout) {
  164. $link .= ' onmouseout="' . ($onmouseout) . '"';
  165. }
  166. if ($onmousedown) {
  167. $link .= ' onmousedown="' . ($onmousedown) . '"';
  168. }
  169. $link .= '>';
  170. $link .= $content;
  171. if ($href) {
  172. $link .= '</a>';
  173. } else {
  174. $link .= '</span>';
  175. }
  176. return $link;
  177. }
  178. // default column to sort on -- wall time
  179. $sort_col = "wt";
  180. // default is "single run" report
  181. $diff_mode = false;
  182. // call count data present?
  183. $display_calls = true;
  184. // The following column headers are sortable
  185. $sortable_columns = array("fn" => 1,
  186. "ct" => 1,
  187. "wt" => 1,
  188. "excl_wt" => 1,
  189. "ut" => 1,
  190. "excl_ut" => 1,
  191. "st" => 1,
  192. "excl_st" => 1,
  193. "mu" => 1,
  194. "excl_mu" => 1,
  195. "pmu" => 1,
  196. "excl_pmu" => 1,
  197. "cpu" => 1,
  198. "excl_cpu" => 1,
  199. "samples" => 1,
  200. "excl_samples" => 1
  201. );
  202. // Textual descriptions for column headers in "single run" mode
  203. $descriptions = array(
  204. "fn" => "Function Name",
  205. "ct" => "Calls",
  206. "Calls%" => "Calls%",
  207. "wt" => "Incl. Wall Time<br>(microsec)",
  208. "IWall%" => "IWall%",
  209. "excl_wt" => "Excl. Wall Time<br>(microsec)",
  210. "EWall%" => "EWall%",
  211. "ut" => "Incl. User<br>(microsecs)",
  212. "IUser%" => "IUser%",
  213. "excl_ut" => "Excl. User<br>(microsec)",
  214. "EUser%" => "EUser%",
  215. "st" => "Incl. Sys <br>(microsec)",
  216. "ISys%" => "ISys%",
  217. "excl_st" => "Excl. Sys <br>(microsec)",
  218. "ESys%" => "ESys%",
  219. "cpu" => "Incl. CPU<br>(microsecs)",
  220. "ICpu%" => "ICpu%",
  221. "excl_cpu" => "Excl. CPU<br>(microsec)",
  222. "ECpu%" => "ECPU%",
  223. "mu" => "Incl.<br>MemUse<br>(bytes)",
  224. "IMUse%" => "IMemUse%",
  225. "excl_mu" => "Excl.<br>MemUse<br>(bytes)",
  226. "EMUse%" => "EMemUse%",
  227. "pmu" => "Incl.<br> PeakMemUse<br>(bytes)",
  228. "IPMUse%" => "IPeakMemUse%",
  229. "excl_pmu" => "Excl.<br>PeakMemUse<br>(bytes)",
  230. "EPMUse%" => "EPeakMemUse%",
  231. "samples" => "Incl. Samples",
  232. "ISamples%" => "ISamples%",
  233. "excl_samples" => "Excl. Samples",
  234. "ESamples%" => "ESamples%",
  235. );
  236. // Formatting Callback Functions...
  237. $format_cbk = array(
  238. "fn" => "",
  239. "ct" => "xhprof_count_format",
  240. "Calls%" => "xhprof_percent_format",
  241. "wt" => "number_format",
  242. "IWall%" => "xhprof_percent_format",
  243. "excl_wt" => "number_format",
  244. "EWall%" => "xhprof_percent_format",
  245. "ut" => "number_format",
  246. "IUser%" => "xhprof_percent_format",
  247. "excl_ut" => "number_format",
  248. "EUser%" => "xhprof_percent_format",
  249. "st" => "number_format",
  250. "ISys%" => "xhprof_percent_format",
  251. "excl_st" => "number_format",
  252. "ESys%" => "xhprof_percent_format",
  253. "cpu" => "number_format",
  254. "ICpu%" => "xhprof_percent_format",
  255. "excl_cpu" => "number_format",
  256. "ECpu%" => "xhprof_percent_format",
  257. "mu" => "number_format",
  258. "IMUse%" => "xhprof_percent_format",
  259. "excl_mu" => "number_format",
  260. "EMUse%" => "xhprof_percent_format",
  261. "pmu" => "number_format",
  262. "IPMUse%" => "xhprof_percent_format",
  263. "excl_pmu" => "number_format",
  264. "EPMUse%" => "xhprof_percent_format",
  265. "samples" => "number_format",
  266. "ISamples%" => "xhprof_percent_format",
  267. "excl_samples" => "number_format",
  268. "ESamples%" => "xhprof_percent_format",
  269. );
  270. // Textual descriptions for column headers in "diff" mode
  271. $diff_descriptions = array(
  272. "fn" => "Function Name",
  273. "ct" => "Calls Diff",
  274. "Calls%" => "Calls<br>Diff%",
  275. "wt" => "Incl. Wall<br>Diff<br>(microsec)",
  276. "IWall%" => "IWall<br> Diff%",
  277. "excl_wt" => "Excl. Wall<br>Diff<br>(microsec)",
  278. "EWall%" => "EWall<br>Diff%",
  279. "ut" => "Incl. User Diff<br>(microsec)",
  280. "IUser%" => "IUser<br>Diff%",
  281. "excl_ut" => "Excl. User<br>Diff<br>(microsec)",
  282. "EUser%" => "EUser<br>Diff%",
  283. "cpu" => "Incl. CPU Diff<br>(microsec)",
  284. "ICpu%" => "ICpu<br>Diff%",
  285. "excl_cpu" => "Excl. CPU<br>Diff<br>(microsec)",
  286. "ECpu%" => "ECpu<br>Diff%",
  287. "st" => "Incl. Sys Diff<br>(microsec)",
  288. "ISys%" => "ISys<br>Diff%",
  289. "excl_st" => "Excl. Sys Diff<br>(microsec)",
  290. "ESys%" => "ESys<br>Diff%",
  291. "mu" => "Incl.<br>MemUse<br>Diff<br>(bytes)",
  292. "IMUse%" => "IMemUse<br>Diff%",
  293. "excl_mu" => "Excl.<br>MemUse<br>Diff<br>(bytes)",
  294. "EMUse%" => "EMemUse<br>Diff%",
  295. "pmu" => "Incl.<br> PeakMemUse<br>Diff<br>(bytes)",
  296. "IPMUse%" => "IPeakMemUse<br>Diff%",
  297. "excl_pmu" => "Excl.<br>PeakMemUse<br>Diff<br>(bytes)",
  298. "EPMUse%" => "EPeakMemUse<br>Diff%",
  299. "samples" => "Incl. Samples Diff",
  300. "ISamples%" => "ISamples Diff%",
  301. "excl_samples" => "Excl. Samples Diff",
  302. "ESamples%" => "ESamples Diff%",
  303. );
  304. // columns that'll be displayed in a top-level report
  305. $stats = array();
  306. // columns that'll be displayed in a function's parent/child report
  307. $pc_stats = array();
  308. // Various total counts
  309. $totals = 0;
  310. $totals_1 = 0;
  311. $totals_2 = 0;
  312. /*
  313. * The subset of $possible_metrics that is present in the raw profile data.
  314. */
  315. $metrics = null;
  316. /**
  317. * Callback comparison operator (passed to usort() for sorting array of
  318. * tuples) that compares array elements based on the sort column
  319. * specified in $sort_col (global parameter).
  320. *
  321. * @author Kannan
  322. */
  323. function sort_cbk($a, $b) {
  324. global $sort_col;
  325. global $diff_mode;
  326. if ($sort_col == "fn") {
  327. // case insensitive ascending sort for function names
  328. $left = strtoupper($a["fn"]);
  329. $right = strtoupper($b["fn"]);
  330. if ($left == $right)
  331. return 0;
  332. return ($left < $right) ? -1 : 1;
  333. } else {
  334. // descending sort for all others
  335. $left = $a[$sort_col];
  336. $right = $b[$sort_col];
  337. // if diff mode, sort by absolute value of regression/improvement
  338. if ($diff_mode) {
  339. $left = abs($left);
  340. $right = abs($right);
  341. }
  342. if ($left == $right)
  343. return 0;
  344. return ($left > $right) ? -1 : 1;
  345. }
  346. }
  347. /**
  348. * Get the appropriate description for a statistic
  349. * (depending upon whether we are in diff report mode
  350. * or single run report mode).
  351. *
  352. * @author Kannan
  353. */
  354. function stat_description($stat) {
  355. global $descriptions;
  356. global $diff_descriptions;
  357. global $diff_mode;
  358. if ($diff_mode) {
  359. return $diff_descriptions[$stat];
  360. } else {
  361. return $descriptions[$stat];
  362. }
  363. }
  364. /**
  365. * Analyze raw data & generate the profiler report
  366. * (common for both single run mode and diff mode).
  367. *
  368. * @author: Kannan
  369. */
  370. function profiler_report ($url_params,
  371. $rep_symbol,
  372. $sort,
  373. $run1,
  374. $run1_desc,
  375. $run1_data,
  376. $run2 = 0,
  377. $run2_desc = "",
  378. $run2_data = array()) {
  379. global $totals;
  380. global $totals_1;
  381. global $totals_2;
  382. global $stats;
  383. global $pc_stats;
  384. global $diff_mode;
  385. global $base_path;
  386. // if we are reporting on a specific function, we can trim down
  387. // the report(s) to just stuff that is relevant to this function.
  388. // That way compute_flat_info()/compute_diff() etc. do not have
  389. // to needlessly work hard on churning irrelevant data.
  390. if (!empty($rep_symbol)) {
  391. $run1_data = xhprof_trim_run($run1_data, array($rep_symbol));
  392. if ($diff_mode) {
  393. $run2_data = xhprof_trim_run($run2_data, array($rep_symbol));
  394. }
  395. }
  396. if ($diff_mode) {
  397. $run_delta = xhprof_compute_diff($run1_data, $run2_data);
  398. $symbol_tab = xhprof_compute_flat_info($run_delta, $totals);
  399. $symbol_tab1 = xhprof_compute_flat_info($run1_data, $totals_1);
  400. $symbol_tab2 = xhprof_compute_flat_info($run2_data, $totals_2);
  401. } else {
  402. $symbol_tab = xhprof_compute_flat_info($run1_data, $totals);
  403. }
  404. $run1_txt = sprintf("<b>Run #%s:</b> %s",
  405. $run1, $run1_desc);
  406. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  407. 'symbol'),
  408. 'all');
  409. $top_link_query_string = "$base_path/?" . http_build_query($base_url_params);
  410. if ($diff_mode) {
  411. $diff_text = "Diff";
  412. $base_url_params = xhprof_array_unset($base_url_params, 'run1');
  413. $base_url_params = xhprof_array_unset($base_url_params, 'run2');
  414. $run1_link = xhprof_render_link('View Run #' . $run1,
  415. "$base_path/?" .
  416. http_build_query(xhprof_array_set($base_url_params,
  417. 'run',
  418. $run1)));
  419. $run2_txt = sprintf("<b>Run #%s:</b> %s",
  420. $run2, $run2_desc);
  421. $run2_link = xhprof_render_link('View Run #' . $run2,
  422. "$base_path/?" .
  423. http_build_query(xhprof_array_set($base_url_params,
  424. 'run',
  425. $run2)));
  426. } else {
  427. $diff_text = "Run";
  428. }
  429. // set up the action links for operations that can be done on this report
  430. $links = array();
  431. $links [] = xhprof_render_link("View Top Level $diff_text Report",
  432. $top_link_query_string);
  433. if ($diff_mode) {
  434. $inverted_params = $url_params;
  435. $inverted_params['run1'] = $url_params['run2'];
  436. $inverted_params['run2'] = $url_params['run1'];
  437. // view the different runs or invert the current diff
  438. $links [] = $run1_link;
  439. $links [] = $run2_link;
  440. $links [] = xhprof_render_link('Invert ' . $diff_text . ' Report',
  441. "$base_path/?".
  442. http_build_query($inverted_params));
  443. }
  444. // lookup function typeahead form
  445. $links [] = '<input class="function_typeahead" ' .
  446. ' type="input" size="40" maxlength="100" />';
  447. echo xhprof_render_actions($links);
  448. echo
  449. '<dl class=phprof_report_info>' .
  450. ' <dt>' . $diff_text . ' Report</dt>' .
  451. ' <dd>' . ($diff_mode ?
  452. $run1_txt . '<br><b>vs.</b><br>' . $run2_txt :
  453. $run1_txt) .
  454. ' </dd>' .
  455. ' <dt>Tip</dt>' .
  456. ' <dd>Click a function name below to drill down.</dd>' .
  457. '</dl>' .
  458. '<div style="clear: both; margin: 3em 0em;"></div>';
  459. // data tables
  460. if (!empty($rep_symbol)) {
  461. if (!isset($symbol_tab[$rep_symbol])) {
  462. echo "<hr>Symbol <b>$rep_symbol</b> not found in XHProf run</b><hr>";
  463. return;
  464. }
  465. /* single function report with parent/child information */
  466. if ($diff_mode) {
  467. $info1 = isset($symbol_tab1[$rep_symbol]) ?
  468. $symbol_tab1[$rep_symbol] : null;
  469. $info2 = isset($symbol_tab2[$rep_symbol]) ?
  470. $symbol_tab2[$rep_symbol] : null;
  471. symbol_report($url_params, $run_delta, $symbol_tab[$rep_symbol],
  472. $sort, $rep_symbol,
  473. $run1, $info1,
  474. $run2, $info2);
  475. } else {
  476. symbol_report($url_params, $run1_data, $symbol_tab[$rep_symbol],
  477. $sort, $rep_symbol, $run1);
  478. }
  479. } else {
  480. /* flat top-level report of all functions */
  481. full_report($url_params, $symbol_tab, $sort, $run1, $run2);
  482. }
  483. }
  484. /**
  485. * Computes percentage for a pair of values, and returns it
  486. * in string format.
  487. */
  488. function pct($a, $b) {
  489. if ($b == 0) {
  490. return "N/A";
  491. } else {
  492. $res = (round(($a * 1000 / $b)) / 10);
  493. return $res;
  494. }
  495. }
  496. /**
  497. * Given a number, returns the td class to use for display.
  498. *
  499. * For instance, negative numbers in diff reports comparing two runs (run1 & run2)
  500. * represent improvement from run1 to run2. We use green to display those deltas,
  501. * and red for regression deltas.
  502. */
  503. function get_print_class($num, $bold) {
  504. global $vbar;
  505. global $vbbar;
  506. global $vrbar;
  507. global $vgbar;
  508. global $diff_mode;
  509. if ($bold) {
  510. if ($diff_mode) {
  511. if ($num <= 0) {
  512. $class = $vgbar; // green (improvement)
  513. } else {
  514. $class = $vrbar; // red (regression)
  515. }
  516. } else {
  517. $class = $vbbar; // blue
  518. }
  519. }
  520. else {
  521. $class = $vbar; // default (black)
  522. }
  523. return $class;
  524. }
  525. /**
  526. * Prints a <td> element with a numeric value.
  527. */
  528. function print_td_num($num, $fmt_func, $bold=false, $attributes=null) {
  529. $class = get_print_class($num, $bold);
  530. if (!empty($fmt_func) && is_numeric($num) ) {
  531. $num = call_user_func($fmt_func, $num);
  532. }
  533. print("<td $attributes $class>$num</td>\n");
  534. }
  535. /**
  536. * Prints a <td> element with a pecentage.
  537. */
  538. function print_td_pct($numer, $denom, $bold=false, $attributes=null) {
  539. global $vbar;
  540. global $vbbar;
  541. global $diff_mode;
  542. $class = get_print_class($numer, $bold);
  543. if ($denom == 0) {
  544. $pct = "N/A%";
  545. } else {
  546. $pct = xhprof_percent_format($numer / abs($denom));
  547. }
  548. print("<td $attributes $class>$pct</td>\n");
  549. }
  550. /**
  551. * Print "flat" data corresponding to one function.
  552. *
  553. * @author Kannan
  554. */
  555. function print_function_info($url_params, $info, $sort, $run1, $run2) {
  556. static $odd_even = 0;
  557. global $totals;
  558. global $sort_col;
  559. global $metrics;
  560. global $format_cbk;
  561. global $display_calls;
  562. global $base_path;
  563. // Toggle $odd_or_even
  564. $odd_even = 1 - $odd_even;
  565. if ($odd_even) {
  566. print("<tr>");
  567. }
  568. else {
  569. print('<tr bgcolor="#e5e5e5">');
  570. }
  571. $href = "$base_path/?" .
  572. http_build_query(xhprof_array_set($url_params,
  573. 'symbol', $info["fn"]));
  574. print('<td>');
  575. print(xhprof_render_link($info["fn"], $href));
  576. print_source_link($info);
  577. print("</td>\n");
  578. if ($display_calls) {
  579. // Call Count..
  580. print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"));
  581. print_td_pct($info["ct"], $totals["ct"], ($sort_col == "ct"));
  582. }
  583. // Other metrics..
  584. foreach ($metrics as $metric) {
  585. // Inclusive metric
  586. print_td_num($info[$metric], $format_cbk[$metric],
  587. ($sort_col == $metric));
  588. print_td_pct($info[$metric], $totals[$metric],
  589. ($sort_col == $metric));
  590. // Exclusive Metric
  591. print_td_num($info["excl_" . $metric],
  592. $format_cbk["excl_" . $metric],
  593. ($sort_col == "excl_" . $metric));
  594. print_td_pct($info["excl_" . $metric],
  595. $totals[$metric],
  596. ($sort_col == "excl_" . $metric));
  597. }
  598. print("</tr>\n");
  599. }
  600. /**
  601. * Print non-hierarchical (flat-view) of profiler data.
  602. *
  603. * @author Kannan
  604. */
  605. function print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit) {
  606. global $stats;
  607. global $sortable_columns;
  608. global $vwbar;
  609. global $base_path;
  610. $size = count($flat_data);
  611. if (!$limit) { // no limit
  612. $limit = $size;
  613. $display_link = "";
  614. } else {
  615. $display_link = xhprof_render_link(" [ <b class=bubble>display all </b>]",
  616. "$base_path/?" .
  617. http_build_query(xhprof_array_set($url_params,
  618. 'all', 1)));
  619. }
  620. print("<h3 align=center>$title $display_link</h3><br>");
  621. print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
  622. .'rules=rows bordercolor="#bdc7d8" align=center>');
  623. print('<tr bgcolor="#bdc7d8" align=right>');
  624. foreach ($stats as $stat) {
  625. $desc = stat_description($stat);
  626. if (array_key_exists($stat, $sortable_columns)) {
  627. $href = "$base_path/?"
  628. . http_build_query(xhprof_array_set($url_params, 'sort', $stat));
  629. $header = xhprof_render_link($desc, $href);
  630. } else {
  631. $header = $desc;
  632. }
  633. if ($stat == "fn")
  634. print("<th align=left><nobr>$header</th>");
  635. else print("<th " . $vwbar . "><nobr>$header</th>");
  636. }
  637. print("</tr>\n");
  638. if ($limit >= 0) {
  639. $limit = min($size, $limit);
  640. for ($i = 0; $i < $limit; $i++) {
  641. print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2);
  642. }
  643. } else {
  644. // if $limit is negative, print abs($limit) items starting from the end
  645. $limit = min($size, abs($limit));
  646. for ($i = 0; $i < $limit; $i++) {
  647. print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2);
  648. }
  649. }
  650. print("</table>");
  651. // let's print the display all link at the bottom as well...
  652. if ($display_link) {
  653. echo '<div style="text-align: left; padding: 2em">' . $display_link . '</div>';
  654. }
  655. }
  656. /**
  657. * Generates a tabular report for all functions. This is the top-level report.
  658. *
  659. * @author Kannan
  660. */
  661. function full_report($url_params, $symbol_tab, $sort, $run1, $run2) {
  662. global $vwbar;
  663. global $vbar;
  664. global $totals;
  665. global $totals_1;
  666. global $totals_2;
  667. global $metrics;
  668. global $diff_mode;
  669. global $descriptions;
  670. global $sort_col;
  671. global $format_cbk;
  672. global $display_calls;
  673. global $base_path;
  674. $possible_metrics = xhprof_get_possible_metrics();
  675. if ($diff_mode) {
  676. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  677. 'run1'),
  678. 'run2');
  679. $href1 = "$base_path/?" .
  680. http_build_query(xhprof_array_set($base_url_params,
  681. 'run', $run1));
  682. $href2 = "$base_path/?" .
  683. http_build_query(xhprof_array_set($base_url_params,
  684. 'run', $run2));
  685. print("<h3><center>Overall Diff Summary</center></h3>");
  686. print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
  687. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  688. print('<tr bgcolor="#bdc7d8" align=right>');
  689. print("<th></th>");
  690. print("<th $vwbar>" . xhprof_render_link("Run #$run1", $href1) . "</th>");
  691. print("<th $vwbar>" . xhprof_render_link("Run #$run2", $href2) . "</th>");
  692. print("<th $vwbar>Diff</th>");
  693. print("<th $vwbar>Diff%</th>");
  694. print('</tr>');
  695. if ($display_calls) {
  696. print('<tr>');
  697. print("<td>Number of Function Calls</td>");
  698. print_td_num($totals_1["ct"], $format_cbk["ct"]);
  699. print_td_num($totals_2["ct"], $format_cbk["ct"]);
  700. print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true);
  701. print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true);
  702. print('</tr>');
  703. }
  704. foreach ($metrics as $metric) {
  705. $m = $metric;
  706. print('<tr>');
  707. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  708. print_td_num($totals_1[$m], $format_cbk[$m]);
  709. print_td_num($totals_2[$m], $format_cbk[$m]);
  710. print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true);
  711. print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true);
  712. print('<tr>');
  713. }
  714. print('</table>');
  715. $callgraph_report_title = '[View Regressions/Improvements using Callgraph Diff]';
  716. } else {
  717. print("<p><center>\n");
  718. print('<table cellpadding=2 cellspacing=1 width="30%" '
  719. .'bgcolor="#bdc7d8" align=center>' . "\n");
  720. echo "<tr>";
  721. echo "<th style='text-align:right'>Overall Summary</th>";
  722. echo "<th></th>";
  723. echo "</tr>";
  724. foreach ($metrics as $metric) {
  725. echo "<tr>";
  726. echo "<td style='text-align:right; font-weight:bold'>Total "
  727. . str_replace("<br>", " ", stat_description($metric)) . ":</td>";
  728. echo "<td>" . number_format($totals[$metric]) . " "
  729. . $possible_metrics[$metric][1] . "</td>";
  730. echo "</tr>";
  731. }
  732. if ($display_calls) {
  733. echo "<tr>";
  734. echo "<td style='text-align:right; font-weight:bold'>Number of Function Calls:</td>";
  735. echo "<td>" . number_format($totals['ct']) . "</td>";
  736. echo "</tr>";
  737. }
  738. echo "</table>";
  739. print("</center></p>\n");
  740. $callgraph_report_title = '[View Full Callgraph]';
  741. }
  742. print("<center><br><h3>" .
  743. xhprof_render_link($callgraph_report_title,
  744. "$base_path/callgraph.php" . "?" . http_build_query($url_params))
  745. . "</h3></center>");
  746. $flat_data = array();
  747. foreach ($symbol_tab as $symbol => $info) {
  748. $tmp = $info;
  749. $tmp["fn"] = $symbol;
  750. $flat_data[] = $tmp;
  751. }
  752. usort($flat_data, 'sort_cbk');
  753. print("<br>");
  754. if (!empty($url_params['all'])) {
  755. $all = true;
  756. $limit = 0; // display all rows
  757. } else {
  758. $all = false;
  759. $limit = 100; // display only limited number of rows
  760. }
  761. $desc = str_replace("<br>", " ", $descriptions[$sort_col]);
  762. if ($diff_mode) {
  763. if ($all) {
  764. $title = "Total Diff Report: '
  765. .'Sorted by absolute value of regression/improvement in $desc";
  766. } else {
  767. $title = "Top 100 <i style='color:red'>Regressions</i>/"
  768. . "<i style='color:green'>Improvements</i>: "
  769. . "Sorted by $desc Diff";
  770. }
  771. } else {
  772. if ($all) {
  773. $title = "Sorted by $desc";
  774. } else {
  775. $title = "Displaying top $limit functions: Sorted by $desc";
  776. }
  777. }
  778. print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit);
  779. }
  780. /**
  781. * Return attribute names and values to be used by javascript tooltip.
  782. */
  783. function get_tooltip_attributes($type, $metric) {
  784. return "type='$type' metric='$metric'";
  785. }
  786. /**
  787. * Print info for a parent or child function in the
  788. * parent & children report.
  789. *
  790. * @author Kannan
  791. */
  792. function pc_info($info, $base_ct, $base_info, $parent) {
  793. global $sort_col;
  794. global $metrics;
  795. global $format_cbk;
  796. global $display_calls;
  797. if ($parent)
  798. $type = "Parent";
  799. else $type = "Child";
  800. if ($display_calls) {
  801. $mouseoverct = get_tooltip_attributes($type, "ct");
  802. /* call count */
  803. print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"), $mouseoverct);
  804. print_td_pct($info["ct"], $base_ct, ($sort_col == "ct"), $mouseoverct);
  805. }
  806. /* Inclusive metric values */
  807. foreach ($metrics as $metric) {
  808. print_td_num($info[$metric], $format_cbk[$metric],
  809. ($sort_col == $metric),
  810. get_tooltip_attributes($type, $metric));
  811. print_td_pct($info[$metric], $base_info[$metric], ($sort_col == $metric),
  812. get_tooltip_attributes($type, $metric));
  813. }
  814. }
  815. function print_pc_array($url_params, $results, $base_ct, $base_info, $parent,
  816. $run1, $run2) {
  817. global $base_path;
  818. // Construct section title
  819. if ($parent) {
  820. $title = 'Parent function';
  821. }
  822. else {
  823. $title = 'Child function';
  824. }
  825. if (count($results) > 1) {
  826. $title .= 's';
  827. }
  828. print("<tr bgcolor='#e0e0ff'><td>");
  829. print("<b><i><center>" . $title . "</center></i></b>");
  830. print("</td></tr>");
  831. $odd_even = 0;
  832. foreach ($results as $info) {
  833. $href = "$base_path/?" .
  834. http_build_query(xhprof_array_set($url_params,
  835. 'symbol', $info["fn"]));
  836. $odd_even = 1 - $odd_even;
  837. if ($odd_even) {
  838. print('<tr>');
  839. }
  840. else {
  841. print('<tr bgcolor="#e5e5e5">');
  842. }
  843. print("<td>" . xhprof_render_link($info["fn"], $href));
  844. print_source_link($info);
  845. print("</td>");
  846. pc_info($info, $base_ct, $base_info, $parent);
  847. print("</tr>");
  848. }
  849. }
  850. function print_source_link($info) {
  851. if (strncmp($info['fn'], 'run_init', 8) && $info['fn'] !== 'main()') {
  852. if (defined('XHPROF_SYMBOL_LOOKUP_URL')) {
  853. $link = xhprof_render_link(
  854. 'source',
  855. XHPROF_SYMBOL_LOOKUP_URL . '?symbol='.rawurlencode($info["fn"]));
  856. print(' ('.$link.')');
  857. }
  858. }
  859. }
  860. function print_symbol_summary($symbol_info, $stat, $base) {
  861. $val = $symbol_info[$stat];
  862. $desc = str_replace("<br>", " ", stat_description($stat));
  863. print("$desc: </td>");
  864. print(number_format($val));
  865. print(" (" . pct($val, $base) . "% of overall)");
  866. if (substr($stat, 0, 4) == "excl") {
  867. $func_base = $symbol_info[str_replace("excl_", "", $stat)];
  868. print(" (" . pct($val, $func_base) . "% of this function)");
  869. }
  870. print("<br>");
  871. }
  872. /**
  873. * Generates a report for a single function/symbol.
  874. *
  875. * @author Kannan
  876. */
  877. function symbol_report($url_params,
  878. $run_data, $symbol_info, $sort, $rep_symbol,
  879. $run1,
  880. $symbol_info1 = null,
  881. $run2 = 0,
  882. $symbol_info2 = null) {
  883. global $vwbar;
  884. global $vbar;
  885. global $totals;
  886. global $pc_stats;
  887. global $sortable_columns;
  888. global $metrics;
  889. global $diff_mode;
  890. global $descriptions;
  891. global $format_cbk;
  892. global $sort_col;
  893. global $display_calls;
  894. global $base_path;
  895. $possible_metrics = xhprof_get_possible_metrics();
  896. if ($diff_mode) {
  897. $diff_text = "<b>Diff</b>";
  898. $regr_impr = "<i style='color:red'>Regression</i>/<i style='color:green'>Improvement</i>";
  899. } else {
  900. $diff_text = "";
  901. $regr_impr = "";
  902. }
  903. if ($diff_mode) {
  904. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  905. 'run1'),
  906. 'run2');
  907. $href1 = "$base_path?"
  908. . http_build_query(xhprof_array_set($base_url_params, 'run', $run1));
  909. $href2 = "$base_path?"
  910. . http_build_query(xhprof_array_set($base_url_params, 'run', $run2));
  911. print("<h3 align=center>$regr_impr summary for $rep_symbol<br><br></h3>");
  912. print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
  913. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  914. print('<tr bgcolor="#bdc7d8" align=right>');
  915. print("<th align=left>$rep_symbol</th>");
  916. print("<th $vwbar><a href=" . $href1 . ">Run #$run1</a></th>");
  917. print("<th $vwbar><a href=" . $href2 . ">Run #$run2</a></th>");
  918. print("<th $vwbar>Diff</th>");
  919. print("<th $vwbar>Diff%</th>");
  920. print('</tr>');
  921. print('<tr>');
  922. if ($display_calls) {
  923. print("<td>Number of Function Calls</td>");
  924. print_td_num($symbol_info1["ct"], $format_cbk["ct"]);
  925. print_td_num($symbol_info2["ct"], $format_cbk["ct"]);
  926. print_td_num($symbol_info2["ct"] - $symbol_info1["ct"],
  927. $format_cbk["ct"], true);
  928. print_td_pct($symbol_info2["ct"] - $symbol_info1["ct"],
  929. $symbol_info1["ct"], true);
  930. print('</tr>');
  931. }
  932. foreach ($metrics as $metric) {
  933. $m = $metric;
  934. // Inclusive stat for metric
  935. print('<tr>');
  936. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  937. print_td_num($symbol_info1[$m], $format_cbk[$m]);
  938. print_td_num($symbol_info2[$m], $format_cbk[$m]);
  939. print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
  940. print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
  941. print('</tr>');
  942. // AVG (per call) Inclusive stat for metric
  943. print('<tr>');
  944. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . " per call </td>");
  945. $avg_info1 = 'N/A';
  946. $avg_info2 = 'N/A';
  947. if ($symbol_info1['ct'] > 0) {
  948. $avg_info1 = ($symbol_info1[$m] / $symbol_info1['ct']);
  949. }
  950. if ($symbol_info2['ct'] > 0) {
  951. $avg_info2 = ($symbol_info2[$m] / $symbol_info2['ct']);
  952. }
  953. print_td_num($avg_info1, $format_cbk[$m]);
  954. print_td_num($avg_info2, $format_cbk[$m]);
  955. print_td_num($avg_info2 - $avg_info1, $format_cbk[$m], true);
  956. print_td_pct($avg_info2 - $avg_info1, $avg_info1, true);
  957. print('</tr>');
  958. // Exclusive stat for metric
  959. $m = "excl_" . $metric;
  960. print('<tr style="border-bottom: 1px solid black;">');
  961. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  962. print_td_num($symbol_info1[$m], $format_cbk[$m]);
  963. print_td_num($symbol_info2[$m], $format_cbk[$m]);
  964. print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
  965. print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
  966. print('</tr>');
  967. }
  968. print('</table>');
  969. }
  970. print("<br><h4><center>");
  971. print("Parent/Child $regr_impr report for <b>$rep_symbol</b>");
  972. $callgraph_href = "$base_path/callgraph.php?"
  973. . http_build_query(xhprof_array_set($url_params, 'func', $rep_symbol));
  974. print(" <a href='$callgraph_href'>[View Callgraph $diff_text]</a><br>");
  975. print("</center></h4><br>");
  976. print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
  977. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  978. print('<tr bgcolor="#bdc7d8" align=right>');
  979. foreach ($pc_stats as $stat) {
  980. $desc = stat_description($stat);
  981. if (array_key_exists($stat, $sortable_columns)) {
  982. $href = "$base_path/?" .
  983. http_build_query(xhprof_array_set($url_params,
  984. 'sort', $stat));
  985. $header = xhprof_render_link($desc, $href);
  986. } else {
  987. $header = $desc;
  988. }
  989. if ($stat == "fn")
  990. print("<th align=left><nobr>$header</th>");
  991. else print("<th " . $vwbar . "><nobr>$header</th>");
  992. }
  993. print("</tr>");
  994. print("<tr bgcolor='#e0e0ff'><td>");
  995. print("<b><i><center>Current Function</center></i></b>");
  996. print("</td></tr>");
  997. print("<tr>");
  998. // make this a self-reference to facilitate copy-pasting snippets to e-mails
  999. print("<td><a href=''>$rep_symbol</a>");
  1000. print_source_link(array('fn' => $rep_symbol));
  1001. print("</td>");
  1002. if ($display_calls) {
  1003. // Call Count
  1004. print_td_num($symbol_info["ct"], $format_cbk["ct"]);
  1005. print_td_pct($symbol_info["ct"], $totals["ct"]);
  1006. }
  1007. // Inclusive Metrics for current function
  1008. foreach ($metrics as $metric) {
  1009. print_td_num($symbol_info[$metric], $format_cbk[$metric], ($sort_col == $metric));
  1010. print_td_pct($symbol_info[$metric], $totals[$metric], ($sort_col == $metric));
  1011. }
  1012. print("</tr>");
  1013. print("<tr bgcolor='#ffffff'>");
  1014. print("<td style='text-align:right;color:blue'>"
  1015. ."Exclusive Metrics $diff_text for Current Function</td>");
  1016. if ($display_calls) {
  1017. // Call Count
  1018. print("<td $vbar></td>");
  1019. print("<td $vbar></td>");
  1020. }
  1021. // Exclusive Metrics for current function
  1022. foreach ($metrics as $metric) {
  1023. print_td_num($symbol_info["excl_" . $metric], $format_cbk["excl_" . $metric],
  1024. ($sort_col == $metric),
  1025. get_tooltip_attributes("Child", $metric));
  1026. print_td_pct($symbol_info["excl_" . $metric], $symbol_info[$metric],
  1027. ($sort_col == $metric),
  1028. get_tooltip_attributes("Child", $metric));
  1029. }
  1030. print("</tr>");
  1031. // list of callers/parent functions
  1032. $results = array();
  1033. if ($display_calls) {
  1034. $base_ct = $symbol_info["ct"];
  1035. } else {
  1036. $base_ct = 0;
  1037. }
  1038. foreach ($metrics as $metric) {
  1039. $base_info[$metric] = $symbol_info[$metric];
  1040. }
  1041. foreach ($run_data as $parent_child => $info) {
  1042. list($parent, $child) = xhprof_parse_parent_child($parent_child);
  1043. if (($child == $rep_symbol) && ($parent)) {
  1044. $info_tmp = $info;
  1045. $info_tmp["fn"] = $parent;
  1046. $results[] = $info_tmp;
  1047. }
  1048. }
  1049. usort($results, 'sort_cbk');
  1050. if (count($results) > 0) {
  1051. print_pc_array($url_params, $results, $base_ct, $base_info, true,
  1052. $run1, $run2);
  1053. }
  1054. // list of callees/child functions
  1055. $results = array();
  1056. $base_ct = 0;
  1057. foreach ($run_data as $parent_child => $info) {
  1058. list($parent, $child) = xhprof_parse_parent_child($parent_child);
  1059. if ($parent == $rep_symbol) {
  1060. $info_tmp = $info;
  1061. $info_tmp["fn"] = $child;
  1062. $results[] = $info_tmp;
  1063. if ($display_calls) {
  1064. $base_ct += $info["ct"];
  1065. }
  1066. }
  1067. }
  1068. usort($results, 'sort_cbk');
  1069. if (count($results)) {
  1070. print_pc_array($url_params, $results, $base_ct, $base_info, false,
  1071. $run1, $run2);
  1072. }
  1073. print("</table>");
  1074. // These will be used for pop-up tips/help.
  1075. // Related javascript code is in: xhprof_report.js
  1076. print("\n");
  1077. print('<script language="javascript">' . "\n");
  1078. print("var func_name = '\"" . $rep_symbol . "\"';\n");
  1079. print("var total_child_ct = " . $base_ct . ";\n");
  1080. if ($display_calls) {
  1081. print("var func_ct = " . $symbol_info["ct"] . ";\n");
  1082. }
  1083. print("var func_metrics = new Array();\n");
  1084. print("var metrics_col = new Array();\n");
  1085. print("var metrics_desc = new Array();\n");
  1086. if ($diff_mode) {
  1087. print("var diff_mode = true;\n");
  1088. } else {
  1089. print("var diff_mode = false;\n");
  1090. }
  1091. $column_index = 3; // First three columns are Func Name, Calls, Calls%
  1092. foreach ($metrics as $metric) {
  1093. print("func_metrics[\"" . $metric . "\"] = " . round($symbol_info[$metric]) . ";\n");
  1094. print("metrics_col[\"". $metric . "\"] = " . $column_index . ";\n");
  1095. print("metrics_desc[\"". $metric . "\"] = \"" . $possible_metrics[$metric][2] . "\";\n");
  1096. // each metric has two columns..
  1097. $column_index += 2;
  1098. }
  1099. print('</script>');
  1100. print("\n");
  1101. }
  1102. /**
  1103. * Generate the profiler report for a single run.
  1104. *
  1105. * @author Kannan
  1106. */
  1107. function profiler_single_run_report ($url_params,
  1108. $xhprof_data,
  1109. $run_desc,
  1110. $rep_symbol,
  1111. $sort,
  1112. $run) {
  1113. init_metrics($xhprof_data, $rep_symbol, $sort, false);
  1114. profiler_report($url_params, $rep_symbol, $sort, $run, $run_desc,
  1115. $xhprof_data);
  1116. }
  1117. /**
  1118. * Generate the profiler report for diff mode (delta between two runs).
  1119. *
  1120. * @author Kannan
  1121. */
  1122. function profiler_diff_report($url_params,
  1123. $xhprof_data1,
  1124. $run1_desc,
  1125. $xhprof_data2,
  1126. $run2_desc,
  1127. $rep_symbol,
  1128. $sort,
  1129. $run1,
  1130. $run2) {
  1131. // Initialize what metrics we'll display based on data in Run2
  1132. init_metrics($xhprof_data2, $rep_symbol, $sort, true);
  1133. profiler_report($url_params,
  1134. $rep_symbol,
  1135. $sort,
  1136. $run1,
  1137. $run1_desc,
  1138. $xhprof_data1,
  1139. $run2,
  1140. $run2_desc,
  1141. $xhprof_data2);
  1142. }
  1143. /**
  1144. * Generate a XHProf Display View given the various URL parameters
  1145. * as arguments. The first argument is an object that implements
  1146. * the iXHProfRuns interface.
  1147. *
  1148. * @param object $xhprof_runs_impl An object that implements
  1149. * the iXHProfRuns interface
  1150. *.
  1151. * @param array $url_params Array of non-default URL params.
  1152. *
  1153. * @param string $source Category/type of the run. The source in
  1154. * combination with the run id uniquely
  1155. * determines a profiler run.
  1156. *
  1157. * @param string $run run id, or comma separated sequence of
  1158. * run ids. The latter is used if an aggregate
  1159. * report of the runs is desired.
  1160. *
  1161. * @param string $wts Comma separate list of integers.
  1162. * Represents the weighted ratio in
  1163. * which which a set of runs will be
  1164. * aggregated. [Used only for aggregate
  1165. * reports.]
  1166. *
  1167. * @param string $symbol Function symbol. If non-empty then the
  1168. * parent/child view of this function is
  1169. * displayed. If empty, a flat-profile view
  1170. * of the functions is displayed.
  1171. *
  1172. * @param string $run1 Base run id (for diff reports)
  1173. *
  1174. * @param string $run2 New run id (for diff reports)
  1175. *
  1176. */
  1177. function displayXHProfReport($xhprof_runs_impl, $url_params, $source,
  1178. $run, $wts, $symbol, $sort, $run1, $run2) {
  1179. if ($run) { // specific run to display?
  1180. // run may be a single run or a comma separate list of runs
  1181. // that'll be aggregated. If "wts" (a comma separated list
  1182. // of integral weights is specified), the runs will be
  1183. // aggregated in that ratio.
  1184. //
  1185. $runs_array = explode(",", $run);
  1186. if (count($runs_array) == 1) {
  1187. $xhprof_data = $xhprof_runs_impl->get_run($runs_array[0],
  1188. $source,
  1189. $description);
  1190. } else {
  1191. if (!empty($wts)) {
  1192. $wts_array = explode(",", $wts);
  1193. } else {
  1194. $wts_array = null;
  1195. }
  1196. $data = xhprof_aggregate_runs($xhprof_runs_impl,
  1197. $runs_array, $wts_array, $source, false);
  1198. $xhprof_data = $data['raw'];
  1199. $description = $data['description'];
  1200. }
  1201. profiler_single_run_report($url_params,
  1202. $xhprof_data,
  1203. $description,
  1204. $symbol,
  1205. $sort,
  1206. $run);
  1207. } else if ($run1 && $run2) { // diff report for two runs
  1208. $xhprof_data1 = $xhprof_runs_impl->get_run($run1, $source, $description1);
  1209. $xhprof_data2 = $xhprof_runs_impl->get_run($run2, $source, $description2);
  1210. profiler_diff_report($url_params,
  1211. $xhprof_data1,
  1212. $description1,
  1213. $xhprof_data2,
  1214. $description2,
  1215. $symbol,
  1216. $sort,
  1217. $run1,
  1218. $run2);
  1219. } else {
  1220. echo "No XHProf runs specified in the URL.";
  1221. if (method_exists($xhprof_runs_impl, 'list_runs')) {
  1222. $xhprof_runs_impl->list_runs();
  1223. }
  1224. }
  1225. }