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