xhprof.php 45 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499
  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(dirname(__FILE__) . '/..');
  32. }
  33. include_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/xhprof_lib.php';
  34. include_once $GLOBALS['XHPROF_LIB_ROOT'].'/utils/callgraph_utils.php';
  35. include_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'></link>";
  58. echo "<link href='$ui_dir_url_path/jquery/jquery.tooltip.css' ".
  59. " rel='stylesheet' type='text/css'></link>";
  60. echo "<link href='$ui_dir_url_path/jquery/jquery.autocomplete.css' ".
  61. " rel='stylesheet' type='text/css'></link>";
  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. {
  327. global $sort_col;
  328. global $diff_mode;
  329. if ($sort_col == "fn") {
  330. // case insensitive ascending sort for function names
  331. $left = strtoupper($a["fn"]);
  332. $right = strtoupper($b["fn"]);
  333. if ($left == $right)
  334. return 0;
  335. return ($left < $right) ? -1 : 1;
  336. } else {
  337. // descending sort for all others
  338. $left = $a[$sort_col];
  339. $right = $b[$sort_col];
  340. // if diff mode, sort by absolute value of regression/improvement
  341. if ($diff_mode) {
  342. $left = abs($left);
  343. $right = abs($right);
  344. }
  345. if ($left == $right)
  346. return 0;
  347. return ($left > $right) ? -1 : 1;
  348. }
  349. }
  350. /**
  351. * Initialize the metrics we'll display based on the information
  352. * in the raw data.
  353. *
  354. * @author Kannan
  355. */
  356. function init_metrics($xhprof_data, $rep_symbol, $sort, $diff_report = false) {
  357. global $stats;
  358. global $pc_stats;
  359. global $metrics;
  360. global $diff_mode;
  361. global $sortable_columns;
  362. global $sort_col;
  363. global $display_calls;
  364. $diff_mode = $diff_report;
  365. if (!empty($sort)) {
  366. if (array_key_exists($sort, $sortable_columns)) {
  367. $sort_col = $sort;
  368. } else {
  369. print("Invalid Sort Key $sort specified in URL");
  370. }
  371. }
  372. // For C++ profiler runs, walltime attribute isn't present.
  373. // In that case, use "samples" as the default sort column.
  374. if (!isset($xhprof_data["main()"]["wt"])) {
  375. if ($sort_col == "wt") {
  376. $sort_col = "samples";
  377. }
  378. // C++ profiler data doesn't have call counts.
  379. // ideally we should check to see if "ct" metric
  380. // is present for "main()". But currently "ct"
  381. // metric is artificially set to 1. So, relying
  382. // on absence of "wt" metric instead.
  383. $display_calls = false;
  384. } else {
  385. $display_calls = true;
  386. }
  387. // parent/child report doesn't support exclusive times yet.
  388. // So, change sort hyperlinks to closest fit.
  389. if (!empty($rep_symbol)) {
  390. $sort_col = str_replace("excl_", "", $sort_col);
  391. }
  392. if ($display_calls) {
  393. $stats = array("fn", "ct", "Calls%");
  394. } else {
  395. $stats = array("fn");
  396. }
  397. $pc_stats = $stats;
  398. $possible_metrics = xhprof_get_possible_metrics($xhprof_data);
  399. foreach ($possible_metrics as $metric => $desc) {
  400. if (isset($xhprof_data["main()"][$metric])) {
  401. $metrics[] = $metric;
  402. // flat (top-level reports): we can compute
  403. // exclusive metrics reports as well.
  404. $stats[] = $metric;
  405. $stats[] = "I" . $desc[0] . "%";
  406. $stats[] = "excl_" . $metric;
  407. $stats[] = "E" . $desc[0] . "%";
  408. // parent/child report for a function: we can
  409. // only breakdown inclusive times correctly.
  410. $pc_stats[] = $metric;
  411. $pc_stats[] = "I" . $desc[0] . "%";
  412. }
  413. }
  414. }
  415. /**
  416. * Get the appropriate description for a statistic
  417. * (depending upon whether we are in diff report mode
  418. * or single run report mode).
  419. *
  420. * @author Kannan
  421. */
  422. function stat_description($stat) {
  423. global $descriptions;
  424. global $diff_descriptions;
  425. global $diff_mode;
  426. if ($diff_mode) {
  427. return $diff_descriptions[$stat];
  428. } else {
  429. return $descriptions[$stat];
  430. }
  431. }
  432. /**
  433. * Analyze raw data & generate the profiler report
  434. * (common for both single run mode and diff mode).
  435. *
  436. * @author: Kannan
  437. */
  438. function profiler_report ($url_params,
  439. $rep_symbol,
  440. $sort,
  441. $run1,
  442. $run1_desc,
  443. $run1_data,
  444. $run2 = 0,
  445. $run2_desc = "",
  446. $run2_data = array()) {
  447. global $totals;
  448. global $totals_1;
  449. global $totals_2;
  450. global $stats;
  451. global $pc_stats;
  452. global $diff_mode;
  453. global $base_path;
  454. // if we are reporting on a specific function, we can trim down
  455. // the report(s) to just stuff that is relevant to this function.
  456. // That way compute_flat_info()/compute_diff() etc. do not have
  457. // to needlessly work hard on churning irrelevant data.
  458. if (!empty($rep_symbol)) {
  459. $run1_data = xhprof_trim_run($run1_data, array($rep_symbol));
  460. if ($diff_mode) {
  461. $run2_data = xhprof_trim_run($run2_data, array($rep_symbol));
  462. }
  463. }
  464. if ($diff_mode) {
  465. $run_delta = xhprof_compute_diff($run1_data, $run2_data);
  466. $symbol_tab = xhprof_compute_flat_info($run_delta, $totals);
  467. $symbol_tab1 = xhprof_compute_flat_info($run1_data, $totals_1);
  468. $symbol_tab2 = xhprof_compute_flat_info($run2_data, $totals_2);
  469. } else {
  470. $symbol_tab = xhprof_compute_flat_info($run1_data, $totals);
  471. }
  472. $run1_txt = sprintf("<b>Run #%s:</b> %s",
  473. $run1, $run1_desc);
  474. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  475. 'symbol'),
  476. 'all');
  477. $top_link_query_string = "$base_path/?" . http_build_query($base_url_params);
  478. if ($diff_mode) {
  479. $diff_text = "Diff";
  480. $base_url_params = xhprof_array_unset($base_url_params, 'run1');
  481. $base_url_params = xhprof_array_unset($base_url_params, 'run2');
  482. $run1_link = xhprof_render_link('View Run #' . $run1,
  483. "$base_path/?" .
  484. http_build_query(xhprof_array_set($base_url_params,
  485. 'run',
  486. $run1)));
  487. $run2_txt = sprintf("<b>Run #%s:</b> %s",
  488. $run2, $run2_desc);
  489. $run2_link = xhprof_render_link('View Run #' . $run2,
  490. "$base_path/?" .
  491. http_build_query(xhprof_array_set($base_url_params,
  492. 'run',
  493. $run2)));
  494. } else {
  495. $diff_text = "Run";
  496. }
  497. // set up the action links for operations that can be done on this report
  498. $links = array();
  499. $links []= xhprof_render_link("View Top Level $diff_text Report",
  500. $top_link_query_string);
  501. if ($diff_mode) {
  502. $inverted_params = $url_params;
  503. $inverted_params['run1'] = $url_params['run2'];
  504. $inverted_params['run2'] = $url_params['run1'];
  505. // view the different runs or invert the current diff
  506. $links []= $run1_link;
  507. $links []= $run2_link;
  508. $links []= xhprof_render_link('Invert ' . $diff_text . ' Report',
  509. "$base_path/?".
  510. http_build_query($inverted_params));
  511. }
  512. // lookup function typeahead form
  513. $links [] = '<input class="function_typeahead" ' .
  514. ' type="input" size="40" maxlength="100" />';
  515. echo xhprof_render_actions($links);
  516. echo
  517. '<dl class=phprof_report_info>' .
  518. ' <dt>' . $diff_text . ' Report</dt>' .
  519. ' <dd>' . ($diff_mode ?
  520. $run1_txt . '<br><b>vs.</b><br>' . $run2_txt :
  521. $run1_txt) .
  522. ' </dd>' .
  523. ' <dt>Tip</dt>' .
  524. ' <dd>Click a function name below to drill down.</dd>' .
  525. '</dl>' .
  526. '<div style="clear: both; margin: 3em 0em;"></div>';
  527. // data tables
  528. if (!empty($rep_symbol)) {
  529. if (!isset($symbol_tab[$rep_symbol])) {
  530. echo "<hr>Symbol <b>$rep_symbol</b> not found in XHProf run</b><hr>";
  531. return;
  532. }
  533. /* single function report with parent/child information */
  534. if ($diff_mode) {
  535. $info1 = isset($symbol_tab1[$rep_symbol]) ?
  536. $symbol_tab1[$rep_symbol] : null;
  537. $info2 = isset($symbol_tab2[$rep_symbol]) ?
  538. $symbol_tab2[$rep_symbol] : null;
  539. symbol_report($url_params, $run_delta, $symbol_tab[$rep_symbol],
  540. $sort, $rep_symbol,
  541. $run1, $info1,
  542. $run2, $info2);
  543. } else {
  544. symbol_report($url_params, $run1_data, $symbol_tab[$rep_symbol],
  545. $sort, $rep_symbol, $run1);
  546. }
  547. } else {
  548. /* flat top-level report of all functions */
  549. full_report($url_params, $symbol_tab, $sort, $run1, $run2);
  550. }
  551. }
  552. /**
  553. * Computes percentage for a pair of values, and returns it
  554. * in string format.
  555. */
  556. function pct($a, $b) {
  557. if ($b == 0) {
  558. return "N/A";
  559. } else {
  560. $res = (round(($a * 1000 / $b)) / 10);
  561. return $res;
  562. }
  563. }
  564. /**
  565. * Given a number, returns the td class to use for display.
  566. *
  567. * For instance, negative numbers in diff reports comparing two runs (run1 & run2)
  568. * represent improvement from run1 to run2. We use green to display those deltas,
  569. * and red for regression deltas.
  570. */
  571. function get_print_class($num, $bold) {
  572. global $vbar;
  573. global $vbbar;
  574. global $vrbar;
  575. global $vgbar;
  576. global $diff_mode;
  577. if ($bold) {
  578. if ($diff_mode) {
  579. if ($num <= 0) {
  580. $class = $vgbar; // green (improvement)
  581. } else {
  582. $class = $vrbar; // red (regression)
  583. }
  584. } else {
  585. $class = $vbbar; // blue
  586. }
  587. }
  588. else {
  589. $class = $vbar; // default (black)
  590. }
  591. return $class;
  592. }
  593. /**
  594. * Prints a <td> element with a numeric value.
  595. */
  596. function print_td_num($num, $fmt_func, $bold=false, $attributes=null) {
  597. $class = get_print_class($num, $bold);
  598. if (!empty($fmt_func)) {
  599. $num = call_user_func($fmt_func, $num);
  600. }
  601. print("<td $attributes $class>$num</td>\n");
  602. }
  603. /**
  604. * Prints a <td> element with a pecentage.
  605. */
  606. function print_td_pct($numer, $denom, $bold=false, $attributes=null) {
  607. global $vbar;
  608. global $vbbar;
  609. global $diff_mode;
  610. $class = get_print_class($numer, $bold);
  611. if ($denom == 0) {
  612. $pct = "N/A%";
  613. } else {
  614. $pct = xhprof_percent_format($numer / abs($denom));
  615. }
  616. print("<td $attributes $class>$pct</td>\n");
  617. }
  618. /**
  619. * Print "flat" data corresponding to one function.
  620. *
  621. * @author Kannan
  622. */
  623. function print_function_info($url_params, $info, $sort, $run1, $run2) {
  624. static $odd_even = 0;
  625. global $totals;
  626. global $sort_col;
  627. global $metrics;
  628. global $format_cbk;
  629. global $display_calls;
  630. global $base_path;
  631. // Toggle $odd_or_even
  632. $odd_even = 1 - $odd_even;
  633. if ($odd_even) {
  634. print("<tr>");
  635. }
  636. else {
  637. print('<tr bgcolor="#e5e5e5">');
  638. }
  639. $href = "$base_path/?" .
  640. http_build_query(xhprof_array_set($url_params,
  641. 'symbol', $info["fn"]));
  642. print('<td>');
  643. print(xhprof_render_link($info["fn"], $href));
  644. print("</td>\n");
  645. if ($display_calls) {
  646. // Call Count..
  647. print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"));
  648. print_td_pct($info["ct"], $totals["ct"], ($sort_col == "ct"));
  649. }
  650. // Other metrics..
  651. foreach ($metrics as $metric) {
  652. // Inclusive metric
  653. print_td_num($info[$metric], $format_cbk[$metric],
  654. ($sort_col == $metric));
  655. print_td_pct($info[$metric], $totals[$metric],
  656. ($sort_col == $metric));
  657. // Exclusive Metric
  658. print_td_num($info["excl_" . $metric],
  659. $format_cbk["excl_" . $metric],
  660. ($sort_col == "excl_" . $metric));
  661. print_td_pct($info["excl_" . $metric],
  662. $totals[$metric],
  663. ($sort_col == "excl_" . $metric));
  664. }
  665. print("</tr>\n");
  666. }
  667. /**
  668. * Print non-hierarchical (flat-view) of profiler data.
  669. *
  670. * @author Kannan
  671. */
  672. function print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit) {
  673. global $stats;
  674. global $sortable_columns;
  675. global $vwbar;
  676. global $base_path;
  677. $size = count($flat_data);
  678. if (!$limit) { // no limit
  679. $limit = $size;
  680. $display_link = "";
  681. } else {
  682. $display_link = xhprof_render_link(" [ <b class=bubble>display all </b>]",
  683. "$base_path/?" .
  684. http_build_query(xhprof_array_set($url_params,
  685. 'all', 1)));
  686. }
  687. print("<h3 align=center>$title $display_link</h3><br>");
  688. print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
  689. .'rules=rows bordercolor="#bdc7d8" align=center>');
  690. print('<tr bgcolor="#bdc7d8" align=right>');
  691. foreach ($stats as $stat) {
  692. $desc = stat_description($stat);
  693. if (array_key_exists($stat, $sortable_columns)) {
  694. $href = "$base_path/?"
  695. . http_build_query(xhprof_array_set($url_params, 'sort', $stat));
  696. $header = xhprof_render_link($desc, $href);
  697. } else {
  698. $header = $desc;
  699. }
  700. if ($stat == "fn")
  701. print("<th align=left><nobr>$header</th>");
  702. else
  703. print("<th " . $vwbar . "><nobr>$header</th>");
  704. }
  705. print("</tr>\n");
  706. if ($limit >= 0) {
  707. $limit = min($size, $limit);
  708. for($i=0; $i < $limit; $i++) {
  709. print_function_info($url_params, $flat_data[$i], $sort, $run1, $run2);
  710. }
  711. } else {
  712. // if $limit is negative, print abs($limit) items starting from the end
  713. $limit = min($size, abs($limit));
  714. for($i=0; $i < $limit; $i++) {
  715. print_function_info($url_params, $flat_data[$size - $i - 1], $sort, $run1, $run2);
  716. }
  717. }
  718. print("</table>");
  719. // let's print the display all link at the bottom as well...
  720. if ($display_link) {
  721. echo '<div style="text-align: left; padding: 2em">' . $display_link . '</div>';
  722. }
  723. }
  724. /**
  725. * Generates a tabular report for all functions. This is the top-level report.
  726. *
  727. * @author Kannan
  728. */
  729. function full_report($url_params, $symbol_tab, $sort, $run1, $run2) {
  730. global $vwbar;
  731. global $vbar;
  732. global $totals;
  733. global $totals_1;
  734. global $totals_2;
  735. global $metrics;
  736. global $diff_mode;
  737. global $descriptions;
  738. global $sort_col;
  739. global $format_cbk;
  740. global $display_calls;
  741. global $base_path;
  742. $possible_metrics = xhprof_get_possible_metrics();
  743. if ($diff_mode) {
  744. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  745. 'run1'),
  746. 'run2');
  747. $href1 = "$base_path/?" .
  748. http_build_query(xhprof_array_set($base_url_params,
  749. 'run', $run1));
  750. $href2 = "$base_path/?" .
  751. http_build_query(xhprof_array_set($base_url_params,
  752. 'run', $run2));
  753. print("<h3><center>Overall Diff Summary</center></h3>");
  754. print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
  755. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  756. print('<tr bgcolor="#bdc7d8" align=right>');
  757. print("<th></th>");
  758. print("<th $vwbar>" . xhprof_render_link("Run #$run1", $href1) . "</th>");
  759. print("<th $vwbar>" . xhprof_render_link("Run #$run2", $href2) . "</th>");
  760. print("<th $vwbar>Diff</th>");
  761. print("<th $vwbar>Diff%</th>");
  762. print('</tr>');
  763. if ($display_calls) {
  764. print('<tr>');
  765. print("<td>Number of Function Calls</td>");
  766. print_td_num($totals_1["ct"], $format_cbk["ct"]);
  767. print_td_num($totals_2["ct"], $format_cbk["ct"]);
  768. print_td_num($totals_2["ct"] - $totals_1["ct"], $format_cbk["ct"], true);
  769. print_td_pct($totals_2["ct"] - $totals_1["ct"], $totals_1["ct"], true);
  770. print('</tr>');
  771. }
  772. foreach ($metrics as $metric) {
  773. $m = $metric;
  774. print('<tr>');
  775. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  776. print_td_num($totals_1[$m], $format_cbk[$m]);
  777. print_td_num($totals_2[$m], $format_cbk[$m]);
  778. print_td_num($totals_2[$m] - $totals_1[$m], $format_cbk[$m], true);
  779. print_td_pct($totals_2[$m] - $totals_1[$m], $totals_1[$m], true);
  780. print('<tr>');
  781. }
  782. print('</table>');
  783. $callgraph_report_title = '[View Regressions/Improvements using Callgraph Diff]';
  784. } else {
  785. print("<p><center>\n");
  786. print('<table cellpadding=2 cellspacing=1 width="30%" '
  787. .'bgcolor="#bdc7d8" align=center>' . "\n");
  788. echo "<tr>";
  789. echo "<th style='text-align:right'>Overall Summary</th>";
  790. echo "<th'></th>";
  791. echo "</tr>";
  792. foreach ($metrics as $metric) {
  793. echo "<tr>";
  794. echo "<td style='text-align:right; font-weight:bold'>Total "
  795. . str_replace("<br>", " ", stat_description($metric)) . ":</td>";
  796. echo "<td>" . number_format($totals[$metric]) . " "
  797. . $possible_metrics[$metric][1] . "</td>";
  798. echo "</tr>";
  799. }
  800. if ($display_calls) {
  801. echo "<tr>";
  802. echo "<td style='text-align:right; font-weight:bold'>Number of Function Calls:</td>";
  803. echo "<td>" . number_format($totals['ct']) . "</td>";
  804. echo "</tr>";
  805. }
  806. echo "</table>";
  807. print("</center></p>\n");
  808. $callgraph_report_title = '[View Full Callgraph]';
  809. }
  810. print("<center><br><h3>" .
  811. xhprof_render_link($callgraph_report_title,
  812. "$base_path/callgraph.php" . "?" . http_build_query($url_params))
  813. . "</h3></center>");
  814. $flat_data = array();
  815. foreach ($symbol_tab as $symbol => $info) {
  816. $tmp = $info;
  817. $tmp["fn"] = $symbol;
  818. $flat_data[] = $tmp;
  819. }
  820. usort($flat_data, 'sort_cbk');
  821. print("<br>");
  822. if (!empty($url_params['all'])) {
  823. $all = true;
  824. $limit = 0; // display all rows
  825. } else {
  826. $all = false;
  827. $limit = 100; // display only limited number of rows
  828. }
  829. $desc = str_replace("<br>", " ", $descriptions[$sort_col]);
  830. if ($diff_mode) {
  831. if ($all) {
  832. $title = "Total Diff Report: '
  833. .'Sorted by absolute value of regression/improvement in $desc";
  834. } else {
  835. $title = "Top 100 <i style='color:red'>Regressions</i>/"
  836. . "<i style='color:green'>Improvements</i>: "
  837. . "Sorted by $desc Diff";
  838. }
  839. } else {
  840. if ($all) {
  841. $title = "Sorted by $desc";
  842. } else {
  843. $title = "Displaying top $limit functions: Sorted by $desc";
  844. }
  845. }
  846. print_flat_data($url_params, $title, $flat_data, $sort, $run1, $run2, $limit);
  847. }
  848. /**
  849. * Return attribute names and values to be used by javascript tooltip.
  850. */
  851. function get_tooltip_attributes($type, $metric) {
  852. return "type='$type' metric='$metric'";
  853. }
  854. /**
  855. * Print info for a parent or child function in the
  856. * parent & children report.
  857. *
  858. * @author Kannan
  859. */
  860. function pc_info($info, $base_ct, $base_info, $parent) {
  861. global $sort_col;
  862. global $metrics;
  863. global $format_cbk;
  864. global $display_calls;
  865. if ($parent)
  866. $type = "Parent";
  867. else
  868. $type = "Child";
  869. if ($display_calls) {
  870. $mouseoverct = get_tooltip_attributes($type, "ct");
  871. /* call count */
  872. print_td_num($info["ct"], $format_cbk["ct"], ($sort_col == "ct"), $mouseoverct);
  873. print_td_pct($info["ct"], $base_ct, ($sort_col == "ct"), $mouseoverct);
  874. }
  875. /* Inclusive metric values */
  876. foreach ($metrics as $metric) {
  877. print_td_num($info[$metric], $format_cbk[$metric],
  878. ($sort_col == $metric),
  879. get_tooltip_attributes($type, $metric));
  880. print_td_pct($info[$metric], $base_info[$metric], ($sort_col == $metric),
  881. get_tooltip_attributes($type, $metric));
  882. }
  883. }
  884. function print_pc_array($url_params, $results, $base_ct, $base_info, $parent,
  885. $run1, $run2) {
  886. global $base_path;
  887. // Construct section title
  888. if ($parent) {
  889. $title = 'Parent function';
  890. }
  891. else {
  892. $title = 'Child function';
  893. }
  894. if (count($results) > 1) {
  895. $title .= 's';
  896. }
  897. print("<tr bgcolor='#e0e0ff'><td>");
  898. print("<b><i><center>" . $title . "</center></i></b>");
  899. print("</td></tr>");
  900. $odd_even = 0;
  901. foreach ($results as $info) {
  902. $href = "$base_path/?" .
  903. http_build_query(xhprof_array_set($url_params,
  904. 'symbol', $info["fn"]));
  905. $odd_even = 1 - $odd_even;
  906. if ($odd_even) {
  907. print('<tr>');
  908. }
  909. else {
  910. print('<tr bgcolor="#e5e5e5">');
  911. }
  912. print("<td>" . xhprof_render_link($info["fn"], $href) . "</td>");
  913. pc_info($info, $base_ct, $base_info, $parent);
  914. print("</tr>");
  915. }
  916. }
  917. function print_symbol_summary($symbol_info, $stat, $base) {
  918. $val = $symbol_info[$stat];
  919. $desc = str_replace("<br>", " ", stat_description($stat));
  920. print("$desc: </td>");
  921. print(number_format($val));
  922. print(" (" . pct($val, $base) . "% of overall)");
  923. if (substr($stat, 0, 4) == "excl") {
  924. $func_base = $symbol_info[str_replace("excl_", "", $stat)];
  925. print(" (" . pct($val, $func_base) . "% of this function)");
  926. }
  927. print("<br>");
  928. }
  929. /**
  930. * Generates a report for a single function/symbol.
  931. *
  932. * @author Kannan
  933. */
  934. function symbol_report($url_params,
  935. $run_data, $symbol_info, $sort, $rep_symbol,
  936. $run1,
  937. $symbol_info1 = null,
  938. $run2 = 0,
  939. $symbol_info2 = null) {
  940. global $vwbar;
  941. global $vbar;
  942. global $totals;
  943. global $pc_stats;
  944. global $sortable_columns;
  945. global $metrics;
  946. global $diff_mode;
  947. global $descriptions;
  948. global $format_cbk;
  949. global $sort_col;
  950. global $display_calls;
  951. global $base_path;
  952. $possible_metrics = xhprof_get_possible_metrics();
  953. if ($diff_mode) {
  954. $diff_text = "<b>Diff</b>";
  955. $regr_impr = "<i style='color:red'>Regression</i>/<i style='color:green'>Improvement</i>";
  956. } else {
  957. $diff_text = "";
  958. $regr_impr = "";
  959. }
  960. if ($diff_mode) {
  961. $base_url_params = xhprof_array_unset(xhprof_array_unset($url_params,
  962. 'run1'),
  963. 'run2');
  964. $href1 = "$base_path?"
  965. . http_build_query(xhprof_array_set($base_url_params, 'run', $run1));
  966. $href2 = "$base_path?"
  967. . http_build_query(xhprof_array_set($base_url_params, 'run', $run2));
  968. print("<h3 align=center>$regr_impr summary for $rep_symbol<br><br></h3>");
  969. print('<table border=1 cellpadding=2 cellspacing=1 width="30%" '
  970. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  971. print('<tr bgcolor="#bdc7d8" align=right>');
  972. print("<th align=left>$rep_symbol</th>");
  973. print("<th $vwbar><a href=" . $href1 . ">Run #$run1</a></th>");
  974. print("<th $vwbar><a href=" . $href2 . ">Run #$run2</a></th>");
  975. print("<th $vwbar>Diff</th>");
  976. print("<th $vwbar>Diff%</th>");
  977. print('</tr>');
  978. print('<tr>');
  979. if ($display_calls) {
  980. print("<td>Number of Function Calls</td>");
  981. print_td_num($symbol_info1["ct"], $format_cbk["ct"]);
  982. print_td_num($symbol_info2["ct"], $format_cbk["ct"]);
  983. print_td_num($symbol_info2["ct"] - $symbol_info1["ct"],
  984. $format_cbk["ct"], true);
  985. print_td_pct($symbol_info2["ct"] - $symbol_info1["ct"],
  986. $symbol_info1["ct"], true);
  987. print('</tr>');
  988. }
  989. foreach ($metrics as $metric) {
  990. $m = $metric;
  991. // Inclusive stat for metric
  992. print('<tr>');
  993. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  994. print_td_num($symbol_info1[$m], $format_cbk[$m]);
  995. print_td_num($symbol_info2[$m], $format_cbk[$m]);
  996. print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
  997. print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
  998. print('</tr>');
  999. // AVG (per call) Inclusive stat for metric
  1000. print('<tr>');
  1001. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . " per call </td>");
  1002. $avg_info1 = 'N/A';
  1003. $avg_info2 = 'N/A';
  1004. if ($symbol_info1['ct'] > 0) {
  1005. $avg_info1 = ($symbol_info1[$m]/$symbol_info1['ct']);
  1006. }
  1007. if ($symbol_info2['ct'] > 0) {
  1008. $avg_info2 = ($symbol_info2[$m]/$symbol_info2['ct']);
  1009. }
  1010. print_td_num($avg_info1, $format_cbk[$m]);
  1011. print_td_num($avg_info2, $format_cbk[$m]);
  1012. print_td_num($avg_info2 - $avg_info1, $format_cbk[$m], true);
  1013. print_td_pct($avg_info2 - $avg_info1, $avg_info1, true);
  1014. print('</tr>');
  1015. // Exclusive stat for metric
  1016. $m = "excl_" . $metric;
  1017. print('<tr style="border-bottom: 1px solid black;">');
  1018. print("<td>" . str_replace("<br>", " ", $descriptions[$m]) . "</td>");
  1019. print_td_num($symbol_info1[$m], $format_cbk[$m]);
  1020. print_td_num($symbol_info2[$m], $format_cbk[$m]);
  1021. print_td_num($symbol_info2[$m] - $symbol_info1[$m], $format_cbk[$m], true);
  1022. print_td_pct($symbol_info2[$m] - $symbol_info1[$m], $symbol_info1[$m], true);
  1023. print('</tr>');
  1024. }
  1025. print('</table>');
  1026. }
  1027. print("<br><h4><center>");
  1028. print("Parent/Child $regr_impr report for <b>$rep_symbol</b>");
  1029. $callgraph_href = "$base_path/callgraph.php?"
  1030. . http_build_query(xhprof_array_set($url_params, 'func', $rep_symbol));
  1031. print(" <a href='$callgraph_href'>[View Callgraph $diff_text]</a><br>");
  1032. print("</center></h4><br>");
  1033. print('<table border=1 cellpadding=2 cellspacing=1 width="90%" '
  1034. .'rules=rows bordercolor="#bdc7d8" align=center>' . "\n");
  1035. print('<tr bgcolor="#bdc7d8" align=right>');
  1036. foreach ($pc_stats as $stat) {
  1037. $desc = stat_description($stat);
  1038. if (array_key_exists($stat, $sortable_columns)) {
  1039. $href = "$base_path/?" .
  1040. http_build_query(xhprof_array_set($url_params,
  1041. 'sort', $stat));
  1042. $header = xhprof_render_link($desc, $href);
  1043. } else {
  1044. $header = $desc;
  1045. }
  1046. if ($stat == "fn")
  1047. print("<th align=left><nobr>$header</th>");
  1048. else
  1049. print("<th " . $vwbar . "><nobr>$header</th>");
  1050. }
  1051. print("</tr>");
  1052. print("<tr bgcolor='#e0e0ff'><td>");
  1053. print("<b><i><center>Current Function</center></i></b>");
  1054. print("</td></tr>");
  1055. print("<tr>");
  1056. // make this a self-reference to facilitate copy-pasting snippets to e-mails
  1057. print("<td><a href=''>$rep_symbol</a></td>");
  1058. if ($display_calls) {
  1059. // Call Count
  1060. print_td_num($symbol_info["ct"], $format_cbk["ct"]);
  1061. print_td_pct($symbol_info["ct"], $totals["ct"]);
  1062. }
  1063. // Inclusive Metrics for current function
  1064. foreach ($metrics as $metric) {
  1065. print_td_num($symbol_info[$metric], $format_cbk[$metric], ($sort_col == $metric));
  1066. print_td_pct($symbol_info[$metric], $totals[$metric], ($sort_col == $metric));
  1067. }
  1068. print("</tr>");
  1069. print("<tr bgcolor='#ffffff'>");
  1070. print("<td style='text-align:right;color:blue'>"
  1071. ."Exclusive Metrics $diff_text for Current Function</td>");
  1072. if ($display_calls) {
  1073. // Call Count
  1074. print("<td $vbar></td>");
  1075. print("<td $vbar></td>");
  1076. }
  1077. // Exclusive Metrics for current function
  1078. foreach ($metrics as $metric) {
  1079. print_td_num($symbol_info["excl_" . $metric], $format_cbk["excl_" . $metric],
  1080. ($sort_col == $metric),
  1081. get_tooltip_attributes("Child", $metric));
  1082. print_td_pct($symbol_info["excl_" . $metric], $symbol_info[$metric],
  1083. ($sort_col == $metric),
  1084. get_tooltip_attributes("Child", $metric));
  1085. }
  1086. print("</tr>");
  1087. // list of callers/parent functions
  1088. $results = array();
  1089. if ($display_calls) {
  1090. $base_ct = $symbol_info["ct"];
  1091. } else {
  1092. $base_ct = 0;
  1093. }
  1094. foreach ($metrics as $metric) {
  1095. $base_info[$metric] = $symbol_info[$metric];
  1096. }
  1097. foreach ($run_data as $parent_child => $info) {
  1098. list($parent, $child) = xhprof_parse_parent_child($parent_child);
  1099. if (($child == $rep_symbol) && ($parent)) {
  1100. $info_tmp = $info;
  1101. $info_tmp["fn"] = $parent;
  1102. $results[] = $info_tmp;
  1103. }
  1104. }
  1105. usort($results, 'sort_cbk');
  1106. if (count($results) > 0) {
  1107. print_pc_array($url_params, $results, $base_ct, $base_info, true,
  1108. $run1, $run2);
  1109. }
  1110. // list of callees/child functions
  1111. $results = array();
  1112. $base_ct = 0;
  1113. foreach ($run_data as $parent_child => $info) {
  1114. list($parent, $child) = xhprof_parse_parent_child($parent_child);
  1115. if ($parent == $rep_symbol) {
  1116. $info_tmp = $info;
  1117. $info_tmp["fn"] = $child;
  1118. $results[] = $info_tmp;
  1119. if ($display_calls) {
  1120. $base_ct += $info["ct"];
  1121. }
  1122. }
  1123. }
  1124. usort($results, 'sort_cbk');
  1125. if (count($results)) {
  1126. print_pc_array($url_params, $results, $base_ct, $base_info, false,
  1127. $run1, $run2);
  1128. }
  1129. print("</table>");
  1130. // These will be used for pop-up tips/help.
  1131. // Related javascript code is in: xhprof_report.js
  1132. print("\n");
  1133. print('<script language="javascript">' . "\n");
  1134. print("var func_name = '\"" . $rep_symbol . "\"';\n");
  1135. print("var total_child_ct = " . $base_ct . ";\n");
  1136. if ($display_calls) {
  1137. print("var func_ct = " . $symbol_info["ct"] . ";\n" );
  1138. }
  1139. print("var func_metrics = new Array();\n");
  1140. print("var metrics_col = new Array();\n");
  1141. print("var metrics_desc = new Array();\n");
  1142. if ($diff_mode) {
  1143. print("var diff_mode = true;\n");
  1144. } else {
  1145. print("var diff_mode = false;\n");
  1146. }
  1147. $column_index = 3; // First three columns are Func Name, Calls, Calls%
  1148. foreach ($metrics as $metric) {
  1149. print("func_metrics[\"" . $metric . "\"] = " . round($symbol_info[$metric]) . ";\n" );
  1150. print("metrics_col[\"". $metric . "\"] = " . $column_index . ";\n");
  1151. print("metrics_desc[\"". $metric . "\"] = \"" . $possible_metrics[$metric][2] . "\";\n");
  1152. // each metric has two columns..
  1153. $column_index += 2;
  1154. }
  1155. print('</script>');
  1156. print("\n");
  1157. }
  1158. /**
  1159. * Generate the profiler report for a single run.
  1160. *
  1161. * @author Kannan
  1162. */
  1163. function profiler_single_run_report ($url_params,
  1164. $xhprof_data,
  1165. $run_desc,
  1166. $rep_symbol,
  1167. $sort,
  1168. $run) {
  1169. init_metrics($xhprof_data, $rep_symbol, $sort, false);
  1170. profiler_report($url_params, $rep_symbol, $sort, $run, $run_desc,
  1171. $xhprof_data);
  1172. }
  1173. /**
  1174. * Generate the profiler report for diff mode (delta between two runs).
  1175. *
  1176. * @author Kannan
  1177. */
  1178. function profiler_diff_report($url_params,
  1179. $xhprof_data1,
  1180. $run1_desc,
  1181. $xhprof_data2,
  1182. $run2_desc,
  1183. $rep_symbol,
  1184. $sort,
  1185. $run1,
  1186. $run2) {
  1187. // Initialize what metrics we'll display based on data in Run2
  1188. init_metrics($xhprof_data2, $rep_symbol, $sort, true);
  1189. profiler_report($url_params,
  1190. $rep_symbol,
  1191. $sort,
  1192. $run1,
  1193. $run1_desc,
  1194. $xhprof_data1,
  1195. $run2,
  1196. $run2_desc,
  1197. $xhprof_data2);
  1198. }
  1199. /**
  1200. * Generate a XHProf Display View given the various URL parameters
  1201. * as arguments. The first argument is an object that implements
  1202. * the iXHProfRuns interface.
  1203. *
  1204. * @param object $xhprof_runs_impl An object that implements
  1205. * the iXHProfRuns interface
  1206. *.
  1207. * @param array $url_params Array of non-default URL params.
  1208. *
  1209. * @param string $source Category/type of the run. The source in
  1210. * combination with the run id uniquely
  1211. * determines a profiler run.
  1212. *
  1213. * @param string $run run id, or comma separated sequence of
  1214. * run ids. The latter is used if an aggregate
  1215. * report of the runs is desired.
  1216. *
  1217. * @param string $wts Comma separate list of integers.
  1218. * Represents the weighted ratio in
  1219. * which which a set of runs will be
  1220. * aggregated. [Used only for aggregate
  1221. * reports.]
  1222. *
  1223. * @param string $symbol Function symbol. If non-empty then the
  1224. * parent/child view of this function is
  1225. * displayed. If empty, a flat-profile view
  1226. * of the functions is displayed.
  1227. *
  1228. * @param string $run1 Base run id (for diff reports)
  1229. *
  1230. * @param string $run2 New run id (for diff reports)
  1231. *
  1232. */
  1233. function displayXHProfReport($xhprof_runs_impl, $url_params, $source,
  1234. $run, $wts, $symbol, $sort, $run1, $run2) {
  1235. if ($run) { // specific run to display?
  1236. // run may be a single run or a comma separate list of runs
  1237. // that'll be aggregated. If "wts" (a comma separated list
  1238. // of integral weights is specified), the runs will be
  1239. // aggregated in that ratio.
  1240. //
  1241. $runs_array = explode(",", $run);
  1242. if (count($runs_array) == 1) {
  1243. $xhprof_data = $xhprof_runs_impl->get_run($runs_array[0],
  1244. $source,
  1245. $description);
  1246. } else {
  1247. if (!empty($wts)) {
  1248. $wts_array = explode(",", $wts);
  1249. } else {
  1250. $wts_array = null;
  1251. }
  1252. $data = xhprof_aggregate_runs($xhprof_runs_impl,
  1253. $runs_array, $wts_array, $source, false);
  1254. $xhprof_data = $data['raw'];
  1255. $description = $data['description'];
  1256. }
  1257. profiler_single_run_report($url_params,
  1258. $xhprof_data,
  1259. $description,
  1260. $symbol,
  1261. $sort,
  1262. $run);
  1263. } else if ($run1 && $run2) { // diff report for two runs
  1264. $xhprof_data1 = $xhprof_runs_impl->get_run($run1, $source, $description1);
  1265. $xhprof_data2 = $xhprof_runs_impl->get_run($run2, $source, $description2);
  1266. profiler_diff_report($url_params,
  1267. $xhprof_data1,
  1268. $description1,
  1269. $xhprof_data2,
  1270. $description2,
  1271. $symbol,
  1272. $sort,
  1273. $run1,
  1274. $run2);
  1275. } else {
  1276. echo "No XHProf runs specified in the URL.";
  1277. }
  1278. }