diff --git a/admin/report/profiling/settings.php b/admin/report/profiling/settings.php index b7c724bbf88..bf2dc5ff2cb 100644 --- a/admin/report/profiling/settings.php +++ b/admin/report/profiling/settings.php @@ -3,6 +3,6 @@ defined('MOODLE_INTERNAL') || die; // profiling report, added to development -if (extension_loaded('xhprof') && function_exists('xhprof_enable') && !empty($CFG->profilingenabled)) { +if (extension_loaded('xhprof') && function_exists('xhprof_enable') && (!empty($CFG->profilingenabled) || !empty($CFG->earlyprofilingenabled))) { $ADMIN->add('development', new admin_externalpage('reportprofiling', get_string('pluginname', 'report_profiling'), "$CFG->wwwroot/$CFG->admin/report/profiling/index.php", 'moodle/site:config')); } diff --git a/config-dist.php b/config-dist.php index e5952af4a3f..61c4e20bc00 100644 --- a/config-dist.php +++ b/config-dist.php @@ -297,6 +297,13 @@ $CFG->admin = 'admin'; // Print to footer (works with the default theme) // define('MDL_PERFTOFOOT', true); // +// Enable earlier profiling that causes more code to be covered +// on every request (db connections, config load, other inits...). +// Requires extra configuration to be defined in config.php like: +// profilingincluded, profilingexcluded, profilingautofrec, +// profilingallowme, profilingallowall, profilinglifetime +// $CFG->earlyprofilingenabled = true; +// // Force displayed usernames // A little hack to anonymise user names for all students. If you set these // then all non-teachers will always see these for every person. diff --git a/lib/setup.php b/lib/setup.php index de6f9fff90b..5c8bcace351 100644 --- a/lib/setup.php +++ b/lib/setup.php @@ -228,6 +228,14 @@ if (!defined('MOODLE_INTERNAL')) { // necessary because cli installer has to def define('MOODLE_INTERNAL', true); } +// Early profiling start, based exclusively on config.php $CFG settings +if (!empty($CFG->earlyprofilingenabled)) { + require_once($CFG->libdir . '/xhprof/xhprof_moodle.php'); + if (profiling_start()) { + register_shutdown_function('profiling_stop'); + } +} + /** * Database connection. Used for all access to the database. * @global moodle_database $DB @@ -669,11 +677,12 @@ session_get_instance(); $SESSION = &$_SESSION['SESSION']; $USER = &$_SESSION['USER']; -// include and start profiling if needed, and register profiling_stop as shutdown function +// Late profiling, only happening if early one wasn't started if (!empty($CFG->profilingenabled)) { require_once($CFG->libdir . '/xhprof/xhprof_moodle.php'); - profiling_start(); - register_shutdown_function('profiling_stop'); + if (profiling_start()) { + register_shutdown_function('profiling_stop'); + } } // Process theme change in the URL. diff --git a/lib/xhprof/readme_moodle.txt b/lib/xhprof/readme_moodle.txt index c75c3d470f9..6168abd7b7f 100644 --- a/lib/xhprof/readme_moodle.txt +++ b/lib/xhprof/readme_moodle.txt @@ -25,9 +25,6 @@ TODO: * export/import profiling runs: Allow to pick any profile record, encapsulate it into some serialized/encoded way and allow download/upload. It requires DB changes in order to be able to specify the source of each record (own/imported). - * move profiling start to earlier place: detect if all the needed $CFG->profilingXXX variables - have been defined in config.php file and if that condition is fullfilled, start profiling - @ the very first lines of setup.php (as early as possible). * improvements to the listing mode: various commodity details like: - allow to filter by various criteria - inline (and ajax) editing of reference/comment and deleting @@ -38,4 +35,5 @@ TODO: - cpu times (all them are right now enabled for everybody by default) -20101122 - Eloy Lafuente (stronk7): Original import of 0.9.2 release +20101122 - MDL-24600 - Eloy Lafuente (stronk7): Original import of 0.9.2 release +20110318 - MDL-26891 - Eloy Lafuente (stronk7): Implemented earlier profiling runs diff --git a/lib/xhprof/xhprof_moodle.php b/lib/xhprof/xhprof_moodle.php index 26958c83bfc..b268c324fb7 100644 --- a/lib/xhprof/xhprof_moodle.php +++ b/lib/xhprof/xhprof_moodle.php @@ -69,7 +69,7 @@ function profiling_start() { } // If profiling isn't enabled, nothing to start - if (!$CFG->profilingenabled) { + if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) { return false; } @@ -78,19 +78,22 @@ function profiling_start() { return false; } + // Set script (from global if available, else our own) + $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script(); + // Get PGC variables $check = 'PROFILEME'; $profileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false; - $profileme = $profileme && $CFG->profilingallowme; + $profileme = $profileme && !empty($CFG->profilingallowme); $check = 'DONTPROFILEME'; $dontprofileme = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false; - $dontprofileme = $dontprofileme && $CFG->profilingallowme; + $dontprofileme = $dontprofileme && !empty($CFG->profilingallowme); $check = 'PROFILEALL'; $profileall = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false; - $profileall = $profileall && $CFG->profilingallowall; + $profileall = $profileall && !empty($CFG->profilingallowall); $check = 'PROFILEALLSTOP'; $profileallstop = isset($_POST[$check]) || isset($_GET[$check]) || isset($_COOKIE[$check]) ? true : false; - $profileallstop = $profileallstop && $CFG->profilingallowall; + $profileallstop = $profileallstop && !empty($CFG->profilingallowall); // DONTPROFILEME detected, nothing to start if ($dontprofileme) { @@ -98,12 +101,12 @@ function profiling_start() { } // PROFILEALLSTOP detected, clean the mark in seesion and continue - if ($profileallstop) { + if ($profileallstop && !empty($SESSION)) { unset($SESSION->profileall); } // PROFILEALL detected, set the mark in session and continue - if ($profileall) { + if ($profileall && !empty($SESSION)) { $SESSION->profileall = true; // SESSION->profileall detected, set $profileall @@ -113,21 +116,23 @@ function profiling_start() { // Evaluate automatic (random) profiling if necessary $profileauto = false; - if ($CFG->profilingautofrec) { + if (!empty($CFG->profilingautofrec)) { $profileauto = (mt_rand(1, $CFG->profilingautofrec) === 1); } - // See if the $SCRIPT matches any of the included patterns - $profileincluded = profiling_string_matches($SCRIPT, $CFG->profilingincluded); + // See if the $script matches any of the included patterns + $included = empty($CFG->profilingincluded) ? '' : $CFG->profilingincluded; + $profileincluded = profiling_string_matches($script, $included); - // See if the $SCRIPT matches any of the excluded patterns - $profileexcluded = profiling_string_matches($SCRIPT, $CFG->profilingexcluded); + // See if the $script matches any of the excluded patterns + $excluded = empty($CFG->profilingexcluded) ? '' : $CFG->profilingexcluded; + $profileexcluded = profiling_string_matches($script, $excluded); // Decide if profile auto must happen (observe matchings) $profileauto = $profileauto && $profileincluded && !$profileexcluded; // Decide if profile by match must happen (only if profileauto is disabled) - $profilematch = $profileincluded && !$profileexcluded && !$CFG->profilingautofrec; + $profilematch = $profileincluded && !$profileexcluded && empty($CFG->profilingautofrec); // If not auto, me, all, match have been detected, nothing to do if (!$profileauto && !$profileme && !$profileall && !$profilematch) { @@ -138,6 +143,9 @@ function profiling_start() { $ignore = array('call_user_func', 'call_user_func_array'); xhprof_enable(XHPROF_FLAGS_CPU + XHPROF_FLAGS_MEMORY, array('ignored_functions' => $ignore)); profiling_is_running(true); + + // Started, return true + return true; } /** @@ -152,7 +160,7 @@ function profiling_stop() { } // If profiling isn't enabled, nothing to stop - if (!$CFG->profilingenabled) { + if (empty($CFG->profilingenabled) && empty($CFG->earlyprofilingenabled)) { return false; } @@ -161,17 +169,23 @@ function profiling_stop() { return false; } + // Set script (from global if available, else our own) + $script = !empty($SCRIPT) ? $SCRIPT : profiling_get_script(); + // Arrived here, profiling is running, stop and save everything profiling_is_running(false); $data = xhprof_disable(); $run = new moodle_xhprofrun(); - $run->prepare_run($SCRIPT); + $run->prepare_run($script); $runid = $run->save_run($data, null); profiling_is_saved(true); // Prune old runs profiling_prune_old_runs($runid); + + // Finished, return true + return true; } function profiling_prune_old_runs($exception = 0) { @@ -190,6 +204,34 @@ function profiling_prune_old_runs($exception = 0) { runid != :exception', $params); } +/** + * Returns the path to the php script being requested + * + * Note this function is a partial copy of initialise_fullme() and + * setup_get_remote_url(), in charge of setting $FULLME, $SCRIPT and + * friends. To be used by early profiling runs in situations where + * $SCRIPT isn't defined yet + * + * @return string absolute path (wwwroot based) of the script being executed + */ +function profiling_get_script() { + global $CFG; + + $wwwroot = parse_url($CFG->wwwroot); + + if (!isset($wwwroot['path'])) { + $wwwroot['path'] = ''; + } + $wwwroot['path'] .= '/'; + + $path = $_SERVER['SCRIPT_NAME']; + + if (strpos($path, $wwwroot['path']) === 0) { + return substr($path, strlen($wwwroot['path']) - 1); + } + return ''; +} + function profiling_urls($report, $runid, $runid2 = null) { global $CFG;