Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

module: print amount of load time of a module #52213

Merged
merged 29 commits into from
May 30, 2024
Merged
Show file tree
Hide file tree
Changes from 24 commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
79f1583
module: print amount of load time of a cjs module
H4ad Apr 10, 2024
11ea88a
try support both node_debug and trace by introducing a new module
H4ad May 23, 2024
facfd58
add trace label to better visualization
H4ad Mar 30, 2024
db60283
fix lint issue with max line
H4ad Mar 30, 2024
fc16e3d
lazy load trace_timer
H4ad Mar 30, 2024
6cfb608
fix lint issues introduce when lazy load
H4ad Mar 30, 2024
966b7b9
cleanup and added more tests
H4ad Apr 10, 2024
956b75a
remove unecessary changes
H4ad Apr 10, 2024
cdc1629
remove unecessary changes
H4ad Apr 10, 2024
cd4fb61
resolve rebase conflicts
H4ad Apr 10, 2024
108be09
fixing nits
H4ad Apr 12, 2024
ba734f0
resolve conflicts after rebase
H4ad Apr 12, 2024
b04cfc5
fix lint issues
H4ad Apr 12, 2024
b426ede
handle unexpected errors during _load
H4ad Apr 13, 2024
2c2a6ef
add wrap module load function
H4ad May 23, 2024
61a94af
removed unused spaces
H4ad Apr 13, 2024
9f46a21
fixing tests on last modification
H4ad May 23, 2024
b607a1d
escape backslash when is label
H4ad May 22, 2024
ad790be
fix references for _load
H4ad May 23, 2024
1c727c0
add test to check against un-escaped backslash
H4ad May 23, 2024
fffaaae
fix issues with test & missing fn
H4ad May 23, 2024
0ad8a70
making eslint happy with trailing space
H4ad May 23, 2024
d7ecab3
minor changes
H4ad May 24, 2024
02b11b8
fix missing changing the name of the module
H4ad May 25, 2024
3d23033
try get more info from ci
H4ad May 29, 2024
455d408
try get more info from ci & make lint happy
H4ad May 29, 2024
2f3a102
fix import of common and spawnSync
H4ad May 29, 2024
51d1a39
do not cache process.execPath on import
H4ad May 29, 2024
5adcb8a
thanks richard, you are amazing
H4ad May 29, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
107 changes: 19 additions & 88 deletions lib/internal/console/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,6 @@ const {
Boolean,
ErrorCaptureStackTrace,
FunctionPrototypeBind,
MathFloor,
Number,
NumberPrototypeToFixed,
ObjectDefineProperties,
ObjectDefineProperty,
ObjectKeys,
Expand All @@ -30,10 +27,8 @@ const {
SafeSet,
SafeWeakMap,
StringPrototypeIncludes,
StringPrototypePadStart,
StringPrototypeRepeat,
StringPrototypeSlice,
StringPrototypeSplit,
Symbol,
SymbolHasInstance,
SymbolToStringTag,
Expand Down Expand Up @@ -63,19 +58,14 @@ const {
isTypedArray, isSet, isMap, isSetIterator, isMapIterator,
} = require('internal/util/types');
const {
CHAR_LOWERCASE_B: kTraceBegin,
CHAR_LOWERCASE_E: kTraceEnd,
CHAR_LOWERCASE_N: kTraceInstant,
CHAR_UPPERCASE_C: kTraceCount,
} = require('internal/constants');
const { styleText } = require('util');
const kCounts = Symbol('counts');
const { time, timeLog, timeEnd, kNone } = require('internal/util/debuglog');

const kTraceConsoleCategory = 'node,node.console';

const kSecond = 1000;
const kMinute = 60 * kSecond;
const kHour = 60 * kMinute;
const kMaxGroupIndentation = 1000;

// Lazy loaded for startup performance.
Expand All @@ -101,6 +91,7 @@ const kBindStreamsEager = Symbol('kBindStreamsEager');
const kBindStreamsLazy = Symbol('kBindStreamsLazy');
const kUseStdout = Symbol('kUseStdout');
const kUseStderr = Symbol('kUseStderr');
const kInternalTimeLogImpl = Symbol('kInternalTimeLogImpl');

const optionsMap = new SafeWeakMap();
function Console(options /* or: stdout, stderr, ignoreErrors = true */) {
Expand Down Expand Up @@ -381,6 +372,14 @@ function createWriteErrorHandler(instance, streamSymbol) {
};
}

function timeLogImpl(label, formatted, args) {
if (args === undefined) {
this.log('%s: %s', label, formatted);
} else {
this.log('%s: %s', label, formatted, ...new SafeArrayIterator(args));
}
}

const consoleMethods = {
log(...args) {
this[kWriteToConsole](kUseStdout, this[kFormatForStdout](args));
Expand All @@ -404,31 +403,21 @@ const consoleMethods = {
},

time(label = 'default') {
// Coerces everything other than Symbol to a string
label = `${label}`;
if (this._times.has(label)) {
process.emitWarning(`Label '${label}' already exists for console.time()`);
return;
}
trace(kTraceBegin, kTraceConsoleCategory, `time::${label}`, 0);
this._times.set(label, process.hrtime());
time(this._times, kTraceConsoleCategory, 'console.time()', kNone, label, `time::${label}`);
},

timeEnd(label = 'default') {
// Coerces everything other than Symbol to a string
label = `${label}`;
const found = timeLogImpl(this, 'timeEnd', label);
trace(kTraceEnd, kTraceConsoleCategory, `time::${label}`, 0);
if (found) {
this._times.delete(label);
}
if (this[kInternalTimeLogImpl] === undefined)
this[kInternalTimeLogImpl] = FunctionPrototypeBind(timeLogImpl, this);

timeEnd(this._times, kTraceConsoleCategory, 'console.timeEnd()', kNone, this[kInternalTimeLogImpl], label, `time::${label}`);
},

timeLog(label = 'default', ...data) {
// Coerces everything other than Symbol to a string
label = `${label}`;
timeLogImpl(this, 'timeLog', label, data);
trace(kTraceInstant, kTraceConsoleCategory, `time::${label}`, 0);
if (this[kInternalTimeLogImpl] === undefined)
this[kInternalTimeLogImpl] = FunctionPrototypeBind(timeLogImpl, this);

timeLog(this._times, kTraceConsoleCategory, 'console.timeLog()', kNone, this[kInternalTimeLogImpl], label, `time::${label}`, data);
},

trace: function trace(...args) {
Expand Down Expand Up @@ -627,63 +616,6 @@ const consoleMethods = {
},
};

// Returns true if label was found
function timeLogImpl(self, name, label, data) {
const time = self._times.get(label);
if (time === undefined) {
process.emitWarning(`No such label '${label}' for console.${name}()`);
return false;
}
const duration = process.hrtime(time);
const ms = duration[0] * 1000 + duration[1] / 1e6;

const formatted = formatTime(ms);

if (data === undefined) {
self.log('%s: %s', label, formatted);
} else {
self.log('%s: %s', label, formatted, ...new SafeArrayIterator(data));
}
return true;
}

function pad(value) {
return StringPrototypePadStart(`${value}`, 2, '0');
}

function formatTime(ms) {
let hours = 0;
let minutes = 0;
let seconds = 0;

if (ms >= kSecond) {
if (ms >= kMinute) {
if (ms >= kHour) {
hours = MathFloor(ms / kHour);
ms = ms % kHour;
}
minutes = MathFloor(ms / kMinute);
ms = ms % kMinute;
}
seconds = ms / kSecond;
}

if (hours !== 0 || minutes !== 0) {
({ 0: seconds, 1: ms } = StringPrototypeSplit(
NumberPrototypeToFixed(seconds, 3),
'.',
));
const res = hours !== 0 ? `${hours}:${pad(minutes)}` : minutes;
return `${res}:${pad(seconds)}.${ms} (${hours !== 0 ? 'h:m' : ''}m:ss.mmm)`;
}

if (seconds !== 0) {
return `${NumberPrototypeToFixed(seconds, 3)}s`;
}

return `${Number(NumberPrototypeToFixed(ms, 3))}ms`;
}

const keyKey = 'Key';
const valuesKey = 'Values';
const indexKey = '(index)';
Expand Down Expand Up @@ -743,5 +675,4 @@ module.exports = {
kBindStreamsLazy,
kBindProperties,
initializeGlobalConsole,
formatTime, // exported for tests
};
3 changes: 1 addition & 2 deletions lib/internal/main/repl.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,7 @@ markBootstrapComplete();

if (process.env.NODE_REPL_EXTERNAL_MODULE) {
require('internal/modules/cjs/loader')
.Module
._load(process.env.NODE_REPL_EXTERNAL_MODULE, undefined, true);
.wrapModuleLoad(process.env.NODE_REPL_EXTERNAL_MODULE, undefined, true);
} else {
// --input-type flag not supported in REPL
if (getOptionValue('--input-type')) {
Expand Down
32 changes: 29 additions & 3 deletions lib/internal/modules/cjs/loader.js
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,7 @@ module.exports = {
initializeCJS,
Module,
wrapSafe,
wrapModuleLoad,
kIsMainSymbol,
kIsCachedByESMLoader,
kRequiredModuleSymbol,
Expand Down Expand Up @@ -181,6 +182,13 @@ const {
isProxy,
} = require('internal/util/types');

const { debuglog, debugWithTimer } = require('internal/util/debuglog');

let { startTimer, endTimer } = debugWithTimer('module_timer', (start, end) => {
startTimer = start;
endTimer = end;
});

const isWindows = process.platform === 'win32';

const relativeResolveCache = { __proto__: null };
Expand All @@ -189,6 +197,24 @@ let requireDepth = 0;
let isPreloading = false;
let statCache = null;

/**
* Internal method to add tracing capabilities for Module._load.
*
* See more {@link Module._load}
*/
function wrapModuleLoad(request, parent, isMain) {
const logLabel = `[${parent?.id || ''}] [${request}]`;
const traceLabel = `require('${request}')`;

startTimer(logLabel, traceLabel);

try {
return Module._load(request, parent, isMain);
} finally {
endTimer(logLabel, traceLabel);
}
}

/**
* Get a path's properties, using an in-memory cache to minimize lookups.
* @param {string} filename Absolute path to the file
Expand Down Expand Up @@ -354,7 +380,7 @@ function setModuleParent(value) {
this[kModuleParent] = value;
}

let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
let debug = debuglog('module', (fn) => {
debug = fn;
});

Expand Down Expand Up @@ -971,7 +997,7 @@ function getExportsForCircularRequire(module) {
* 3. Otherwise, create a new module for the file and save it to the cache.
* Then have it load the file contents before returning its exports object.
* @param {string} request Specifier of module to load via `require`
* @param {string} parent Absolute path of the module importing the child
* @param {Module} parent Absolute path of the module importing the child
* @param {boolean} isMain Whether the module is the main entry point
*/
Module._load = function(request, parent, isMain) {
Expand Down Expand Up @@ -1268,7 +1294,7 @@ Module.prototype.require = function(id) {
}
requireDepth++;
try {
return Module._load(id, this, /* isMain */ false);
return wrapModuleLoad(id, this, /* isMain */ false);
} finally {
requireDepth--;
}
Expand Down
7 changes: 4 additions & 3 deletions lib/internal/modules/esm/translators.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ const {
const {
kIsCachedByESMLoader,
Module: CJSModule,
wrapModuleLoad,
kModuleSource,
kModuleExport,
kModuleExportNames,
Expand Down Expand Up @@ -198,7 +199,7 @@ function loadCJSModule(module, source, url, filename, isMain) {
importAttributes = { __proto__: null, type: 'json' };
break;
case '.node':
return CJSModule._load(specifier, module);
return wrapModuleLoad(specifier, module);
default:
// fall through
}
Expand Down Expand Up @@ -290,7 +291,7 @@ translators.set('commonjs-sync', function requireCommonJS(url, source, isMain) {
return createCJSModuleWrap(url, source, isMain, (module, source, url, filename, isMain) => {
assert(module === CJSModule._cache[filename]);
assert(!isMain);
CJSModule._load(filename, null, isMain);
wrapModuleLoad(filename, null, isMain);
});
});

Expand All @@ -315,7 +316,7 @@ translators.set('commonjs', async function commonjsStrategy(url, source,
// obtained by calling the monkey-patchable CJS loader.
const cjsLoader = source == null ? (module, source, url, filename, isMain) => {
assert(module === CJSModule._cache[filename]);
CJSModule._load(filename, undefined, isMain);
wrapModuleLoad(filename, undefined, isMain);
} : loadCJSModule;

try {
Expand Down
4 changes: 2 additions & 2 deletions lib/internal/modules/run_main.js
Original file line number Diff line number Diff line change
Expand Up @@ -154,8 +154,8 @@ function executeUserEntryPoint(main = process.argv[1]) {
// try to run the entry point via the CommonJS loader; and if that fails under certain conditions, retry as ESM.
if (!useESMLoader) {
const cjsLoader = require('internal/modules/cjs/loader');
const { Module } = cjsLoader;
Module._load(main, null, true);
const { wrapModuleLoad } = cjsLoader;
wrapModuleLoad(main, null, true);
} else {
const mainPath = resolvedMain || main;
if (mainURL === undefined) {
Expand Down
Loading