From c646dd26ea6c2f5bc873eec366af38a641e040eb Mon Sep 17 00:00:00 2001 From: "Eloy Lafuente (stronk7)" Date: Sat, 19 Mar 2011 00:32:45 +0100 Subject: [PATCH] MDL-26891 profiling - earlier runs This allows profiling to be started earlier in the setup.php execution, by configuring everything in the config.php file. That way some interesting code is also profiled, like DB connections, load of config records... 100% compatible with normal profiling and enabled via special setting $CFG->earlyprofilingenabled Example (to be put on config.php): $CFG->earlyprofilingenabled = true; $CFG->profilingautofrec = 3; $CFG->profilingincluded = '/*'; $CFG->profilingallowme = true; (to enable early profiling for 1/3 of any requests while also allowing to use the PROFILEME PGC) --- admin/report/profiling/settings.php | 2 +- config-dist.php | 7 +++ lib/setup.php | 15 ++++-- lib/xhprof/readme_moodle.txt | 6 +-- lib/xhprof/xhprof_moodle.php | 72 +++++++++++++++++++++++------ 5 files changed, 79 insertions(+), 23 deletions(-) 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;