Proyectos de Subversion Moodle

Rev

| Ultima modificación | Ver Log |

Rev Autor Línea Nro. Línea
1 efrain 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
}