remove --prof-modules-flag, adopt new loader, https://github.com/microsoft/vscode/issues/62643

This commit is contained in:
Johannes Rieken
2019-06-05 15:03:05 +02:00
parent 98c36e8516
commit ee070dc2db
7 changed files with 73 additions and 108 deletions
+6 -1
View File
@@ -17,7 +17,12 @@ declare const enum LoaderEventType {
NodeEndEvaluatingScript = 32,
NodeBeginNativeRequire = 33,
NodeEndNativeRequire = 34
NodeEndNativeRequire = 34,
CachedDataFound = 60,
CachedDataMissed = 61,
CachedDataRejected = 62,
CachedDataCreated = 63,
}
declare class LoaderEvent {
@@ -35,13 +35,7 @@ bootstrapWindow.load([
showPartsSplash(windowConfig);
},
beforeLoaderConfig: function (windowConfig, loaderConfig) {
loaderConfig.recordStats = !!windowConfig['prof-modules'];
if (loaderConfig.nodeCachedData) {
const onNodeCachedData = window['MonacoEnvironment'].onNodeCachedData = [];
loaderConfig.nodeCachedData.onData = function () {
onNodeCachedData.push(arguments);
};
}
loaderConfig.recordStats = true;
},
beforeRequire: function () {
perf.mark('willLoadWorkbenchMain');
+56 -85
View File
@@ -235,6 +235,7 @@ var AMDLoader;
*--------------------------------------------------------------------------------------------*/
var AMDLoader;
(function (AMDLoader) {
;
var ConfigurationOptionsUtil = (function () {
function ConfigurationOptionsUtil() {
}
@@ -305,22 +306,8 @@ var AMDLoader;
if (typeof options.nodeCachedData.writeDelay !== 'number' || options.nodeCachedData.writeDelay < 0) {
options.nodeCachedData.writeDelay = 1000 * 7;
}
if (typeof options.nodeCachedData.onData !== 'function') {
options.nodeCachedData.onData = function (err) {
if (err && err.errorCode === 'cachedDataRejected') {
console.warn('Rejected cached data from file: ' + err.path);
}
else if (err && err.errorCode) {
console.error('Problems handling cached data file: ' + err.path);
console.error(err.detail);
}
else if (err) {
console.error(err);
}
};
}
if (!options.nodeCachedData.path || typeof options.nodeCachedData.path !== 'string') {
options.nodeCachedData.onData('INVALID cached data configuration, \'path\' MUST be set');
options.onError('INVALID cached data configuration, \'path\' MUST be set');
options.nodeCachedData = undefined;
}
}
@@ -660,7 +647,6 @@ var AMDLoader;
this._env = env;
this._didInitialize = false;
this._didPatchNodeRequire = false;
this._hasCreateCachedData = false;
}
NodeScriptLoader.prototype._init = function (nodeRequire) {
if (this._didInitialize) {
@@ -672,14 +658,17 @@ var AMDLoader;
this._vm = nodeRequire('vm');
this._path = nodeRequire('path');
this._crypto = nodeRequire('crypto');
// check for `createCachedData`-api
this._hasCreateCachedData = typeof (new this._vm.Script('').createCachedData) === 'function';
};
// patch require-function of nodejs such that we can manually create a script
// from cached data. this is done by overriding the `Module._compile` function
NodeScriptLoader.prototype._initNodeRequire = function (nodeRequire, moduleManager) {
// It is important to check for `nodeCachedData` first and then set `_didPatchNodeRequire`.
// That's because `nodeCachedData` is set _after_ calling this for the first time...
var nodeCachedData = moduleManager.getConfig().getOptionsLiteral().nodeCachedData;
if (!nodeCachedData || this._didPatchNodeRequire) {
if (!nodeCachedData) {
return;
}
if (this._didPatchNodeRequire) {
return;
}
this._didPatchNodeRequire = true;
@@ -708,13 +697,13 @@ var AMDLoader;
content = content.replace(/^#!.*/, '');
// create wrapper function
var wrapper = Module.wrap(content);
var cachedDataPath = that._getCachedDataPath(nodeCachedData.seed, nodeCachedData.path, filename);
var cachedDataPath = that._getCachedDataPath(nodeCachedData, filename);
var options = { filename: filename };
try {
options.cachedData = that._fs.readFileSync(cachedDataPath);
}
catch (e) {
options.produceCachedData = !that._hasCreateCachedData;
// ignore
}
var script = new that._vm.Script(wrapper, options);
var compileWrapper = script.runInThisContext(options);
@@ -722,7 +711,7 @@ var AMDLoader;
var require = makeRequireFunction(this);
var args = [this.exports, require, this, filename, dirname, process, _commonjsGlobal, Buffer];
var result = compileWrapper.apply(this.exports, args);
that._processCachedData(moduleManager, script, wrapper, cachedDataPath, !options.cachedData);
that._processCachedData(script, cachedDataPath, Boolean(options.cachedData), moduleManager.getConfig(), moduleManager.getRecorder());
return result;
};
};
@@ -780,16 +769,16 @@ var AMDLoader;
_this._loadAndEvalScript(moduleManager, scriptSrc, vmScriptSrc, contents, { filename: vmScriptSrc }, recorder, callback, errorback);
}
else {
var cachedDataPath_1 = _this._getCachedDataPath(opts.nodeCachedData.seed, opts.nodeCachedData.path, scriptSrc);
var cachedDataPath_1 = _this._getCachedDataPath(opts.nodeCachedData, scriptSrc);
_this._fs.readFile(cachedDataPath_1, function (_err, cachedData) {
// create script options
var options = {
filename: vmScriptSrc,
produceCachedData: !_this._hasCreateCachedData && typeof cachedData === 'undefined',
cachedData: cachedData
};
recorder.record(cachedData ? 60 /* CachedDataFound */ : 61 /* CachedDataMissed */, scriptSrc);
var script = _this._loadAndEvalScript(moduleManager, scriptSrc, vmScriptSrc, contents, options, recorder, callback, errorback);
_this._processCachedData(moduleManager, script, contents, cachedDataPath_1, !options.cachedData);
_this._processCachedData(script, cachedDataPath_1, Boolean(cachedData), moduleManager.getConfig(), recorder);
});
}
});
@@ -818,74 +807,56 @@ var AMDLoader;
}
return script;
};
NodeScriptLoader.prototype._getCachedDataPath = function (seed, basedir, filename) {
var hash = this._crypto.createHash('md5').update(filename, 'utf8').update(seed, 'utf8').digest('hex');
NodeScriptLoader.prototype._getCachedDataPath = function (config, filename) {
var hash = this._crypto.createHash('md5').update(filename, 'utf8').update(config.seed, 'utf8').digest('hex');
var basename = this._path.basename(filename).replace(/\.js$/, '');
return this._path.join(basedir, basename + "-" + hash + ".code");
return this._path.join(config.path, basename + "-" + hash + ".code");
};
NodeScriptLoader.prototype._processCachedData = function (moduleManager, script, contents, cachedDataPath, createCachedData) {
NodeScriptLoader.prototype._processCachedData = function (script, cachedDataPath, hadCachedData, config, recorder) {
var _this = this;
if (script.cachedDataRejected) {
// data rejected => delete cache file
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({
errorCode: 'cachedDataRejected',
path: cachedDataPath
// rejected cached data
// (1) delete data
// (2) create new data
recorder.record(62 /* CachedDataRejected */, cachedDataPath);
this._fs.unlink(cachedDataPath, function (err) {
if (err) {
config.onError(err);
}
_this._createCachedData(script, cachedDataPath, config, recorder);
});
NodeScriptLoader._runSoon(function () {
return _this._fs.unlink(cachedDataPath, function (err) {
if (err) {
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({
errorCode: 'unlink',
path: cachedDataPath,
detail: err
});
}
});
}, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay / 2);
}
else if (script.cachedDataProduced) {
// data produced => tell outside world
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData(undefined, {
path: cachedDataPath
});
// data produced => write cache file
NodeScriptLoader._runSoon(function () {
return _this._fs.writeFile(cachedDataPath, script.cachedData, function (err) {
if (err) {
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({
errorCode: 'writeFile',
path: cachedDataPath,
detail: err
});
}
});
}, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay);
}
else if (this._hasCreateCachedData && createCachedData) {
// NEW world
// data produced => tell outside world
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData(undefined, {
path: cachedDataPath
});
// soon'ish create and save cached data
NodeScriptLoader._runSoon(function () {
var data = script.createCachedData(contents);
_this._fs.writeFile(cachedDataPath, data, function (err) {
if (!err) {
return;
}
moduleManager.getConfig().getOptionsLiteral().nodeCachedData.onData({
errorCode: 'writeFile',
path: cachedDataPath,
detail: err
});
});
}, moduleManager.getConfig().getOptionsLiteral().nodeCachedData.writeDelay);
else if (!hadCachedData) {
// create cached data unless we already had
// and accepted cached data
this._createCachedData(script, cachedDataPath, config, recorder);
}
};
NodeScriptLoader._runSoon = function (callback, minTimeout) {
var timeout = minTimeout + Math.ceil(Math.random() * minTimeout);
setTimeout(callback, timeout);
NodeScriptLoader.prototype._createCachedData = function (script, cachedDataPath, config, recorder) {
var _this = this;
var timeout = Math.ceil(config.getOptionsLiteral().nodeCachedData.writeDelay * (1 + Math.random()));
var lastSize = -1;
var iteration = 0;
var createLoop = function () {
setTimeout(function () {
var data = script.createCachedData();
if (data.length === lastSize) {
return;
}
lastSize = data.length;
_this._fs.writeFile(cachedDataPath, data, function (err) {
if (err) {
config.onError(err);
}
recorder.record(63 /* CachedDataCreated */, cachedDataPath);
createLoop();
});
}, timeout * (Math.pow(4, iteration++)));
};
// with some delay (`timeout`) create cached data
// and repeat that (with backoff delay) until the
// data seems to be not changing anymore
createLoop();
};
return NodeScriptLoader;
}());
@@ -27,7 +27,6 @@ export interface ParsedArgs {
'prof-startup'?: string;
'prof-startup-prefix'?: string;
'prof-append-timers'?: string;
'prof-modules'?: string;
verbose?: boolean;
trace?: boolean;
'trace-category-filter'?: string;
+1 -2
View File
@@ -54,7 +54,6 @@ export const options: Option[] = [
{ id: 'verbose', type: 'boolean', cat: 't', description: localize('verbose', "Print verbose output (implies --wait).") },
{ id: 'log', type: 'string', cat: 't', args: 'level', description: localize('log', "Log level to use. Default is 'info'. Allowed values are 'critical', 'error', 'warn', 'info', 'debug', 'trace', 'off'.") },
{ id: 'status', type: 'boolean', alias: 's', cat: 't', description: localize('status', "Print process usage and diagnostics information.") },
{ id: 'prof-modules', type: 'boolean', alias: 'p', cat: 't', description: localize('prof-modules', "Capture performance markers while loading JS modules and print them with 'F1 > Developer: Startup Performance") },
{ id: 'prof-startup', type: 'boolean', cat: 't', description: localize('prof-startup', "Run CPU profiler during startup") },
{ id: 'disable-extensions', type: 'boolean', deprecates: 'disableExtensions', cat: 't', description: localize('disableExtensions', "Disable all installed extensions.") },
{ id: 'disable-extension', type: 'string', cat: 't', args: 'extension-id', description: localize('disableExtension', "Disable an extension.") },
@@ -275,4 +274,4 @@ export function createWaitMarkerFile(verbose?: boolean): string | undefined {
}
return undefined;
}
}
}
@@ -20,7 +20,6 @@ import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ICodeEditorService } from 'vs/editor/browser/services/codeEditorService';
import { writeTransientState } from 'vs/workbench/contrib/codeEditor/browser/toggleWordWrap';
import { mergeSort } from 'vs/base/common/arrays';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import product from 'vs/platform/product/node/product';
import pkg from 'vs/platform/product/node/package';
@@ -73,7 +72,6 @@ class PerfModelContentProvider implements ITextModelContentProvider {
@ICodeEditorService private readonly _editorService: ICodeEditorService,
@ILifecycleService private readonly _lifecycleService: ILifecycleService,
@ITimerService private readonly _timerService: ITimerService,
@IEnvironmentService private readonly _envService: IEnvironmentService,
@IExtensionService private readonly _extensionService: IExtensionService,
) { }
@@ -107,7 +105,7 @@ class PerfModelContentProvider implements ITextModelContentProvider {
]).then(([metrics]) => {
if (this._model && !this._model.isDisposed()) {
let stats = this._envService.args['prof-modules'] ? LoaderStats.get() : undefined;
let stats = LoaderStats.get();
let md = new MarkdownBuilder();
this._addSummary(md, metrics);
md.blank();
@@ -12,7 +12,6 @@ import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/
import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/common/workspace';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { registerSingleton } from 'vs/platform/instantiation/common/extensions';
import { isNonEmptyArray } from 'vs/base/common/arrays';
import { IUpdateService } from 'vs/platform/update/common/update';
import { ILifecycleService } from 'vs/platform/lifecycle/common/lifecycle';
import { IViewletService } from 'vs/workbench/services/viewlet/browser/viewlet';
@@ -432,16 +431,16 @@ export function didUseCachedData(): boolean {
if (!Boolean((<any>global).require.getConfig().nodeCachedData)) {
return false;
}
// whenever cached data is produced or rejected a onNodeCachedData-callback is invoked. That callback
// stores data in the `MonacoEnvironment.onNodeCachedData` global. See:
// https://github.com/Microsoft/vscode/blob/efe424dfe76a492eab032343e2fa4cfe639939f0/src/vs/workbench/electron-browser/bootstrap/index.js#L299
if (isNonEmptyArray(MonacoEnvironment.onNodeCachedData)) {
return false;
// There are loader events that signal if cached data was missing, rejected,
// or used. The former two mean no cached data.
for (const event of require.getStats()) {
switch (event.type) {
case LoaderEventType.CachedDataRejected:
case LoaderEventType.CachedDataMissed:
return false;
}
}
return true;
}
declare type OnNodeCachedDataArgs = [{ errorCode: string, path: string, detail?: string }, { path: string, length: number }];
declare const MonacoEnvironment: { onNodeCachedData: OnNodeCachedDataArgs[] };
//#endregion