Moodle  2.2.1
http://www.collinsharper.com
C:/xampp/htdocs/moodle/lib/xhprof/xhprof_moodle.php
Go to the documentation of this file.
00001 <?php
00002 // This file is part of Moodle - http://moodle.org/
00003 //
00004 // Moodle is free software: you can redistribute it and/or modify
00005 // it under the terms of the GNU General Public License as published by
00006 // the Free Software Foundation, either version 3 of the License, or
00007 // (at your option) any later version.
00008 //
00009 // Moodle is distributed in the hope that it will be useful,
00010 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00011 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012 // GNU General Public License for more details.
00013 //
00014 // You should have received a copy of the GNU General Public License
00015 // along with Moodle.  If not, see <http://www.gnu.org/licenses/>.
00016 
00024 defined('MOODLE_INTERNAL') || die();
00025 
00026 // need some stuff from xhprof
00027 require_once($CFG->libdir . '/xhprof/xhprof_lib/utils/xhprof_lib.php');
00028 require_once($CFG->libdir . '/xhprof/xhprof_lib/utils/xhprof_runs.php');
00029 // need some stuff from moodle
00030 require_once($CFG->libdir.'/tablelib.php');
00031 
00032 // TODO: Change the implementation below to proper profiling class
00033 
00037 function profiling_is_running($value = null) {
00038     static $running = null;
00039 
00040     if (!is_null($value)) {
00041         $running = (bool)$value;
00042     }
00043 
00044     return $running;
00045 }
00046 
00050 function profiling_is_saved($value = null) {
00051     static $saved = null;
00052 
00053     if (!is_null($value)) {
00054         $saved = (bool)$value;
00055     }
00056 
00057     return $saved;
00058 }
00059 
00063 function profiling_start() {
00064     global $CFG, $SESSION, $SCRIPT;
00065 
00066     // If profiling isn't available, nothing to start
00067     if (!extension_loaded('xhprof') || !function_exists('xhprof_enable')) {
00068         return false;
00069     }
00070 
00071     // If profiling isn't enabled, nothing to start
00072     if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) {
00073         return false;
00074     }
00075 
00076     // If profiling is already running or saved, nothing to start
00077     if (profiling_is_running() || profiling_is_saved()) {
00078         return false;
00079     }
00080 
00081     // Set script (from global if available, else our own)
00082     $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script();
00083 
00084     // Get PGC variables
00085     $check = 'PROFILEME';
00086     $profileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
00087     $profileme = $profileme && !empty($CFG->profilingallowme);
00088     $check = 'DONTPROFILEME';
00089     $dontprofileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
00090     $dontprofileme = $dontprofileme && !empty($CFG->profilingallowme);
00091     $check = 'PROFILEALL';
00092     $profileall = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
00093     $profileall = $profileall && !empty($CFG->profilingallowall);
00094     $check = 'PROFILEALLSTOP';
00095     $profileallstop = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false;
00096     $profileallstop = $profileallstop && !empty($CFG->profilingallowall);
00097 
00098     // DONTPROFILEME detected, nothing to start
00099     if ($dontprofileme) {
00100         return false;
00101     }
00102 
00103     // PROFILEALLSTOP detected, clean the mark in seesion and continue
00104     if ($profileallstop && !empty($SESSION)) {
00105         unset($SESSION->profileall);
00106     }
00107 
00108     // PROFILEALL detected, set the mark in session and continue
00109     if ($profileall && !empty($SESSION)) {
00110         $SESSION->profileall = true;
00111 
00112     // SESSION->profileall detected, set $profileall
00113     } else if (!empty($SESSION->profileall)) {
00114         $profileall = true;
00115     }
00116 
00117     // Evaluate automatic (random) profiling if necessary
00118     $profileauto = false;
00119     if (!empty($CFG->profilingautofrec)) {
00120         $profileauto = (mt_rand(1, $CFG->profilingautofrec) === 1);
00121     }
00122 
00123     // See if the $script matches any of the included patterns
00124     $included = empty($CFG->profilingincluded) ? '' : $CFG->profilingincluded;
00125     $profileincluded = profiling_string_matches($script, $included);
00126 
00127     // See if the $script matches any of the excluded patterns
00128     $excluded = empty($CFG->profilingexcluded) ? '' : $CFG->profilingexcluded;
00129     $profileexcluded = profiling_string_matches($script, $excluded);
00130 
00131     // Decide if profile auto must happen (observe matchings)
00132     $profileauto = $profileauto && $profileincluded && !$profileexcluded;
00133 
00134     // Decide if profile by match must happen (only if profileauto is disabled)
00135     $profilematch = $profileincluded && !$profileexcluded && empty($CFG->profilingautofrec);
00136 
00137     // If not auto, me, all, match have been detected, nothing to do
00138     if (!$profileauto && !$profileme && !$profileall && !$profilematch) {
00139         return false;
00140     }
00141 
00142     // Arrived here, the script is going to be profiled, let's do it
00143     $ignore = array('call_user_func', 'call_user_func_array');
00144     xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY, array('ignored_functions' =>  $ignore));
00145     profiling_is_running(true);
00146 
00147     // Started, return true
00148     return true;
00149 }
00150 
00154 function profiling_stop() {
00155     global $CFG, $DB, $SCRIPT;
00156 
00157     // If profiling isn't available, nothing to stop
00158     if (!extension_loaded('xhprof') || !function_exists('xhprof_enable')) {
00159         return false;
00160     }
00161 
00162     // If profiling isn't enabled, nothing to stop
00163     if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) {
00164         return false;
00165     }
00166 
00167     // If profiling is not running or is already saved, nothing to stop
00168     if (!profiling_is_running() || profiling_is_saved()) {
00169         return false;
00170     }
00171 
00172     // Set script (from global if available, else our own)
00173     $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script();
00174 
00175     // Arrived here, profiling is running, stop and save everything
00176     profiling_is_running(false);
00177     $data = xhprof_disable();
00178 
00179     // We only save the run after ensuring the DB table exists
00180     // (this prevents problems with profiling runs enabled in
00181     // config.php before Moodle is installed. Rare but...
00182     $tables = $DB->get_tables();
00183     if (!in_array('profiling', $tables)) {
00184         return false;
00185     }
00186 
00187     $run = new moodle_xhprofrun();
00188     $run->prepare_run($script);
00189     $runid = $run->save_run($data, null);
00190     profiling_is_saved(true);
00191 
00192     // Prune old runs
00193     profiling_prune_old_runs($runid);
00194 
00195     // Finished, return true
00196     return true;
00197 }
00198 
00199 function profiling_prune_old_runs($exception = 0) {
00200     global $CFG, $DB;
00201 
00202     // Setting to 0 = no prune
00203     if (empty($CFG->profilinglifetime)) {
00204         return;
00205     }
00206 
00207     $cuttime = time() - ($CFG->profilinglifetime * 60);
00208     $params = array('cuttime' => $cuttime, 'exception' => $exception);
00209 
00210     $DB->delete_records_select('profiling', 'runreference = 0 AND
00211                                              timecreated < :cuttime AND
00212                                              runid != :exception', $params);
00213 }
00214 
00225 function profiling_get_script() {
00226     global $CFG;
00227 
00228     $wwwroot = parse_url($CFG->wwwroot);
00229 
00230     if (!isset($wwwroot['path'])) {
00231         $wwwroot['path'] = '';
00232     }
00233     $wwwroot['path'] .= '/';
00234 
00235     $path = $_SERVER['SCRIPT_NAME'];
00236 
00237     if (strpos($path, $wwwroot['path']) === 0) {
00238         return substr($path, strlen($wwwroot['path']) - 1);
00239     }
00240     return '';
00241 }
00242 
00243 function profiling_urls($report, $runid, $runid2 = null) {
00244     global $CFG;
00245 
00246     $url = '';
00247     switch ($report) {
00248         case 'run':
00249             $url = $CFG->wwwroot . '/lib/xhprof/xhprof_html/index.php?run=' . $runid;
00250             break;
00251         case 'diff':
00252             $url = $CFG->wwwroot . '/lib/xhprof/xhprof_html/index.php?run1=' . $runid . '&amp;run2=' . $runid2;
00253             break;
00254         case 'graph':
00255             $url = $CFG->wwwroot . '/lib/xhprof/xhprof_html/callgraph.php?run=' . $runid;
00256             break;
00257     }
00258     return $url;
00259 }
00260 
00261 function profiling_print_run($run, $prevrunid = null) {
00262     global $CFG, $OUTPUT;
00263 
00264     $output = '';
00265 
00266     // Prepare the runreference/runcomment form
00267     $checked = $run->runreference ? ' checked=checked' : '';
00268     $referenceform = "<form id=\"profiling_runreference\" action=\"index.php\" method=\"GET\">" .
00269                      "<input type=\"hidden\" name=\"sesskey\" value=\"" . sesskey() . "\"/>".
00270                      "<input type=\"hidden\" name=\"runid\" value=\"$run->runid\"/>".
00271                      "<input type=\"hidden\" name=\"listurl\" value=\"$run->url\"/>".
00272                      "<input type=\"checkbox\" name=\"runreference\" value=\"1\"$checked/>&nbsp;".
00273                      "<input type=\"text\" name=\"runcomment\" value=\"$run->runcomment\"/>&nbsp;".
00274                      "<input type=\"submit\" value=\"" . get_string('savechanges') ."\"/>".
00275                      "</form>";
00276 
00277     $table = new html_table();
00278     $table->align = array('right', 'left');
00279     $table->tablealign = 'center';
00280     $table->attributes['class'] = 'profilingruntable';
00281     $table->colclasses = array('label', 'value');
00282     $table->data = array(
00283        array(get_string('runid', 'tool_profiling'), $run->runid),
00284        array(get_string('url'), $run->url),
00285        array(get_string('date'), userdate($run->timecreated, '%d %B %Y, %H:%M')),
00286        array(get_string('executiontime', 'tool_profiling'), format_float($run->totalexecutiontime / 1000, 3) . ' ms'),
00287        array(get_string('cputime', 'tool_profiling'), format_float($run->totalcputime / 1000, 3) . ' ms'),
00288        array(get_string('calls', 'tool_profiling'), $run->totalcalls),
00289        array(get_string('memory', 'tool_profiling'), format_float($run->totalmemory / 1024, 0) . ' KB'),
00290        array(get_string('markreferencerun', 'tool_profiling'), $referenceform));
00291     $output = $OUTPUT->box(html_writer::table($table), 'generalbox boxwidthwide boxaligncenter profilingrunbox', 'profiling_summary', true);
00292     // Add link to details
00293     $strviewdetails = get_string('viewdetails', 'tool_profiling');
00294     $url = profiling_urls('run', $run->runid);
00295     $output.=$OUTPUT->heading('<a href="' . $url . '" onclick="javascript:window.open(' . "'" . $url . "'" . ');' .
00296                               'return false;"' . ' title="">' . $strviewdetails . '</a>', 3, 'main profilinglink');
00297     // If there is one previous run marked as reference, add link to diff
00298     if ($prevrunid) {
00299         $strviewdiff = get_string('viewdiff', 'tool_profiling');
00300         $url = 'index.php?runid=' . $run->runid . '&amp;runid2=' . $prevrunid . '&amp;listurl=' . urlencode($run->url);
00301         $output.=$OUTPUT->heading('<a href="' . $url . '" title="">' . $strviewdiff . '</a>', 3, 'main profilinglink');
00302     }
00303 
00304     return $output;
00305 }
00306 
00307 function profiling_print_rundiff($run1, $run2) {
00308     global $CFG, $OUTPUT;
00309 
00310     $output = '';
00311 
00312     // Prepare the reference/comment information
00313     $referencetext1 = ($run1->runreference ? get_string('yes') : get_string('no')) .
00314                       ($run1->runcomment ? ' - ' . s($run1->runcomment) : '');
00315     $referencetext2 = ($run2->runreference ? get_string('yes') : get_string('no')) .
00316                       ($run2->runcomment ? ' - ' . s($run2->runcomment) : '');
00317 
00318     // Calculate global differences
00319     $diffexecutiontime = profiling_get_difference($run1->totalexecutiontime, $run2->totalexecutiontime, 'ms', 1000);
00320     $diffcputime       = profiling_get_difference($run1->totalcputime, $run2->totalcputime, 'ms', 1000);
00321     $diffcalls         = profiling_get_difference($run1->totalcalls, $run2->totalcalls);
00322     $diffmemory        = profiling_get_difference($run1->totalmemory, $run2->totalmemory, 'KB', 1024);
00323 
00324     $table = new html_table();
00325     $table->align = array('right', 'left', 'left', 'left');
00326     $table->tablealign = 'center';
00327     $table->attributes['class'] = 'profilingruntable';
00328     $table->colclasses = array('label', 'value1', 'value2');
00329     $table->data = array(
00330        array(get_string('runid', 'tool_profiling'),
00331            '<a href="index.php?runid=' . $run1->runid . '&listurl=' . urlencode($run1->url) . '" title="">' . $run1->runid . '</a>',
00332            '<a href="index.php?runid=' . $run2->runid . '&listurl=' . urlencode($run2->url) . '" title="">' . $run2->runid . '</a>'),
00333        array(get_string('url'), $run1->url, $run2->url),
00334        array(get_string('date'), userdate($run1->timecreated, '%d %B %Y, %H:%M'),
00335            userdate($run2->timecreated, '%d %B %Y, %H:%M')),
00336        array(get_string('executiontime', 'tool_profiling'),
00337            format_float($run1->totalexecutiontime / 1000, 3) . ' ms',
00338            format_float($run2->totalexecutiontime / 1000, 3) . ' ms ' . $diffexecutiontime),
00339        array(get_string('cputime', 'tool_profiling'),
00340            format_float($run1->totalcputime / 1000, 3) . ' ms',
00341            format_float($run2->totalcputime / 1000, 3) . ' ms ' . $diffcputime),
00342        array(get_string('calls', 'tool_profiling'), $run1->totalcalls, $run2->totalcalls . ' ' . $diffcalls),
00343        array(get_string('memory', 'tool_profiling'),
00344            format_float($run1->totalmemory / 1024, 0) . ' KB',
00345            format_float($run2->totalmemory / 1024, 0) . ' KB ' . $diffmemory),
00346        array(get_string('referencerun', 'tool_profiling'), $referencetext1, $referencetext2));
00347     $output = $OUTPUT->box(html_writer::table($table), 'generalbox boxwidthwide boxaligncenter profilingrunbox', 'profiling_summary', true);
00348     // Add link to details
00349     $strviewdetails = get_string('viewdiffdetails', 'tool_profiling');
00350     $url = profiling_urls('diff', $run1->runid, $run2->runid);
00351     //$url =  $CFG->wwwroot . '/admin/tool/profiling/index.php?run=' . $run->runid;
00352     $output.=$OUTPUT->heading('<a href="' . $url . '" onclick="javascript:window.open(' . "'" . $url . "'" . ');' .
00353                               'return false;"' . ' title="">' . $strviewdetails . '</a>', 3, 'main profilinglink');
00354     return $output;
00355 }
00356 
00362 function profiling_list_controls($listurl) {
00363     global $CFG, $OUTPUT;
00364 
00365     $output = '';
00366 
00367     return $output;
00368 }
00369 
00374 function profiling_string_matches($string, $patterns) {
00375     $patterns = explode(',', $patterns);
00376     foreach ($patterns as $pattern) {
00377         // Trim and prepare pattern
00378         $pattern = str_replace('\*', '.*', preg_quote(trim($pattern), '~'));
00379         // Don't process empty patterns
00380         if (empty($pattern)) {
00381             continue;
00382         }
00383         if (preg_match('~' . $pattern . '~', $string)) {
00384             return true;
00385         }
00386     }
00387     return false;
00388 }
00389 
00394 function profiling_get_difference($number1, $number2, $units = '', $factor = 1, $numdec = 2) {
00395     $numdiff = $number2 - $number1;
00396     $perdiff = 0;
00397     if ($number1 != $number2) {
00398         $perdiff = $number1 != 0 ? ($number2 * 100 / $number1) - 100 : 0;
00399     }
00400     $sign      = $number2 > $number1 ? '+' : '';
00401     $delta     = abs($perdiff) > 0.25 ? '&Delta;' : '&asymp;';
00402     $spanclass = $number2 > $number1 ? 'worse' : ($number1 > $number2 ? 'better' : 'same');
00403     $importantclass= abs($perdiff) > 1 ? ' profiling_important' : '';
00404     $startspan = '<span class="profiling_' . $spanclass . $importantclass . '">';
00405     $endspan   = '</span>';
00406     $fnumdiff = $sign . format_float($numdiff / $factor, $numdec);
00407     $fperdiff = $sign . format_float($perdiff, $numdec);
00408     return $startspan . $delta . ' ' . $fnumdiff . ' ' . $units . ' (' . $fperdiff . '%)' . $endspan;
00409 }
00410 
00421 class moodle_xhprofrun implements iXHProfRuns {
00422 
00423     protected $runid = null;
00424     protected $url = null;
00425     protected $totalexecutiontime = 0;
00426     protected $totalcputime = 0;
00427     protected $totalcalls = 0;
00428     protected $totalmemory = 0;
00429     protected $timecreated = 0;
00430 
00431     public function __construct() {
00432         $this->timecreated = time();
00433     }
00434 
00441     public function get_run($run_id, $type, &$run_desc) {
00442         global $DB;
00443 
00444         $rec = $DB->get_record('profiling', array('runid' => $run_id), '*', MUST_EXIST);
00445 
00446         $this->runid = $rec->runid;
00447         $this->url = $rec->url;
00448         $this->totalexecutiontime = $rec->totalexecutiontime;
00449         $this->totalcputime = $rec->totalcputime;
00450         $this->totalcalls = $rec->totalcalls;
00451         $this->totalmemory = $rec->totalmemory;
00452         $this->timecreated = $rec->timecreated;
00453 
00454         $run_desc = $this->url . ($rec->runreference ? ' (R) ' : ' ') . ' - ' . s($rec->runcomment);
00455 
00456         return unserialize(base64_decode($rec->data));
00457     }
00458 
00465     public function save_run($xhprof_data, $type, $run_id = null) {
00466         global $DB;
00467 
00468         if (is_null($this->url)) {
00469             xhprof_error("Warning: You must use the prepare_run() method before saving it");
00470         }
00471 
00472         // Calculate runid if needed
00473         $this->runid = is_null($run_id) ? md5($this->url . '-' . uniqid()) : $run_id;
00474 
00475         // Calculate totals
00476         $this->totalexecutiontime = $xhprof_data['main()']['wt'];
00477         $this->totalcputime = $xhprof_data['main()']['cpu'];
00478         $this->totalcalls = array_reduce($xhprof_data, array($this, 'sum_calls'));
00479         $this->totalmemory = $xhprof_data['main()']['mu'];
00480 
00481         // Prepare data
00482         $rec = new stdClass();
00483         $rec->runid = $this->runid;
00484         $rec->url = $this->url;
00485         $rec->data = base64_encode(serialize($xhprof_data));
00486         $rec->totalexecutiontime = $this->totalexecutiontime;
00487         $rec->totalcputime = $this->totalcputime;
00488         $rec->totalcalls = $this->totalcalls;
00489         $rec->totalmemory = $this->totalmemory;
00490         $rec->timecreated = $this->timecreated;
00491 
00492         $DB->insert_record('profiling', $rec);
00493         return $this->runid;
00494     }
00495 
00496     public function prepare_run($url) {
00497         $this->url = $url;
00498     }
00499 
00500     // Private API starts here
00501 
00502     protected function sum_calls($sum, $data) {
00503         return $sum + $data['ct'];
00504     }
00505 }
00506 
00512 class xhprof_table_sql extends table_sql {
00513 
00514     protected $listurlmode = false;
00515 
00519     function get_row_class($row) {
00520         return $row->runreference ? 'referencerun' : ''; // apply class to reference runs
00521     }
00522 
00527     function set_listurlmode($listurlmode) {
00528         $this->listurlmode = $listurlmode;
00529     }
00530 
00534     protected function col_url($row) {
00535         global $OUTPUT;
00536 
00537         // Build the link to latest run for the script
00538         $scripturl = new moodle_url('/admin/tool/profiling/index.php', array('script' => $row->url, 'listurl' => $row->url));
00539         $scriptaction = $OUTPUT->action_link($scripturl, $row->url);
00540 
00541         // Decide, based on $this->listurlmode which actions to show
00542         if ($this->listurlmode) {
00543             $detailsaction = '';
00544         } else {
00545             // Build link icon to script details (pix + url + actionlink)
00546             $detailsimg = $OUTPUT->pix_icon('t/right', get_string('profilingfocusscript', 'tool_profiling', $row->url));
00547             $detailsurl = new moodle_url('/admin/tool/profiling/index.php', array('listurl' => $row->url));
00548             $detailsaction = $OUTPUT->action_link($detailsurl, $detailsimg);
00549         }
00550 
00551         return $scriptaction . '&nbsp;' . $detailsaction;
00552     }
00553 
00557     protected function col_timecreated($row) {
00558         global $OUTPUT;
00559         $fdate = userdate($row->timecreated, '%d %b %Y, %H:%M');
00560         $url = new moodle_url('/admin/tool/profiling/index.php', array('runid' => $row->runid, 'listurl' => $row->url));
00561         return $OUTPUT->action_link($url, $fdate);
00562     }
00563 
00567     protected function col_totalexecutiontime($row) {
00568         return format_float($row->totalexecutiontime / 1000, 3) . ' ms';
00569     }
00570 
00574     protected function col_totalcputime($row) {
00575         return format_float($row->totalcputime / 1000, 3) . ' ms';
00576     }
00577 
00581     protected function col_totalmemory($row) {
00582         return format_float($row->totalmemory / 1024, 3) . ' KB';
00583     }
00584 }
 All Data Structures Namespaces Files Functions Variables Enumerations