зеркало из https://github.com/mozilla/pjs.git
404 строки
14 KiB
JavaScript
404 строки
14 KiB
JavaScript
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
|
*
|
|
* ***** BEGIN LICENSE BLOCK *****
|
|
* Version: MPL 1.1/GPL 2.0/LGPL 2.1
|
|
*
|
|
* The contents of this file are subject to the Mozilla Public License Version
|
|
* 1.1 (the "License"); you may not use this file except in compliance with
|
|
* the License. You may obtain a copy of the License at
|
|
* http://www.mozilla.org/MPL/
|
|
*
|
|
* Software distributed under the License is distributed on an "AS IS" basis,
|
|
* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
|
|
* for the specific language governing rights and limitations under the
|
|
* License.
|
|
*
|
|
* The Original Code is The JavaScript Debugger.
|
|
*
|
|
* The Initial Developer of the Original Code is
|
|
* Netscape Communications Corporation.
|
|
* Portions created by the Initial Developer are Copyright (C) 1998
|
|
* the Initial Developer. All Rights Reserved.
|
|
*
|
|
* Contributor(s):
|
|
* Robert Ginda, <rginda@netscape.com>, original author
|
|
*
|
|
* Alternatively, the contents of this file may be used under the terms of
|
|
* either the GNU General Public License Version 2 or later (the "GPL"), or
|
|
* the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
|
|
* in which case the provisions of the GPL or the LGPL are applicable instead
|
|
* of those above. If you wish to allow use of your version of this file only
|
|
* under the terms of either the GPL or the LGPL, and not to allow others to
|
|
* use your version of this file under the terms of the MPL, indicate your
|
|
* decision by deleting the provisions above and replace them with the notice
|
|
* and other provisions required by the GPL or the LGPL. If you do not delete
|
|
* the provisions above, a recipient may use your version of this file under
|
|
* the terms of any one of the MPL, the GPL or the LGPL.
|
|
*
|
|
* ***** END LICENSE BLOCK ***** */
|
|
|
|
function initProfiler ()
|
|
{
|
|
var prefs =
|
|
[
|
|
["profile.template.xml", "chrome://venkman/locale/profile.xml.tpl"],
|
|
["profile.template.html", "chrome://venkman/locale/profile.html.tpl"],
|
|
["profile.template.csv", "chrome://venkman/locale/profile.csv.tpl"],
|
|
["profile.template.txt", "chrome://venkman/locale/profile.txt.tpl"],
|
|
["profile.ranges.default", "1000000, 5000, 2500, 1000, 750, 500, " +
|
|
"250, 100, 75, 50, 25, 10, 7.5, 5, 2.5, 1, 0.75, 0.5, 0.25"]
|
|
];
|
|
|
|
console.prefManager.addPrefs(prefs);
|
|
}
|
|
|
|
function ProfileReport (reportTemplate, file, rangeList, scriptInstanceList)
|
|
{
|
|
this.reportTemplate = reportTemplate;
|
|
this.file = file;
|
|
this.rangeList = rangeList;
|
|
this.scriptInstanceList = scriptInstanceList;
|
|
this.key = "total";
|
|
}
|
|
|
|
console.profiler = new Object();
|
|
|
|
console.profiler.__defineSetter__ ("enabled", pro_setenable);
|
|
function pro_setenable(state)
|
|
{
|
|
if (state)
|
|
console.jsds.flags |= COLLECT_PROFILE_DATA;
|
|
else
|
|
console.jsds.flags &= ~COLLECT_PROFILE_DATA;
|
|
}
|
|
|
|
console.profiler.__defineGetter__ ("enabled", pro_getenable);
|
|
function pro_getenable(state)
|
|
{
|
|
return Boolean(console.jsds.flags & COLLECT_PROFILE_DATA);
|
|
}
|
|
|
|
console.profiler.summarizeScriptWrapper =
|
|
function pro_sumscript (scriptWrapper, key)
|
|
{
|
|
var ex;
|
|
|
|
try
|
|
{
|
|
var jsdScript = scriptWrapper.jsdScript;
|
|
if (!jsdScript.isValid)
|
|
return null;
|
|
|
|
var ccount = jsdScript.callCount;
|
|
if (!ccount)
|
|
return null;
|
|
|
|
var tot_ms = roundTo(jsdScript.totalExecutionTime, 2);
|
|
var min_ms = roundTo(jsdScript.minExecutionTime, 2);
|
|
var max_ms = roundTo(jsdScript.maxExecutionTime, 2);
|
|
var avg_ms = roundTo(jsdScript.totalExecutionTime / ccount, 2);
|
|
var own_tot_ms = roundTo(jsdScript.totalOwnExecutionTime, 2);
|
|
var own_min_ms = roundTo(jsdScript.minOwnExecutionTime, 2);
|
|
var own_max_ms = roundTo(jsdScript.maxOwnExecutionTime, 2);
|
|
var own_avg_ms = roundTo(jsdScript.totalOwnExecutionTime / ccount, 2);
|
|
var recurse = jsdScript.maxRecurseDepth;
|
|
|
|
var summary = new Object();
|
|
summary.total = tot_ms;
|
|
summary.ccount = ccount;
|
|
summary.avg = avg_ms;
|
|
summary.min = min_ms;
|
|
summary.max = max_ms;
|
|
summary.own_avg = own_avg_ms;
|
|
summary.own_min = own_min_ms;
|
|
summary.own_max = own_max_ms;
|
|
summary.own_total = own_tot_ms;
|
|
summary.recurse = recurse;
|
|
summary.url = jsdScript.fileName;
|
|
summary.file = getFileFromPath(summary.url);
|
|
summary.base = jsdScript.baseLineNumber;
|
|
summary.end = summary.base + jsdScript.lineExtent;
|
|
summary.fun = scriptWrapper.functionName;
|
|
var own_str = getMsg(MSN_FMT_PROFILE_STR2, [own_tot_ms, own_min_ms,
|
|
own_max_ms, own_avg_ms]);
|
|
summary.str = getMsg(MSN_FMT_PROFILE_STR,
|
|
[summary.fun, summary.base, summary.end, ccount,
|
|
(summary.recurse ?
|
|
getMsg(MSN_FMT_PROFILE_RECURSE, recurse) : ""),
|
|
tot_ms, min_ms, max_ms, avg_ms, own_str]);
|
|
summary.key = summary[key];
|
|
return summary;
|
|
}
|
|
catch (ex)
|
|
{
|
|
/* This function is called under duress, and the script representd
|
|
* by |s| may get collected at any point. When that happens,
|
|
* attempting to access to the profile data will throw this
|
|
* exception.
|
|
*/
|
|
if ("result" in ex &&
|
|
ex.result == Components.results.NS_ERROR_NOT_AVAILABLE)
|
|
{
|
|
display (getMsg(MSN_PROFILE_LOST, formatScript(jsdScript)), MT_WARN);
|
|
}
|
|
else
|
|
{
|
|
dd ("rethrow");
|
|
dd (dumpObjectTree(ex));
|
|
throw ex;
|
|
}
|
|
}
|
|
|
|
return null;
|
|
}
|
|
|
|
console.profiler.summarizeScriptInstance =
|
|
function pro_suminst (scriptInstance, key)
|
|
{
|
|
var summaryList = new Array();
|
|
var summary;
|
|
|
|
if (scriptInstance.topLevel)
|
|
summary = this.summarizeScriptWrapper (scriptInstance.topLevel, key);
|
|
if (summary)
|
|
summaryList.push (summary);
|
|
|
|
for (var f in scriptInstance.functions)
|
|
{
|
|
summary = this.summarizeScriptWrapper(scriptInstance.functions[f], key);
|
|
if (summary)
|
|
summaryList.push(summary);
|
|
}
|
|
|
|
return summaryList;
|
|
}
|
|
|
|
console.profiler.generateReportSection =
|
|
function pro_rptinst (profileReport, scriptInstance, sectionData)
|
|
{
|
|
function keyCompare (a, b)
|
|
{
|
|
if (a.key < b.key)
|
|
return 1;
|
|
if (a.key > b.key)
|
|
return -1;
|
|
return 0;
|
|
};
|
|
|
|
function scale(K, x) { return roundTo(K * x, 2); };
|
|
|
|
const MAX_WIDTH = 90;
|
|
|
|
var summaryList = this.summarizeScriptInstance (scriptInstance,
|
|
profileReport.key);
|
|
if (!summaryList.length)
|
|
return false;
|
|
|
|
summaryList = summaryList.sort(keyCompare);
|
|
|
|
var file = profileReport.file;
|
|
var reportTemplate = profileReport.reportTemplate;
|
|
var rangeList = profileReport.rangeList ? profileReport.rangeList : [1, 0];
|
|
var finalRangeIndex = rangeList.length - 1;
|
|
var previousRangeIndex;
|
|
var rangeIter = 0;
|
|
var rangeIndex = 0;
|
|
var K = 1;
|
|
var i;
|
|
|
|
if (typeof summaryList[0].key == "number")
|
|
{
|
|
for (i = 0; i < rangeList.length; ++i)
|
|
rangeList[i] = Number(rangeList[i]);
|
|
}
|
|
|
|
if ("sectionHeader" in reportTemplate)
|
|
{
|
|
file.write(replaceStrings(reportTemplate.sectionHeader,
|
|
sectionData));
|
|
}
|
|
|
|
for (i = 0; i < summaryList.length; ++i)
|
|
{
|
|
var summary = summaryList[i];
|
|
var rangeData;
|
|
|
|
while (summary.key &&
|
|
rangeIndex < finalRangeIndex &&
|
|
summary.key < rangeList[rangeIndex])
|
|
{
|
|
++rangeIndex;
|
|
}
|
|
|
|
if (previousRangeIndex != rangeIndex)
|
|
{
|
|
if (rangeIter > 0 && ("rangeFooter" in reportTemplate))
|
|
{
|
|
file.write(replaceStrings(reportTemplate.rangeFooter,
|
|
rangeData));
|
|
}
|
|
|
|
var maxRange = (rangeIndex > 0 ?
|
|
rangeList[rangeIndex - 1] : summary.key);
|
|
var minRange = (rangeIndex < finalRangeIndex ?
|
|
rangeList[rangeIndex + 1] : summary.key);
|
|
K = MAX_WIDTH / maxRange;
|
|
|
|
rangeData = {
|
|
"\\$range-min" : minRange,
|
|
"\\$range-max" : maxRange,
|
|
"\\$range-number-prev": rangeIter > 0 ? rangeIter - 1 : 0,
|
|
"\\$range-number-next": rangeIter + 1,
|
|
"\\$range-number" : rangeIter,
|
|
"__proto__" : sectionData
|
|
};
|
|
|
|
if ("rangeHeader" in reportTemplate)
|
|
{
|
|
file.write(replaceStrings(reportTemplate.rangeHeader,
|
|
rangeData));
|
|
}
|
|
|
|
previousRangeIndex = rangeIndex;
|
|
++rangeIter;
|
|
}
|
|
|
|
var summaryData = {
|
|
"\\$item-number-next": i + 1,
|
|
"\\$item-number-prev": i - 1,
|
|
"\\$item-number" : i,
|
|
"\\$item-name" : summary.url,
|
|
"\\$item-summary" : fromUnicode(summary.str, MSG_REPORT_CHARSET),
|
|
"\\$item-min-pct" : scale(K, summary.min),
|
|
"\\$item-below-pct" : scale(K, summary.avg - summary.min),
|
|
"\\$item-above-pct" : scale(K, summary.max - summary.avg),
|
|
"\\$max-time" : summary.max,
|
|
"\\$min-time" : summary.min,
|
|
"\\$avg-time" : summary.avg,
|
|
"\\$total-time" : summary.total,
|
|
"\\$own-max-time" : summary.own_max,
|
|
"\\$own-min-time" : summary.own_min,
|
|
"\\$own-avg-time" : summary.own_avg,
|
|
"\\$own-total-time" : summary.own_total,
|
|
"\\$call-count" : summary.ccount,
|
|
"\\$recurse-depth" : summary.recurse,
|
|
"\\$function-name" : fromUnicode(summary.fun, MSG_REPORT_CHARSET),
|
|
"\\$start-line" : summary.base,
|
|
"\\$end-line" : summary.end,
|
|
"__proto__" : rangeData
|
|
};
|
|
|
|
if ("itemBody" in reportTemplate)
|
|
file.write(replaceStrings(reportTemplate.itemBody, summaryData));
|
|
}
|
|
|
|
if ("rangeFooter" in reportTemplate)
|
|
{
|
|
/* close the final range */
|
|
file.write(replaceStrings(reportTemplate.rangeFooter,
|
|
rangeData));
|
|
}
|
|
|
|
if ("sectionFooter" in reportTemplate)
|
|
{
|
|
file.write(replaceStrings(reportTemplate.sectionFooter,
|
|
sectionData));
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
console.profiler.generateReport =
|
|
function pro_rptall (profileReport)
|
|
{
|
|
var profiler = this;
|
|
var sectionCount = 0;
|
|
|
|
function generateReportChunk (i)
|
|
{
|
|
/* we build the report in chunks, with setTimeouts in between,
|
|
* so the UI can come up for air. */
|
|
var scriptInstance = profileReport.scriptInstanceList[i];
|
|
var url = scriptInstance.url;
|
|
|
|
var sectionData = {
|
|
"\\$section-number-prev": (sectionCount > 0) ? sectionCount - 1 : 0,
|
|
"\\$section-number-next": sectionCount + 1,
|
|
"\\$section-number" : sectionCount,
|
|
"\\$section-link" : (url ? "<a class='section-link' href='" +
|
|
url + "'>" + url + "</a>" : MSG_VAL_NA),
|
|
"\\$full-url" : url,
|
|
"\\$file-name" : getFileFromPath(url),
|
|
"__proto__" : reportData
|
|
};
|
|
|
|
var hadData = profiler.generateReportSection (profileReport,
|
|
scriptInstance,
|
|
sectionData);
|
|
if (++i == profileReport.scriptInstanceList.length)
|
|
{
|
|
if ("reportFooter" in reportTemplate)
|
|
file.write(replaceStrings(reportTemplate.reportFooter,
|
|
reportData));
|
|
if ("onComplete" in profileReport)
|
|
profileReport.onComplete(i);
|
|
}
|
|
else
|
|
{
|
|
if (hadData)
|
|
{
|
|
++sectionCount;
|
|
console.status = getMsg(MSN_PROFILE_SAVING, [i, last]);
|
|
setTimeout (generateReportChunk, 10, i);
|
|
}
|
|
else
|
|
{
|
|
generateReportChunk (i);
|
|
}
|
|
}
|
|
};
|
|
|
|
var reportData = {
|
|
"\\$report-charset": MSG_REPORT_CHARSET,
|
|
"\\$full-date" : String(Date()),
|
|
"\\$user-agent" : navigator.userAgent,
|
|
"\\$venkman-agent" : console.userAgent,
|
|
"\\$sort-key" : profileReport.key
|
|
};
|
|
|
|
var reportTemplate = profileReport.reportTemplate;
|
|
var file = profileReport.file;
|
|
|
|
if ("reportHeader" in reportTemplate)
|
|
file.write(replaceStrings(reportTemplate.reportHeader, reportData));
|
|
|
|
var length = profileReport.scriptInstanceList.length;
|
|
var last = length - 1;
|
|
|
|
generateReportChunk (0);
|
|
}
|
|
|
|
console.profiler.loadTemplate =
|
|
function pro_load (url)
|
|
{
|
|
var lines = loadURLNow(url);
|
|
if (!lines)
|
|
return null;
|
|
|
|
var sections = {
|
|
"reportHeader" : /@-section-start/mi,
|
|
"sectionHeader" : /@-range-start/mi,
|
|
"rangeHeader" : /@-item-start/mi,
|
|
"itemBody" : /@-item-end/mi,
|
|
"rangeFooter" : /@-range-end/mi,
|
|
"sectionFooter" : /@-section-end/mi,
|
|
"reportFooter" : 0
|
|
};
|
|
|
|
var reportTemplate = parseSections (lines, sections);
|
|
|
|
//dd(dumpObjectTree (reportTemplate));
|
|
return reportTemplate;
|
|
}
|
|
|