xhprof.php 44 KB

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