Merge branch 'wip-MDL-60313-master' of git://github.com/marinaglancy/moodle
[moodle.git] / lib / xhprof / xhprof_lib / utils / xhprof_lib.php
CommitLineData
6af80cae
EL
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
22function 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 */
32function 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 */
50function 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
ffb41a8f 101 $possible_metrics = xhprof_get_possible_metrics();
6af80cae
EL
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 */
125function 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 */
148function 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 */
165function 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 */
186function 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 */
240function 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 */
268function 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 */
320function 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 */
454function 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 */
516function 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 */
567function 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 */
639function 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 */
709function 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 */
719function xhprof_array_unset($arr, $k) {
720 unset($arr[$k]);
721 return $arr;
722}
723
724/**
725 * Type definitions for URL params
726 */
727define('XHPROF_STRING_PARAM', 1);
728define('XHPROF_UINT_PARAM', 2);
729define('XHPROF_FLOAT_PARAM', 3);
730define('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 */
742function 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 */
759function 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 */
778function 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 */
807function 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 */
834function 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 */
886function 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
ffb41a8f
MG
908 if ($k === 'run') {
909 $p = implode(',', array_filter(explode(',', $p), 'ctype_xdigit'));
910 }
911
6af80cae
EL
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 */
925function 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}