MDL-39733 xhprof: implement import of runs

This commit is contained in:
Eloy Lafuente (stronk7) 2013-06-16 17:02:27 +02:00
parent 2e07539699
commit 2e746b72be
11 changed files with 192 additions and 18 deletions

View File

@ -65,6 +65,10 @@ if ($hassiteconfig) { // speedup for non-admins, add all caps used on this page
60 => new lang_string('numminutes', '', 60),
30 => new lang_string('numminutes', '', 30),
15 => new lang_string('numminutes', '', 15))));
// Define the prefix to be added to imported profiling runs.
$temp->add(new admin_setting_configtext('profilingimportprefix',
new lang_string('profilingimportprefix', 'admin'),
new lang_string('profilingimportprefix_desc', 'admin'), '(I)', PARAM_TAG, 10));
// Add the 'profiling' page to admin block
$ADMIN->add('development', $temp);

View File

@ -48,7 +48,11 @@ if ($data = $mform->get_data()) {
$status = $mform->save_file('mprfile', $file);
if ($status) {
// File saved properly, let's import it.
$status = profiling_import_runs($file);
$status = profiling_import_runs($file, $data->importprefix);
}
// Delete the temp file, not needed anymore.
if (file_exists($file)) {
unlink($file);
}
if ($status) {
// Import ended ok, let's redirect to main profiling page.

View File

@ -27,14 +27,21 @@ defined('MOODLE_INTERNAL') || die();
require_once($CFG->libdir . '/formslib.php');
class profiling_import_form extends moodleform {
function definition () {
public function definition () {
global $CFG;
$mform = $this->_form;
$mform->addElement('header', 'settingsheader', get_string('upload'));
$mform->addElement('filepicker', 'mprfile', get_string('file'), null, array('accepted_types' => array('.mpr')));
$mform->addElement('filepicker', 'mprfile', get_string('file'), null, array('accepted_types' => array('.mpr', '.zip')));
$mform->addRule('mprfile', null, 'required');
$mform->addElement('text', 'importprefix',
get_string('importprefix', 'tool_profiling'), array('size' => 10));
$mform->setDefault('importprefix', $CFG->profilingimportprefix);
$mform->setType('importprefix', PARAM_TAG);
$this->add_action_buttons(false, get_string('import', 'tool_profiling'));
}
}

View File

@ -160,7 +160,7 @@ if (isset($script)) {
echo $OUTPUT->heading($header);
// Print the controller block with different options
// Print the controller block with different options.
echo profiling_list_controls($listurl);
// TODO: Fix flexitable to validate tsort/thide/tshow/tifirs/tilast/page

View File

@ -38,6 +38,7 @@ $string['exportproblem'] = 'Some problem happened exporting the profile run "{$a
$string['exportthis'] = 'Export this profiling run';
$string['import'] = 'Import';
$string['importok'] = 'File "{$a}" imported successfully.';
$string['importprefix'] = 'Import prefix';
$string['importproblem'] = 'Some problem happened importing the file "{$a}".';
$string['lastrunof'] = 'Summary of last run of {$a}';
$string['markreferencerun'] = 'Mark as reference run/comment';

View File

@ -17,14 +17,13 @@
/**
* Version details.
*
* @package tool
* @subpackage profiling
* @package tool_profiling
* @copyright 2010 onwards Eloy Lafuente (stronk7) {@link http://stronk7.com}
* @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
*/
defined('MOODLE_INTERNAL') || die();
$plugin->version = 2013050100; // The current plugin version (Date: YYYYMMDDXX)
$plugin->version = 2013050200; // The current plugin version (Date: YYYYMMDDXX)
$plugin->requires = 2013050100; // Requires this Moodle version
$plugin->component = 'tool_profiling'; // Full name of the plugin (used for diagnostics)

View File

@ -874,6 +874,8 @@ $string['profilingenabled'] = 'Enable profiling';
$string['profilingenabled_help'] = 'If you enable this setting, then profiling will be available in this site and you will be able to define its behavior by configuring the next options.';
$string['profilingexcluded'] = 'Exclude profiling';
$string['profilingexcluded_help'] = 'List of (comma separated, absolute skipping wwwroot, callable) URLs that will be excluded from being profiled from the ones defined by \'Profile these\' setting.';
$string['profilingimportprefix'] = 'Profiling import prefix';
$string['profilingimportprefix_desc'] = 'For easier detection, all the imported profiling runs will be prefixed with the value specified here.';
$string['profilingincluded'] = 'Profile these';
$string['profilingincluded_help'] = 'List of (comma separated, absolute skipping wwwroot, callable) URLs that will be automatically profiled. Examples: /index.php, /course/view.php. Also accepts the * wildchar at any position. Examples: /mod/forum/*, /mod/*/view.php.';
$string['profilinglifetime'] = 'Keep profiling runs';

View File

@ -1449,6 +1449,7 @@ function &get_mimetypes_array() {
'mpeg' => array ('type'=>'video/mpeg', 'icon'=>'mpeg', 'groups'=>array('video','web_video'), 'string'=>'video'),
'mpe' => array ('type'=>'video/mpeg', 'icon'=>'mpeg', 'groups'=>array('video','web_video'), 'string'=>'video'),
'mpg' => array ('type'=>'video/mpeg', 'icon'=>'mpeg', 'groups'=>array('video','web_video'), 'string'=>'video'),
'mpr' => array ('type'=>'application/vnd.moodle.profiling', 'icon'=>'moodle'),
'nbk' => array ('type'=>'application/x-smarttech-notebook', 'icon'=>'archive'),
'notebook' => array ('type'=>'application/x-smarttech-notebook', 'icon'=>'archive'),

View File

@ -6070,6 +6070,7 @@ function get_file_packer($mimetype='application/zip') {
switch ($mimetype) {
case 'application/zip':
case 'application/vnd.moodle.backup':
case 'application/vnd.moodle.profiling':
$classname = 'zip_packer';
break;
case 'application/x-tar':

View File

@ -24,9 +24,6 @@ TODO:
* with the 3 reports (index, callgraph and typeahead), close seesion asap,
so user can continue working with moodle while the report (specially
the graph is being generated).
* 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).
* improvements to the listing mode: various commodity details like:
- allow to filter by various criteria
- inline (and ajax) editing of reference/comment and deleting
@ -36,6 +33,9 @@ TODO:
- memory
- cpu times
(all them are right now enabled for everybody by default)
* allow multiple runs to be exported together (right now only ONE can be
exported at a time). Note it is only an UI restriction, backend supports multiple.
20101122 - MDL-24600 - Eloy Lafuente (stronk7): Original import of 0.9.2 release
20110318 - MDL-26891 - Eloy Lafuente (stronk7): Implemented earlier profiling runs
20130621 - MDL-39733 - Eloy Lafuente (stronk7): Export & import of profiling runs

View File

@ -423,7 +423,7 @@ function profiling_get_difference($number1, $number2, $units = '', $factor = 1,
* Export profiling runs to a .mpr (moodle profile runs) file.
*
* This function gets an array of profiling runs (array of runids) and
* saves a .mpr file into destinantion for ulterior handling.
* saves a .mpr file into destination for ulterior handling.
*
* Format of .mpr files:
* mpr files are simple zip packages containing these files:
@ -435,12 +435,12 @@ function profiling_get_difference($number1, $number2, $units = '', $factor = 1,
* - runid.xml: One file per each run detailed in the main file,
* containing the raw dump of the given runid in the profiling table.
*
* Posible improvement: Start storing some extra information in the
* Possible improvement: Start storing some extra information in the
* profiling table for each run (moodle version, database, git hash...).
*
* @param array $runids list of runids to be exported.
* @param string $file filesystem fullpath to destination .mpr file.
* @return boolean the mpr file has been succesfully exported (true) or no (false).
* @return boolean the mpr file has been successfully exported (true) or no (false).
*/
function profiling_export_runs(array $runids, $file) {
global $CFG, $DB;
@ -475,7 +475,7 @@ function profiling_export_runs(array $runids, $file) {
$status = profiling_export_package($file, $tmpdir);
}
// Process finished ok, clean and return
// Process finished ok, clean and return.
fulldelete($tmpdir);
return $status;
}
@ -487,10 +487,86 @@ function profiling_export_runs(array $runids, $file) {
* implementation of .mpr files.
*
* @param string $file filesystem fullpath to target .mpr file.
* @return boolean the mpr file has been succesfully imported (true) or no (false).
* @param string $commentprefix prefix to add to the comments of all the imported runs.
* @return boolean the mpr file has been successfully imported (true) or no (false).
*/
function profiling_import_runs($file) {
return true;
function profiling_import_runs($file, $commentprefix = '') {
global $DB;
// Any problem with the file or its directory, abort.
if (!file_exists($file) or !is_readable($file) or !is_writable(dirname($file))) {
return false;
}
// Unzip the file into temp directory.
$tmpdir = dirname($file) . '/' . time() . '_' . random_string(4);
$fp = get_file_packer('application/vnd.moodle.profiling');
$status = $fp->extract_to_pathname($file, $tmpdir);
// Look for master file and verify its format.
if ($status) {
$mfile = $tmpdir . '/moodle_profiling_runs.xml';
if (!file_exists($mfile) or !is_readable($mfile)) {
$status = false;
} else {
$mdom = new DOMDocument();
if (!$mdom->load($mfile)) {
$status = false;
} else {
$status = @$mdom->schemaValidateSource(profiling_get_import_main_schema());
}
}
}
// Verify all detail files exist and verify their format.
if ($status) {
$runs = $mdom->getElementsByTagName('run');
foreach ($runs as $run) {
$rfile = $tmpdir . '/' . clean_param($run->getAttribute('ref'), PARAM_FILE);
if (!file_exists($rfile) or !is_readable($rfile)) {
$status = false;
} else {
$rdom = new DOMDocument();
if (!$rdom->load($rfile)) {
$status = false;
} else {
$status = @$rdom->schemaValidateSource(profiling_get_import_run_schema());
}
}
}
}
// Everything looks ok, let's import all the runs.
if ($status) {
reset($runs);
foreach ($runs as $run) {
$rfile = $tmpdir . '/' . $run->getAttribute('ref');
$rdom = new DOMDocument();
$rdom->load($rfile);
$runarr = array();
$runarr['runid'] = clean_param($rdom->getElementsByTagName('runid')->item(0)->nodeValue, PARAM_ALPHANUMEXT);
$runarr['url'] = clean_param($rdom->getElementsByTagName('url')->item(0)->nodeValue, PARAM_CLEAN);
$runarr['runreference'] = clean_param($rdom->getElementsByTagName('runreference')->item(0)->nodeValue, PARAM_INT);
$runarr['runcomment'] = $commentprefix . clean_param($rdom->getElementsByTagName('runcomment')->item(0)->nodeValue, PARAM_CLEAN);
$runarr['timecreated'] = time(); // Now.
$runarr['totalexecutiontime'] = clean_param($rdom->getElementsByTagName('totalexecutiontime')->item(0)->nodeValue, PARAM_INT);
$runarr['totalcputime'] = clean_param($rdom->getElementsByTagName('totalcputime')->item(0)->nodeValue, PARAM_INT);
$runarr['totalcalls'] = clean_param($rdom->getElementsByTagName('totalcalls')->item(0)->nodeValue, PARAM_INT);
$runarr['totalmemory'] = clean_param($rdom->getElementsByTagName('totalmemory')->item(0)->nodeValue, PARAM_INT);
$runarr['data'] = clean_param($rdom->getElementsByTagName('data')->item(0)->nodeValue, PARAM_CLEAN);
// If the runid does not exist, insert it.
if (!$DB->record_exists('profiling', array('runid' => $runarr['runid']))) {
$DB->insert_record('profiling', $runarr);
} else {
return false;
}
}
}
// Clean the temp directory used for import.
remove_dir($tmpdir);
return $status;
}
/**
@ -523,7 +599,9 @@ function profiling_export_generate(array $runids, $tmpdir) {
$mainxw->full_tag('release', $release);
$mainxw->full_tag('version', $version);
$mainxw->full_tag('dbtype', $dbtype);
$mainxw->full_tag('githash', $githash);
if ($githash) {
$mainxw->full_tag('githash', $githash);
}
$mainxw->full_tag('date', $date);
$mainxw->end_tag('info');
@ -588,6 +666,83 @@ function profiling_export_package($file, $tmpdir) {
return true;
}
/**
* Return the xml schema for the main import file.
*
* @return string
*
*/
function profiling_get_import_main_schema() {
$schema = <<<EOS
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="moodle_profiling_runs">
<xs:complexType>
<xs:sequence>
<xs:element ref="info"/>
<xs:element ref="runs"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="info">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:string" name="release"/>
<xs:element type="xs:decimal" name="version"/>
<xs:element type="xs:string" name="dbtype"/>
<xs:element type="xs:string" minOccurs="0" name="githash"/>
<xs:element type="xs:int" name="date"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="runs">
<xs:complexType>
<xs:sequence>
<xs:element maxOccurs="unbounded" ref="run"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:element name="run">
<xs:complexType>
<xs:attribute type="xs:int" name="id"/>
<xs:attribute type="xs:string" name="ref"/>
</xs:complexType>
</xs:element>
</xs:schema>
EOS;
return $schema;
}
/**
* Return the xml schema for each individual run import file.
*
* @return string
*
*/
function profiling_get_import_run_schema() {
$schema = <<<EOS
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="moodle_profiling_run">
<xs:complexType>
<xs:sequence>
<xs:element type="xs:int" name="id"/>
<xs:element type="xs:string" name="runid"/>
<xs:element type="xs:string" name="url"/>
<xs:element type="xs:int" name="runreference"/>
<xs:element type="xs:string" name="runcomment"/>
<xs:element type="xs:int" name="timecreated"/>
<xs:element type="xs:int" name="totalexecutiontime"/>
<xs:element type="xs:int" name="totalcputime"/>
<xs:element type="xs:int" name="totalcalls"/>
<xs:element type="xs:int" name="totalmemory"/>
<xs:element type="xs:string" name="data"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
EOS;
return $schema;
}
/**
* Custom implementation of iXHProfRuns
*