Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/xhprof/xhprof_lib/utils/xhprof_lib.php
Go to the documentation of this file.
00001 <?php
00002 //  Copyright (c) 2009 Facebook
00003 //
00004 //  Licensed under the Apache License, Version 2.0 (the "License");
00005 //  you may not use this file except in compliance with the License.
00006 //  You may obtain a copy of the License at
00007 //
00008 //      http://www.apache.org/licenses/LICENSE-2.0
00009 //
00010 //  Unless required by applicable law or agreed to in writing, software
00011 //  distributed under the License is distributed on an "AS IS" BASIS,
00012 //  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
00013 //  See the License for the specific language governing permissions and
00014 //  limitations under the License.
00015 //
00016 
00017 //
00018 // This file contains various XHProf library (utility) functions.
00019 // Do not add any display specific code here.
00020 //
00021 
00022 function xhprof_error($message) {
00023   error_log($message);
00024 }
00025 
00026 /*
00027  * The list of possible metrics collected as part of XHProf that
00028  * require inclusive/exclusive handling while reporting.
00029  *
00030  * @author Kannan
00031  */
00032 function xhprof_get_possible_metrics() {
00033  static $possible_metrics =
00034    array("wt" => array("Wall", "microsecs", "walltime"),
00035          "ut" => array("User", "microsecs", "user cpu time"),
00036          "st" => array("Sys", "microsecs", "system cpu time"),
00037          "cpu" => array("Cpu", "microsecs", "cpu time"),
00038          "mu" => array("MUse", "bytes", "memory usage"),
00039          "pmu" => array("PMUse", "bytes", "peak memory usage"),
00040          "samples" => array("Samples", "samples", "cpu time"));
00041  return $possible_metrics;
00042 }
00043 
00050 function init_metrics($xhprof_data, $rep_symbol, $sort, $diff_report = false) {
00051   global $stats;
00052   global $pc_stats;
00053   global $metrics;
00054   global $diff_mode;
00055   global $sortable_columns;
00056   global $sort_col;
00057   global $display_calls;
00058 
00059   $diff_mode = $diff_report;
00060 
00061   if (!empty($sort)) {
00062     if (array_key_exists($sort, $sortable_columns)) {
00063       $sort_col = $sort;
00064     } else {
00065       print("Invalid Sort Key $sort specified in URL");
00066     }
00067   }
00068 
00069   // For C++ profiler runs, walltime attribute isn't present.
00070   // In that case, use "samples" as the default sort column.
00071   if (!isset($xhprof_data["main()"]["wt"])) {
00072 
00073     if ($sort_col == "wt") {
00074       $sort_col = "samples";
00075     }
00076 
00077     // C++ profiler data doesn't have call counts.
00078     // ideally we should check to see if "ct" metric
00079     // is present for "main()". But currently "ct"
00080     // metric is artificially set to 1. So, relying
00081     // on absence of "wt" metric instead.
00082     $display_calls = false;
00083   } else {
00084     $display_calls = true;
00085   }
00086 
00087   // parent/child report doesn't support exclusive times yet.
00088   // So, change sort hyperlinks to closest fit.
00089   if (!empty($rep_symbol)) {
00090     $sort_col = str_replace("excl_", "", $sort_col);
00091   }
00092 
00093   if ($display_calls) {
00094     $stats = array("fn", "ct", "Calls%");
00095   } else {
00096     $stats = array("fn");
00097   }
00098 
00099   $pc_stats = $stats;
00100 
00101   $possible_metrics = xhprof_get_possible_metrics($xhprof_data);
00102   foreach ($possible_metrics as $metric => $desc) {
00103     if (isset($xhprof_data["main()"][$metric])) {
00104       $metrics[] = $metric;
00105       // flat (top-level reports): we can compute
00106       // exclusive metrics reports as well.
00107       $stats[] = $metric;
00108       $stats[] = "I" . $desc[0] . "%";
00109       $stats[] = "excl_" . $metric;
00110       $stats[] = "E" . $desc[0] . "%";
00111 
00112       // parent/child report for a function: we can
00113       // only breakdown inclusive times correctly.
00114       $pc_stats[] = $metric;
00115       $pc_stats[] = "I" . $desc[0] . "%";
00116     }
00117   }
00118 }
00119 
00120 /*
00121  * Get the list of metrics present in $xhprof_data as an array.
00122  *
00123  * @author Kannan
00124  */
00125 function xhprof_get_metrics($xhprof_data) {
00126 
00127   // get list of valid metrics
00128   $possible_metrics = xhprof_get_possible_metrics();
00129 
00130   // return those that are present in the raw data.
00131   // We'll just look at the root of the subtree for this.
00132   $metrics = array();
00133   foreach ($possible_metrics as $metric => $desc) {
00134     if (isset($xhprof_data["main()"][$metric])) {
00135       $metrics[] = $metric;
00136     }
00137   }
00138 
00139   return $metrics;
00140 }
00141 
00148 function xhprof_parse_parent_child($parent_child) {
00149   $ret = explode("==>", $parent_child);
00150 
00151   // Return if both parent and child are set
00152   if (isset($ret[1])) {
00153     return $ret;
00154   }
00155 
00156   return array(null, $ret[0]);
00157 }
00158 
00165 function xhprof_build_parent_child_key($parent, $child) {
00166   if ($parent) {
00167     return $parent . "==>" . $child;
00168   } else {
00169     return $child;
00170   }
00171 }
00172 
00173 
00186 function xhprof_valid_run($run_id, $raw_data) {
00187 
00188   $main_info = $raw_data["main()"];
00189   if (empty($main_info)) {
00190     xhprof_error("XHProf: main() missing in raw data for Run ID: $run_id");
00191     return false;
00192   }
00193 
00194   // raw data should contain either wall time or samples information...
00195   if (isset($main_info["wt"])) {
00196     $metric = "wt";
00197   } else if (isset($main_info["samples"])) {
00198     $metric = "samples";
00199   } else {
00200     xhprof_error("XHProf: Wall Time information missing from Run ID: $run_id");
00201     return false;
00202   }
00203 
00204   foreach ($raw_data as $info) {
00205     $val = $info[$metric];
00206 
00207     // basic sanity checks...
00208     if ($val < 0) {
00209       xhprof_error("XHProf: $metric should not be negative: Run ID $run_id"
00210                    . serialize($info));
00211       return false;
00212     }
00213     if ($val > (86400000000)) {
00214       xhprof_error("XHProf: $metric > 1 day found in Run ID: $run_id "
00215                    . serialize($info));
00216       return false;
00217     }
00218   }
00219   return true;
00220 }
00221 
00222 
00240 function xhprof_trim_run($raw_data, $functions_to_keep) {
00241 
00242   // convert list of functions to a hash with function as the key
00243   $function_map = array_fill_keys($functions_to_keep, 1);
00244 
00245   // always keep main() as well so that overall totals can still
00246   // be computed if need be.
00247   $function_map['main()'] = 1;
00248 
00249   $new_raw_data = array();
00250   foreach ($raw_data as $parent_child => $info) {
00251     list($parent, $child) = xhprof_parse_parent_child($parent_child);
00252 
00253     if (isset($function_map[$parent]) || isset($function_map[$child])) {
00254       $new_raw_data[$parent_child] = $info;
00255     }
00256   }
00257 
00258   return $new_raw_data;
00259 }
00260 
00268 function xhprof_normalize_metrics($raw_data, $num_runs) {
00269 
00270   if (empty($raw_data) || ($num_runs == 0)) {
00271     return $raw_data;
00272   }
00273 
00274   $raw_data_total = array();
00275 
00276   if (isset($raw_data["==>main()"]) && isset($raw_data["main()"])) {
00277     xhprof_error("XHProf Error: both ==>main() and main() set in raw data...");
00278   }
00279 
00280   foreach ($raw_data as $parent_child => $info) {
00281     foreach ($info as $metric => $value) {
00282       $raw_data_total[$parent_child][$metric] = ($value / $num_runs);
00283     }
00284   }
00285 
00286   return $raw_data_total;
00287 }
00288 
00289 
00320 function xhprof_aggregate_runs($xhprof_runs_impl, $runs,
00321                                $wts, $source="phprof",
00322                                $use_script_name=false) {
00323 
00324   $raw_data_total = null;
00325   $raw_data       = null;
00326   $metrics        = array();
00327 
00328   $run_count = count($runs);
00329   $wts_count = count($wts);
00330 
00331   if (($run_count == 0) ||
00332       (($wts_count > 0) && ($run_count != $wts_count))) {
00333     return array('description' => 'Invalid input..',
00334                  'raw'  => null);
00335   }
00336 
00337   $bad_runs = array();
00338   foreach ($runs as $idx => $run_id) {
00339 
00340     $raw_data = $xhprof_runs_impl->get_run($run_id, $source, $description);
00341 
00342     // use the first run to derive what metrics to aggregate on.
00343     if ($idx == 0) {
00344       foreach ($raw_data["main()"] as $metric => $val) {
00345         if ($metric != "pmu") {
00346           // for now, just to keep data size small, skip "peak" memory usage
00347           // data while aggregating.
00348           // The "regular" memory usage data will still be tracked.
00349           if (isset($val)) {
00350             $metrics[] = $metric;
00351           }
00352         }
00353       }
00354     }
00355 
00356     if (!xhprof_valid_run($run_id, $raw_data)) {
00357       $bad_runs[] = $run_id;
00358       continue;
00359     }
00360 
00361     if ($use_script_name) {
00362       $page = $description;
00363 
00364       // create a fake function '__script::$page', and have and edge from
00365       // main() to '__script::$page'. We will also need edges to transfer
00366       // all edges originating from main() to now originate from
00367       // '__script::$page' to all function called from main().
00368       //
00369       // We also weight main() ever so slightly higher so that
00370       // it shows up above the new entry in reports sorted by
00371       // inclusive metrics or call counts.
00372       if ($page) {
00373         foreach ($raw_data["main()"] as $metric => $val) {
00374           $fake_edge[$metric] = $val;
00375           $new_main[$metric]  = $val + 0.00001;
00376         }
00377         $raw_data["main()"] = $new_main;
00378         $raw_data[xhprof_build_parent_child_key("main()",
00379                                                 "__script::$page")]
00380           = $fake_edge;
00381       } else {
00382         $use_script_name = false;
00383       }
00384     }
00385 
00386     // if no weights specified, use 1 as the default weightage..
00387     $wt = ($wts_count == 0) ? 1 : $wts[$idx];
00388 
00389     // aggregate $raw_data into $raw_data_total with appropriate weight ($wt)
00390     foreach ($raw_data as $parent_child => $info) {
00391       if ($use_script_name) {
00392         // if this is an old edge originating from main(), it now
00393         // needs to be from '__script::$page'
00394         if (substr($parent_child, 0, 9) == "main()==>") {
00395           $child = substr($parent_child, 9);
00396           // ignore the newly added edge from main()
00397           if (substr($child, 0, 10) != "__script::") {
00398             $parent_child = xhprof_build_parent_child_key("__script::$page",
00399                                                           $child);
00400           }
00401         }
00402       }
00403 
00404       if (!isset($raw_data_total[$parent_child])) {
00405         foreach ($metrics as $metric) {
00406           $raw_data_total[$parent_child][$metric] = ($wt * $info[$metric]);
00407         }
00408       } else {
00409         foreach ($metrics as $metric) {
00410           $raw_data_total[$parent_child][$metric] += ($wt * $info[$metric]);
00411         }
00412       }
00413     }
00414   }
00415 
00416   $runs_string = implode(",", $runs);
00417 
00418   if (isset($wts)) {
00419     $wts_string  = "in the ratio (" . implode(":", $wts) . ")";
00420     $normalization_count = array_sum($wts);
00421   } else {
00422     $wts_string = "";
00423     $normalization_count = $run_count;
00424   }
00425 
00426   $run_count = $run_count - count($bad_runs);
00427 
00428   $data['description'] = "Aggregated Report for $run_count runs: ".
00429                          "$runs_string $wts_string\n";
00430   $data['raw'] = xhprof_normalize_metrics($raw_data_total,
00431                                           $normalization_count);
00432   $data['bad_runs'] = $bad_runs;
00433 
00434   return $data;
00435 }
00436 
00437 
00454 function xhprof_compute_flat_info($raw_data, &$overall_totals) {
00455 
00456   global $display_calls;
00457 
00458   $metrics = xhprof_get_metrics($raw_data);
00459 
00460   $overall_totals = array("ct" => 0,
00461                            "wt" => 0,
00462                            "ut" => 0,
00463                            "st" => 0,
00464                            "cpu" => 0,
00465                            "mu" => 0,
00466                            "pmu" => 0,
00467                            "samples" => 0
00468                            );
00469 
00470   // compute inclusive times for each function
00471   $symbol_tab = xhprof_compute_inclusive_times($raw_data);
00472 
00473   /* total metric value is the metric value for "main()" */
00474   foreach ($metrics as $metric) {
00475     $overall_totals[$metric] = $symbol_tab["main()"][$metric];
00476   }
00477 
00478   /*
00479    * initialize exclusive (self) metric value to inclusive metric value
00480    * to start with.
00481    * In the same pass, also add up the total number of function calls.
00482    */
00483   foreach ($symbol_tab as $symbol => $info) {
00484     foreach ($metrics as $metric) {
00485       $symbol_tab[$symbol]["excl_" . $metric] = $symbol_tab[$symbol][$metric];
00486     }
00487     if ($display_calls) {
00488       /* keep track of total number of calls */
00489       $overall_totals["ct"] += $info["ct"];
00490     }
00491   }
00492 
00493   /* adjust exclusive times by deducting inclusive time of children */
00494   foreach ($raw_data as $parent_child => $info) {
00495     list($parent, $child) = xhprof_parse_parent_child($parent_child);
00496 
00497     if ($parent) {
00498       foreach ($metrics as $metric) {
00499         // make sure the parent exists hasn't been pruned.
00500         if (isset($symbol_tab[$parent])) {
00501           $symbol_tab[$parent]["excl_" . $metric] -= $info[$metric];
00502         }
00503       }
00504     }
00505   }
00506 
00507   return $symbol_tab;
00508 }
00509 
00516 function xhprof_compute_diff($xhprof_data1, $xhprof_data2) {
00517   global $display_calls;
00518 
00519   // use the second run to decide what metrics we will do the diff on
00520   $metrics = xhprof_get_metrics($xhprof_data2);
00521 
00522   $xhprof_delta = $xhprof_data2;
00523 
00524   foreach ($xhprof_data1 as $parent_child => $info) {
00525 
00526     if (!isset($xhprof_delta[$parent_child])) {
00527 
00528       // this pc combination was not present in run1;
00529       // initialize all values to zero.
00530       if ($display_calls) {
00531         $xhprof_delta[$parent_child] = array("ct" => 0);
00532       } else {
00533         $xhprof_delta[$parent_child] = array();
00534       }
00535       foreach ($metrics as $metric) {
00536         $xhprof_delta[$parent_child][$metric] = 0;
00537       }
00538     }
00539 
00540     if ($display_calls) {
00541       $xhprof_delta[$parent_child]["ct"] -= $info["ct"];
00542     }
00543 
00544     foreach ($metrics as $metric) {
00545       $xhprof_delta[$parent_child][$metric] -= $info[$metric];
00546     }
00547   }
00548 
00549   return $xhprof_delta;
00550 }
00551 
00552 
00567 function xhprof_compute_inclusive_times($raw_data) {
00568   global $display_calls;
00569 
00570   $metrics = xhprof_get_metrics($raw_data);
00571 
00572   $symbol_tab = array();
00573 
00574   /*
00575    * First compute inclusive time for each function and total
00576    * call count for each function across all parents the
00577    * function is called from.
00578    */
00579   foreach ($raw_data as $parent_child => $info) {
00580 
00581     list($parent, $child) = xhprof_parse_parent_child($parent_child);
00582 
00583     if ($parent == $child) {
00584       /*
00585        * XHProf PHP extension should never trigger this situation any more.
00586        * Recursion is handled in the XHProf PHP extension by giving nested
00587        * calls a unique recursion-depth appended name (for example, foo@1).
00588        */
00589       xhprof_error("Error in Raw Data: parent & child are both: $parent");
00590       return;
00591     }
00592 
00593     if (!isset($symbol_tab[$child])) {
00594 
00595       if ($display_calls) {
00596         $symbol_tab[$child] = array("ct" => $info["ct"]);
00597       } else {
00598         $symbol_tab[$child] = array();
00599       }
00600       foreach ($metrics as $metric) {
00601         $symbol_tab[$child][$metric] = $info[$metric];
00602       }
00603     } else {
00604       if ($display_calls) {
00605         /* increment call count for this child */
00606         $symbol_tab[$child]["ct"] += $info["ct"];
00607       }
00608 
00609       /* update inclusive times/metric for this child  */
00610       foreach ($metrics as $metric) {
00611         $symbol_tab[$child][$metric] += $info[$metric];
00612       }
00613     }
00614   }
00615 
00616   return $symbol_tab;
00617 }
00618 
00619 
00620 /*
00621  * Prunes XHProf raw data:
00622  *
00623  * Any node whose inclusive walltime accounts for less than $prune_percent
00624  * of total walltime is pruned. [It is possible that a child function isn't
00625  * pruned, but one or more of its parents get pruned. In such cases, when
00626  * viewing the child function's hierarchical information, the cost due to
00627  * the pruned parent(s) will be attributed to a special function/symbol
00628  * "__pruned__()".]
00629  *
00630  *  @param   array  $raw_data      XHProf raw data to be pruned & validated.
00631  *  @param   double $prune_percent Any edges that account for less than
00632  *                                 $prune_percent of time will be pruned
00633  *                                 from the raw data.
00634  *
00635  *  @return  array  Returns the pruned raw data.
00636  *
00637  *  @author Kannan
00638  */
00639 function xhprof_prune_run($raw_data, $prune_percent) {
00640 
00641   $main_info = $raw_data["main()"];
00642   if (empty($main_info)) {
00643     xhprof_error("XHProf: main() missing in raw data");
00644     return false;
00645   }
00646 
00647   // raw data should contain either wall time or samples information...
00648   if (isset($main_info["wt"])) {
00649     $prune_metric = "wt";
00650   } else if (isset($main_info["samples"])) {
00651     $prune_metric = "samples";
00652   } else {
00653     xhprof_error("XHProf: for main() we must have either wt "
00654                  ."or samples attribute set");
00655     return false;
00656   }
00657 
00658   // determine the metrics present in the raw data..
00659   $metrics = array();
00660   foreach ($main_info as $metric => $val) {
00661     if (isset($val)) {
00662       $metrics[] = $metric;
00663     }
00664   }
00665 
00666   $prune_threshold = (($main_info[$prune_metric] * $prune_percent) / 100.0);
00667 
00668   init_metrics($raw_data, null, null, false);
00669   $flat_info = xhprof_compute_inclusive_times($raw_data);
00670 
00671   foreach ($raw_data as $parent_child => $info) {
00672 
00673     list($parent, $child) = xhprof_parse_parent_child($parent_child);
00674 
00675     // is this child's overall total from all parents less than threshold?
00676     if ($flat_info[$child][$prune_metric] < $prune_threshold) {
00677       unset($raw_data[$parent_child]); // prune the edge
00678     } else if ($parent &&
00679                ($parent != "__pruned__()") &&
00680                ($flat_info[$parent][$prune_metric] < $prune_threshold)) {
00681 
00682       // Parent's overall inclusive metric is less than a threshold.
00683       // All edges to the parent node will get nuked, and this child will
00684       // be a dangling child.
00685       // So instead change its parent to be a special function __pruned__().
00686       $pruned_edge = xhprof_build_parent_child_key("__pruned__()", $child);
00687 
00688       if (isset($raw_data[$pruned_edge])) {
00689         foreach ($metrics as $metric) {
00690           $raw_data[$pruned_edge][$metric]+=$raw_data[$parent_child][$metric];
00691         }
00692       } else {
00693         $raw_data[$pruned_edge] = $raw_data[$parent_child];
00694       }
00695 
00696       unset($raw_data[$parent_child]); // prune the edge
00697     }
00698   }
00699 
00700   return $raw_data;
00701 }
00702 
00703 
00709 function xhprof_array_set($arr, $k, $v) {
00710   $arr[$k] = $v;
00711   return $arr;
00712 }
00713 
00719 function xhprof_array_unset($arr, $k) {
00720   unset($arr[$k]);
00721   return $arr;
00722 }
00723 
00727 define('XHPROF_STRING_PARAM', 1);
00728 define('XHPROF_UINT_PARAM',   2);
00729 define('XHPROF_FLOAT_PARAM',  3);
00730 define('XHPROF_BOOL_PARAM',   4);
00731 
00732 
00742 function xhprof_get_param_helper($param) {
00743   $val = null;
00744   if (isset($_GET[$param]))
00745     $val = $_GET[$param];
00746   else if (isset($_POST[$param])) {
00747     $val = $_POST[$param];
00748   }
00749   return $val;
00750 }
00751 
00759 function xhprof_get_string_param($param, $default = '') {
00760   $val = xhprof_get_param_helper($param);
00761 
00762   if ($val === null)
00763     return $default;
00764 
00765   return $val;
00766 }
00767 
00778 function xhprof_get_uint_param($param, $default = 0) {
00779   $val = xhprof_get_param_helper($param);
00780 
00781   if ($val === null)
00782     $val = $default;
00783 
00784   // trim leading/trailing whitespace
00785   $val = trim($val);
00786 
00787   // if it only contains digits, then ok..
00788   if (ctype_digit($val)) {
00789     return $val;
00790   }
00791 
00792   xhprof_error("$param is $val. It must be an unsigned integer.");
00793   return null;
00794 }
00795 
00796 
00807 function xhprof_get_float_param($param, $default = 0) {
00808   $val = xhprof_get_param_helper($param);
00809 
00810   if ($val === null)
00811     $val = $default;
00812 
00813   // trim leading/trailing whitespace
00814   $val = trim($val);
00815 
00816   // TBD: confirm the value is indeed a float.
00817   if (true) // for now..
00818     return (float)$val;
00819 
00820   xhprof_error("$param is $val. It must be a float.");
00821   return null;
00822 }
00823 
00834 function xhprof_get_bool_param($param, $default = false) {
00835   $val = xhprof_get_param_helper($param);
00836 
00837   if ($val === null)
00838     $val = $default;
00839 
00840   // trim leading/trailing whitespace
00841   $val = trim($val);
00842 
00843   switch (strtolower($val)) {
00844   case '0':
00845   case '1':
00846     $val = (bool)$val;
00847     break;
00848   case 'true':
00849   case 'on':
00850   case 'yes':
00851     $val = true;
00852     break;
00853   case 'false':
00854   case 'off':
00855   case 'no':
00856     $val = false;
00857     break;
00858   default:
00859     xhprof_error("$param is $val. It must be a valid boolean string.");
00860     return null;
00861   }
00862 
00863   return $val;
00864 
00865 }
00866 
00886 function xhprof_param_init($params) {
00887   /* Create variables specified in $params keys, init defaults */
00888   foreach ($params as $k => $v) {
00889     switch ($v[0]) {
00890     case XHPROF_STRING_PARAM:
00891       $p = xhprof_get_string_param($k, $v[1]);
00892       break;
00893     case XHPROF_UINT_PARAM:
00894       $p = xhprof_get_uint_param($k, $v[1]);
00895       break;
00896     case XHPROF_FLOAT_PARAM:
00897       $p = xhprof_get_float_param($k, $v[1]);
00898       break;
00899     case XHPROF_BOOL_PARAM:
00900       $p = xhprof_get_bool_param($k, $v[1]);
00901       break;
00902     default:
00903       xhprof_error("Invalid param type passed to xhprof_param_init: "
00904                    . $v[0]);
00905       exit();
00906     }
00907 
00908     // create a global variable using the parameter name.
00909     $GLOBALS[$k] = $p;
00910   }
00911 }
00912 
00913 
00921 function xhprof_get_matching_functions($q, $xhprof_data) {
00922 
00923   $matches = array();
00924 
00925   foreach ($xhprof_data as $parent_child => $info) {
00926     list($parent, $child) = xhprof_parse_parent_child($parent_child);
00927     if (stripos($parent, $q) !== false) {
00928       $matches[$parent] = 1;
00929     }
00930     if (stripos($child, $q) !== false) {
00931       $matches[$child] = 1;
00932     }
00933   }
00934 
00935   $res = array_keys($matches);
00936 
00937   // sort it so the answers are in some reliable order...
00938   asort($res);
00939 
00940   return ($res);
00941 }
00942 
 All Data Structures Namespaces Files Functions Variables Enumerations