See Release Notes
Long Term Support Release
Differences Between: [Versions 310 and 401] [Versions 311 and 401] [Versions 39 and 401]
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 // 18 // This file contains various XHProf library (utility) functions. 19 // Do not add any display specific code here. 20 // 21 22 if (!function_exists('xhprof_error')) { 23 function xhprof_error($message) { 24 error_log($message); 25 } 26 } 27 28 /* 29 * The list of possible metrics collected as part of XHProf that 30 * require inclusive/exclusive handling while reporting. 31 * 32 * @author Kannan 33 */ 34 function xhprof_get_possible_metrics() { 35 static $possible_metrics = 36 array("wt" => array("Wall", "microsecs", "walltime"), 37 "ut" => array("User", "microsecs", "user cpu time"), 38 "st" => array("Sys", "microsecs", "system cpu time"), 39 "cpu" => array("Cpu", "microsecs", "cpu time"), 40 "mu" => array("MUse", "bytes", "memory usage"), 41 "pmu" => array("PMUse", "bytes", "peak memory usage"), 42 "samples" => array("Samples", "samples", "cpu time")); 43 return $possible_metrics; 44 } 45 46 /** 47 * Initialize the metrics we'll display based on the information 48 * in the raw data. 49 * 50 * @author Kannan 51 */ 52 function init_metrics($xhprof_data, $rep_symbol, $sort, $diff_report = false) { 53 global $stats; 54 global $pc_stats; 55 global $metrics; 56 global $diff_mode; 57 global $sortable_columns; 58 global $sort_col; 59 global $display_calls; 60 61 $diff_mode = $diff_report; 62 63 if (!empty($sort)) { 64 if (array_key_exists($sort, $sortable_columns)) { 65 $sort_col = $sort; 66 } else { 67 print("Invalid Sort Key $sort specified in URL"); 68 } 69 } 70 71 // For C++ profiler runs, walltime attribute isn't present. 72 // In that case, use "samples" as the default sort column. 73 if (!isset($xhprof_data["main()"]["wt"])) { 74 75 if ($sort_col == "wt") { 76 $sort_col = "samples"; 77 } 78 79 // C++ profiler data doesn't have call counts. 80 // ideally we should check to see if "ct" metric 81 // is present for "main()". But currently "ct" 82 // metric is artificially set to 1. So, relying 83 // on absence of "wt" metric instead. 84 $display_calls = false; 85 } else { 86 $display_calls = true; 87 } 88 89 // parent/child report doesn't support exclusive times yet. 90 // So, change sort hyperlinks to closest fit. 91 if (!empty($rep_symbol)) { 92 $sort_col = str_replace("excl_", "", $sort_col); 93 } 94 95 if ($display_calls) { 96 $stats = array("fn", "ct", "Calls%"); 97 } else { 98 $stats = array("fn"); 99 } 100 101 $pc_stats = $stats; 102 103 $possible_metrics = xhprof_get_possible_metrics(); 104 foreach ($possible_metrics as $metric => $desc) { 105 if (isset($xhprof_data["main()"][$metric])) { 106 $metrics[] = $metric; 107 // flat (top-level reports): we can compute 108 // exclusive metrics reports as well. 109 $stats[] = $metric; 110 $stats[] = "I" . $desc[0] . "%"; 111 $stats[] = "excl_" . $metric; 112 $stats[] = "E" . $desc[0] . "%"; 113 114 // parent/child report for a function: we can 115 // only breakdown inclusive times correctly. 116 $pc_stats[] = $metric; 117 $pc_stats[] = "I" . $desc[0] . "%"; 118 } 119 } 120 } 121 122 /* 123 * Get the list of metrics present in $xhprof_data as an array. 124 * 125 * @author Kannan 126 */ 127 function xhprof_get_metrics($xhprof_data) { 128 129 // get list of valid metrics 130 $possible_metrics = xhprof_get_possible_metrics(); 131 132 // return those that are present in the raw data. 133 // We'll just look at the root of the subtree for this. 134 $metrics = array(); 135 foreach ($possible_metrics as $metric => $desc) { 136 if (isset($xhprof_data["main()"][$metric])) { 137 $metrics[] = $metric; 138 } 139 } 140 141 return $metrics; 142 } 143 144 /** 145 * Takes a parent/child function name encoded as 146 * "a==>b" and returns array("a", "b"). 147 * 148 * @author Kannan 149 */ 150 function xhprof_parse_parent_child($parent_child) { 151 $ret = explode("==>", $parent_child); 152 153 // Return if both parent and child are set 154 if (isset($ret[1])) { 155 return $ret; 156 } 157 158 return array(null, $ret[0]); 159 } 160 161 /** 162 * Given parent & child function name, composes the key 163 * in the format present in the raw data. 164 * 165 * @author Kannan 166 */ 167 function xhprof_build_parent_child_key($parent, $child) { 168 if ($parent) { 169 return $parent . "==>" . $child; 170 } else { 171 return $child; 172 } 173 } 174 175 176 /** 177 * Checks if XHProf raw data appears to be valid and not corrupted. 178 * 179 * @param int $run_id Run id of run to be pruned. 180 * [Used only for reporting errors.] 181 * @param array $raw_data XHProf raw data to be pruned 182 * & validated. 183 * 184 * @return bool true on success, false on failure 185 * 186 * @author Kannan 187 */ 188 function xhprof_valid_run($run_id, $raw_data) { 189 190 $main_info = $raw_data["main()"]; 191 if (empty($main_info)) { 192 xhprof_error("XHProf: main() missing in raw data for Run ID: $run_id"); 193 return false; 194 } 195 196 // raw data should contain either wall time or samples information... 197 if (isset($main_info["wt"])) { 198 $metric = "wt"; 199 } else if (isset($main_info["samples"])) { 200 $metric = "samples"; 201 } else { 202 xhprof_error("XHProf: Wall Time information missing from Run ID: $run_id"); 203 return false; 204 } 205 206 foreach ($raw_data as $info) { 207 $val = $info[$metric]; 208 209 // basic sanity checks... 210 if ($val < 0) { 211 xhprof_error("XHProf: $metric should not be negative: Run ID $run_id" 212 . serialize($info)); 213 return false; 214 } 215 if ($val > (86400000000)) { 216 xhprof_error("XHProf: $metric > 1 day found in Run ID: $run_id " 217 . serialize($info)); 218 return false; 219 } 220 } 221 return true; 222 } 223 224 225 /** 226 * Return a trimmed version of the XHProf raw data. Note that the raw 227 * data contains one entry for each unique parent/child function 228 * combination.The trimmed version of raw data will only contain 229 * entries where either the parent or child function is in the list 230 * of $functions_to_keep. 231 * 232 * Note: Function main() is also always kept so that overall totals 233 * can still be obtained from the trimmed version. 234 * 235 * @param array XHProf raw data 236 * @param array array of function names 237 * 238 * @return array Trimmed XHProf Report 239 * 240 * @author Kannan 241 */ 242 function xhprof_trim_run($raw_data, $functions_to_keep) { 243 244 // convert list of functions to a hash with function as the key 245 $function_map = array_fill_keys($functions_to_keep, 1); 246 247 // always keep main() as well so that overall totals can still 248 // be computed if need be. 249 $function_map['main()'] = 1; 250 251 $new_raw_data = array(); 252 foreach ($raw_data as $parent_child => $info) { 253 list($parent, $child) = xhprof_parse_parent_child($parent_child); 254 255 if (isset($function_map[$parent]) || isset($function_map[$child])) { 256 $new_raw_data[$parent_child] = $info; 257 } 258 } 259 260 return $new_raw_data; 261 } 262 263 /** 264 * Takes raw XHProf data that was aggregated over "$num_runs" number 265 * of runs averages/nomalizes the data. Essentially the various metrics 266 * collected are divided by $num_runs. 267 * 268 * @author Kannan 269 */ 270 function xhprof_normalize_metrics($raw_data, $num_runs) { 271 272 if (empty($raw_data) || ($num_runs == 0)) { 273 return $raw_data; 274 } 275 276 $raw_data_total = array(); 277 278 if (isset($raw_data["==>main()"]) && isset($raw_data["main()"])) { 279 xhprof_error("XHProf Error: both ==>main() and main() set in raw data..."); 280 } 281 282 foreach ($raw_data as $parent_child => $info) { 283 foreach ($info as $metric => $value) { 284 $raw_data_total[$parent_child][$metric] = ($value / $num_runs); 285 } 286 } 287 288 return $raw_data_total; 289 } 290 291 292 /** 293 * Get raw data corresponding to specified array of runs 294 * aggregated by certain weightage. 295 * 296 * Suppose you have run:5 corresponding to page1.php, 297 * run:6 corresponding to page2.php, 298 * and run:7 corresponding to page3.php 299 * 300 * and you want to accumulate these runs in a 2:4:1 ratio. You 301 * can do so by calling: 302 * 303 * xhprof_aggregate_runs(array(5, 6, 7), array(2, 4, 1)); 304 * 305 * The above will return raw data for the runs aggregated 306 * in 2:4:1 ratio. 307 * 308 * @param object $xhprof_runs_impl An object that implements 309 * the iXHProfRuns interface 310 * @param array $runs run ids of the XHProf runs.. 311 * @param array $wts integral (ideally) weights for $runs 312 * @param string $source source to fetch raw data for run from 313 * @param bool $use_script_name If true, a fake edge from main() to 314 * to __script::<scriptname> is introduced 315 * in the raw data so that after aggregations 316 * the script name is still preserved. 317 * 318 * @return array Return aggregated raw data 319 * 320 * @author Kannan 321 */ 322 function xhprof_aggregate_runs($xhprof_runs_impl, $runs, 323 $wts, $source="phprof", 324 $use_script_name=false) { 325 326 $raw_data_total = null; 327 $raw_data = null; 328 $metrics = array(); 329 330 $run_count = count($runs); 331 $wts_count = count($wts); 332 333 if (($run_count == 0) || 334 (($wts_count > 0) && ($run_count != $wts_count))) { 335 return array('description' => 'Invalid input..', 336 'raw' => null); 337 } 338 339 $bad_runs = array(); 340 foreach ($runs as $idx => $run_id) { 341 342 $raw_data = $xhprof_runs_impl->get_run($run_id, $source, $description); 343 344 // use the first run to derive what metrics to aggregate on. 345 if ($idx == 0) { 346 foreach ($raw_data["main()"] as $metric => $val) { 347 if ($metric != "pmu") { 348 // for now, just to keep data size small, skip "peak" memory usage 349 // data while aggregating. 350 // The "regular" memory usage data will still be tracked. 351 if (isset($val)) { 352 $metrics[] = $metric; 353 } 354 } 355 } 356 } 357 358 if (!xhprof_valid_run($run_id, $raw_data)) { 359 $bad_runs[] = $run_id; 360 continue; 361 } 362 363 if ($use_script_name) { 364 $page = $description; 365 366 // create a fake function '__script::$page', and have and edge from 367 // main() to '__script::$page'. We will also need edges to transfer 368 // all edges originating from main() to now originate from 369 // '__script::$page' to all function called from main(). 370 // 371 // We also weight main() ever so slightly higher so that 372 // it shows up above the new entry in reports sorted by 373 // inclusive metrics or call counts. 374 if ($page) { 375 foreach ($raw_data["main()"] as $metric => $val) { 376 $fake_edge[$metric] = $val; 377 $new_main[$metric] = $val + 0.00001; 378 } 379 $raw_data["main()"] = $new_main; 380 $raw_data[xhprof_build_parent_child_key("main()", 381 "__script::$page")] 382 = $fake_edge; 383 } else { 384 $use_script_name = false; 385 } 386 } 387 388 // if no weights specified, use 1 as the default weightage.. 389 $wt = ($wts_count == 0) ? 1 : $wts[$idx]; 390 391 // aggregate $raw_data into $raw_data_total with appropriate weight ($wt) 392 foreach ($raw_data as $parent_child => $info) { 393 if ($use_script_name) { 394 // if this is an old edge originating from main(), it now 395 // needs to be from '__script::$page' 396 if (substr($parent_child, 0, 9) == "main()==>") { 397 $child = substr($parent_child, 9); 398 // ignore the newly added edge from main() 399 if (substr($child, 0, 10) != "__script::") { 400 $parent_child = xhprof_build_parent_child_key("__script::$page", 401 $child); 402 } 403 } 404 } 405 406 if (!isset($raw_data_total[$parent_child])) { 407 foreach ($metrics as $metric) { 408 $raw_data_total[$parent_child][$metric] = ($wt * $info[$metric]); 409 } 410 } else { 411 foreach ($metrics as $metric) { 412 $raw_data_total[$parent_child][$metric] += ($wt * $info[$metric]); 413 } 414 } 415 } 416 } 417 418 $runs_string = implode(",", $runs); 419 420 if (isset($wts)) { 421 $wts_string = "in the ratio (" . implode(":", $wts) . ")"; 422 $normalization_count = array_sum($wts); 423 } else { 424 $wts_string = ""; 425 $normalization_count = $run_count; 426 } 427 428 $run_count = $run_count - count($bad_runs); 429 430 $data['description'] = "Aggregated Report for $run_count runs: ". 431 "$runs_string $wts_string\n"; 432 $data['raw'] = xhprof_normalize_metrics($raw_data_total, 433 $normalization_count); 434 $data['bad_runs'] = $bad_runs; 435 436 return $data; 437 } 438 439 440 /** 441 * Analyze hierarchical raw data, and compute per-function (flat) 442 * inclusive and exclusive metrics. 443 * 444 * Also, store overall totals in the 2nd argument. 445 * 446 * @param array $raw_data XHProf format raw profiler data. 447 * @param array &$overall_totals OUT argument for returning 448 * overall totals for various 449 * metrics. 450 * @return array Returns a map from function name to its 451 * call count and inclusive & exclusive metrics 452 * (such as wall time, etc.). 453 * 454 * @author Kannan Muthukkaruppan 455 */ 456 function xhprof_compute_flat_info($raw_data, &$overall_totals) { 457 458 global $display_calls; 459 460 $metrics = xhprof_get_metrics($raw_data); 461 462 $overall_totals = array("ct" => 0, 463 "wt" => 0, 464 "ut" => 0, 465 "st" => 0, 466 "cpu" => 0, 467 "mu" => 0, 468 "pmu" => 0, 469 "samples" => 0 470 ); 471 472 // compute inclusive times for each function 473 $symbol_tab = xhprof_compute_inclusive_times($raw_data); 474 475 /* total metric value is the metric value for "main()" */ 476 foreach ($metrics as $metric) { 477 $overall_totals[$metric] = $symbol_tab["main()"][$metric]; 478 } 479 480 /* 481 * initialize exclusive (self) metric value to inclusive metric value 482 * to start with. 483 * In the same pass, also add up the total number of function calls. 484 */ 485 foreach ($symbol_tab as $symbol => $info) { 486 foreach ($metrics as $metric) { 487 $symbol_tab[$symbol]["excl_" . $metric] = $symbol_tab[$symbol][$metric]; 488 } 489 if ($display_calls) { 490 /* keep track of total number of calls */ 491 $overall_totals["ct"] += $info["ct"]; 492 } 493 } 494 495 /* adjust exclusive times by deducting inclusive time of children */ 496 foreach ($raw_data as $parent_child => $info) { 497 list($parent, $child) = xhprof_parse_parent_child($parent_child); 498 499 if ($parent) { 500 foreach ($metrics as $metric) { 501 // make sure the parent exists hasn't been pruned. 502 if (isset($symbol_tab[$parent])) { 503 $symbol_tab[$parent]["excl_" . $metric] -= $info[$metric]; 504 } 505 } 506 } 507 } 508 509 return $symbol_tab; 510 } 511 512 /** 513 * Hierarchical diff: 514 * Compute and return difference of two call graphs: Run2 - Run1. 515 * 516 * @author Kannan 517 */ 518 function xhprof_compute_diff($xhprof_data1, $xhprof_data2) { 519 global $display_calls; 520 521 // use the second run to decide what metrics we will do the diff on 522 $metrics = xhprof_get_metrics($xhprof_data2); 523 524 $xhprof_delta = $xhprof_data2; 525 526 foreach ($xhprof_data1 as $parent_child => $info) { 527 528 if (!isset($xhprof_delta[$parent_child])) { 529 530 // this pc combination was not present in run1; 531 // initialize all values to zero. 532 if ($display_calls) { 533 $xhprof_delta[$parent_child] = array("ct" => 0); 534 } else { 535 $xhprof_delta[$parent_child] = array(); 536 } 537 foreach ($metrics as $metric) { 538 $xhprof_delta[$parent_child][$metric] = 0; 539 } 540 } 541 542 if ($display_calls) { 543 $xhprof_delta[$parent_child]["ct"] -= $info["ct"]; 544 } 545 546 foreach ($metrics as $metric) { 547 $xhprof_delta[$parent_child][$metric] -= $info[$metric]; 548 } 549 } 550 551 return $xhprof_delta; 552 } 553 554 555 /** 556 * Compute inclusive metrics for function. This code was factored out 557 * of xhprof_compute_flat_info(). 558 * 559 * The raw data contains inclusive metrics of a function for each 560 * unique parent function it is called from. The total inclusive metrics 561 * for a function is therefore the sum of inclusive metrics for the 562 * function across all parents. 563 * 564 * @return array Returns a map of function name to total (across all parents) 565 * inclusive metrics for the function. 566 * 567 * @author Kannan 568 */ 569 function xhprof_compute_inclusive_times($raw_data) { 570 global $display_calls; 571 572 $metrics = xhprof_get_metrics($raw_data); 573 574 $symbol_tab = array(); 575 576 /* 577 * First compute inclusive time for each function and total 578 * call count for each function across all parents the 579 * function is called from. 580 */ 581 foreach ($raw_data as $parent_child => $info) { 582 583 list($parent, $child) = xhprof_parse_parent_child($parent_child); 584 585 if ($parent == $child) { 586 /* 587 * XHProf PHP extension should never trigger this situation any more. 588 * Recursion is handled in the XHProf PHP extension by giving nested 589 * calls a unique recursion-depth appended name (for example, foo@1). 590 */ 591 xhprof_error("Error in Raw Data: parent & child are both: $parent"); 592 return; 593 } 594 595 if (!isset($symbol_tab[$child])) { 596 597 if ($display_calls) { 598 $symbol_tab[$child] = array("ct" => $info["ct"]); 599 } else { 600 $symbol_tab[$child] = array(); 601 } 602 foreach ($metrics as $metric) { 603 $symbol_tab[$child][$metric] = $info[$metric]; 604 } 605 } else { 606 if ($display_calls) { 607 /* increment call count for this child */ 608 $symbol_tab[$child]["ct"] += $info["ct"]; 609 } 610 611 /* update inclusive times/metric for this child */ 612 foreach ($metrics as $metric) { 613 $symbol_tab[$child][$metric] += $info[$metric]; 614 } 615 } 616 } 617 618 return $symbol_tab; 619 } 620 621 622 /* 623 * Prunes XHProf raw data: 624 * 625 * Any node whose inclusive walltime accounts for less than $prune_percent 626 * of total walltime is pruned. [It is possible that a child function isn't 627 * pruned, but one or more of its parents get pruned. In such cases, when 628 * viewing the child function's hierarchical information, the cost due to 629 * the pruned parent(s) will be attributed to a special function/symbol 630 * "__pruned__()".] 631 * 632 * @param array $raw_data XHProf raw data to be pruned & validated. 633 * @param double $prune_percent Any edges that account for less than 634 * $prune_percent of time will be pruned 635 * from the raw data. 636 * 637 * @return array Returns the pruned raw data. 638 * 639 * @author Kannan 640 */ 641 function xhprof_prune_run($raw_data, $prune_percent) { 642 643 $main_info = $raw_data["main()"]; 644 if (empty($main_info)) { 645 xhprof_error("XHProf: main() missing in raw data"); 646 return false; 647 } 648 649 // raw data should contain either wall time or samples information... 650 if (isset($main_info["wt"])) { 651 $prune_metric = "wt"; 652 } else if (isset($main_info["samples"])) { 653 $prune_metric = "samples"; 654 } else { 655 xhprof_error("XHProf: for main() we must have either wt " 656 ."or samples attribute set"); 657 return false; 658 } 659 660 // determine the metrics present in the raw data.. 661 $metrics = array(); 662 foreach ($main_info as $metric => $val) { 663 if (isset($val)) { 664 $metrics[] = $metric; 665 } 666 } 667 668 $prune_threshold = (($main_info[$prune_metric] * $prune_percent) / 100.0); 669 670 init_metrics($raw_data, null, null, false); 671 $flat_info = xhprof_compute_inclusive_times($raw_data); 672 673 foreach ($raw_data as $parent_child => $info) { 674 675 list($parent, $child) = xhprof_parse_parent_child($parent_child); 676 677 // is this child's overall total from all parents less than threshold? 678 if ($flat_info[$child][$prune_metric] < $prune_threshold) { 679 unset($raw_data[$parent_child]); // prune the edge 680 } else if ($parent && 681 ($parent != "__pruned__()") && 682 ($flat_info[$parent][$prune_metric] < $prune_threshold)) { 683 684 // Parent's overall inclusive metric is less than a threshold. 685 // All edges to the parent node will get nuked, and this child will 686 // be a dangling child. 687 // So instead change its parent to be a special function __pruned__(). 688 $pruned_edge = xhprof_build_parent_child_key("__pruned__()", $child); 689 690 if (isset($raw_data[$pruned_edge])) { 691 foreach ($metrics as $metric) { 692 $raw_data[$pruned_edge][$metric]+=$raw_data[$parent_child][$metric]; 693 } 694 } else { 695 $raw_data[$pruned_edge] = $raw_data[$parent_child]; 696 } 697 698 unset($raw_data[$parent_child]); // prune the edge 699 } 700 } 701 702 return $raw_data; 703 } 704 705 706 /** 707 * Set one key in an array and return the array 708 * 709 * @author Kannan 710 */ 711 function xhprof_array_set($arr, $k, $v) { 712 $arr[$k] = $v; 713 return $arr; 714 } 715 716 /** 717 * Removes/unsets one key in an array and return the array 718 * 719 * @author Kannan 720 */ 721 function xhprof_array_unset($arr, $k) { 722 unset($arr[$k]); 723 return $arr; 724 } 725 726 /** 727 * Type definitions for URL params 728 */ 729 define('XHPROF_STRING_PARAM', 1); 730 define('XHPROF_UINT_PARAM', 2); 731 define('XHPROF_FLOAT_PARAM', 3); 732 define('XHPROF_BOOL_PARAM', 4); 733 734 735 /** 736 * Internal helper function used by various 737 * xhprof_get_param* flavors for various 738 * types of parameters. 739 * 740 * @param string name of the URL query string param 741 * 742 * @author Kannan 743 */ 744 function xhprof_get_param_helper($param) { 745 $val = null; 746 if (isset($_GET[$param])) 747 $val = $_GET[$param]; 748 else if (isset($_POST[$param])) { 749 $val = $_POST[$param]; 750 } 751 return $val; 752 } 753 754 /** 755 * Extracts value for string param $param from query 756 * string. If param is not specified, return the 757 * $default value. 758 * 759 * @author Kannan 760 */ 761 function xhprof_get_string_param($param, $default = '') { 762 $val = xhprof_get_param_helper($param); 763 764 if ($val === null) 765 return $default; 766 767 return $val; 768 } 769 770 /** 771 * Extracts value for unsigned integer param $param from 772 * query string. If param is not specified, return the 773 * $default value. 774 * 775 * If value is not a valid unsigned integer, logs error 776 * and returns null. 777 * 778 * @author Kannan 779 */ 780 function xhprof_get_uint_param($param, $default = 0) { 781 $val = xhprof_get_param_helper($param); 782 783 if ($val === null) 784 $val = $default; 785 786 // trim leading/trailing whitespace 787 $val = trim($val); 788 789 // if it only contains digits, then ok.. 790 if (ctype_digit($val)) { 791 return $val; 792 } 793 794 xhprof_error("$param is $val. It must be an unsigned integer."); 795 return null; 796 } 797 798 799 /** 800 * Extracts value for a float param $param from 801 * query string. If param is not specified, return 802 * the $default value. 803 * 804 * If value is not a valid unsigned integer, logs error 805 * and returns null. 806 * 807 * @author Kannan 808 */ 809 function xhprof_get_float_param($param, $default = 0) { 810 $val = xhprof_get_param_helper($param); 811 812 if ($val === null) 813 $val = $default; 814 815 // trim leading/trailing whitespace 816 $val = trim($val); 817 818 // TBD: confirm the value is indeed a float. 819 if (true) // for now.. 820 return (float)$val; 821 822 xhprof_error("$param is $val. It must be a float."); 823 return null; 824 } 825 826 /** 827 * Extracts value for a boolean param $param from 828 * query string. If param is not specified, return 829 * the $default value. 830 * 831 * If value is not a valid unsigned integer, logs error 832 * and returns null. 833 * 834 * @author Kannan 835 */ 836 function xhprof_get_bool_param($param, $default = false) { 837 $val = xhprof_get_param_helper($param); 838 839 if ($val === null) 840 $val = $default; 841 842 // trim leading/trailing whitespace 843 $val = trim($val); 844 845 switch (strtolower($val)) { 846 case '0': 847 case '1': 848 $val = (bool)$val; 849 break; 850 case 'true': 851 case 'on': 852 case 'yes': 853 $val = true; 854 break; 855 case 'false': 856 case 'off': 857 case 'no': 858 $val = false; 859 break; 860 default: 861 xhprof_error("$param is $val. It must be a valid boolean string."); 862 return null; 863 } 864 865 return $val; 866 867 } 868 869 /** 870 * Initialize params from URL query string. The function 871 * creates globals variables for each of the params 872 * and if the URL query string doesn't specify a particular 873 * param initializes them with the corresponding default 874 * value specified in the input. 875 * 876 * @params array $params An array whose keys are the names 877 * of URL params who value needs to 878 * be retrieved from the URL query 879 * string. PHP globals are created 880 * with these names. The value is 881 * itself an array with 2-elems (the 882 * param type, and its default value). 883 * If a param is not specified in the 884 * query string the default value is 885 * used. 886 * @author Kannan 887 */ 888 function xhprof_param_init($params) { 889 /* Create variables specified in $params keys, init defaults */ 890 foreach ($params as $k => $v) { 891 switch ($v[0]) { 892 case XHPROF_STRING_PARAM: 893 $p = xhprof_get_string_param($k, $v[1]); 894 break; 895 case XHPROF_UINT_PARAM: 896 $p = xhprof_get_uint_param($k, $v[1]); 897 break; 898 case XHPROF_FLOAT_PARAM: 899 $p = xhprof_get_float_param($k, $v[1]); 900 break; 901 case XHPROF_BOOL_PARAM: 902 $p = xhprof_get_bool_param($k, $v[1]); 903 break; 904 default: 905 xhprof_error("Invalid param type passed to xhprof_param_init: " 906 . $v[0]); 907 exit(); 908 } 909 910 if ($k === 'run') { 911 $p = implode(',', array_filter(explode(',', $p), 'ctype_xdigit')); 912 } 913 914 if ($k == 'symbol') { 915 $p = strip_tags($p); 916 } 917 918 // create a global variable using the parameter name. 919 $GLOBALS[$k] = $p; 920 } 921 } 922 923 924 /** 925 * Given a partial query string $q return matching function names in 926 * specified XHProf run. This is used for the type ahead function 927 * selector. 928 * 929 * @author Kannan 930 */ 931 function xhprof_get_matching_functions($q, $xhprof_data) { 932 933 $matches = array(); 934 935 foreach ($xhprof_data as $parent_child => $info) { 936 list($parent, $child) = xhprof_parse_parent_child($parent_child); 937 if (stripos($parent, $q) !== false) { 938 $matches[$parent] = 1; 939 } 940 if (stripos($child, $q) !== false) { 941 $matches[$child] = 1; 942 } 943 } 944 945 $res = array_keys($matches); 946 947 // sort it so the answers are in some reliable order... 948 asort($res); 949 950 return ($res); 951 }
title
Description
Body
title
Description
Body
title
Description
Body
title
Body