Skip to content

Commit 838237a

Browse files
committed
module: print amount of load time of a cjs module
1 parent 1264414 commit 838237a

File tree

3 files changed

+70
-4
lines changed

3 files changed

+70
-4
lines changed

lib/internal/modules/cjs/loader.js

+41-4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ const {
6161
StringPrototypeSplit,
6262
StringPrototypeStartsWith,
6363
Symbol,
64+
Number,
6465
} = primordials;
6566

6667
// Map used to store CJS parsing data or for ESM loading.
@@ -359,10 +360,22 @@ function setModuleParent(value) {
359360
moduleParentCache.set(this, value);
360361
}
361362

362-
let debug = require('internal/util/debuglog').debuglog('module', (fn) => {
363+
const { debuglog, isDebugEnabled } = require('internal/util/debuglog');
364+
365+
let debug = debuglog('module', (fn) => {
363366
debug = fn;
364367
});
365368

369+
let hrtimeBigIntTimingFn = () => {
370+
hrtimeBigIntTimingFn = isDebugEnabled('timing_module_cjs') ? process.hrtime.bigint : () => 0;
371+
372+
return hrtimeBigIntTimingFn();
373+
};
374+
375+
let debugTiming = debuglog('timing_module_cjs', (fn) => {
376+
debugTiming = fn;
377+
});
378+
366379
ObjectDefineProperty(Module.prototype, 'parent', {
367380
__proto__: null,
368381
get: pendingDeprecate(
@@ -958,6 +971,10 @@ function getExportsForCircularRequire(module) {
958971
return module.exports;
959972
}
960973

974+
function logTiming(request, parent, start) {
975+
debugTiming('[%s] [%s]: %d ms', parent?.id || '', request, Number((hrtimeBigIntTimingFn() - start)) / 1e6);
976+
}
977+
961978
/**
962979
* Load a module from cache if it exists, otherwise create a new module instance.
963980
* 1. If a module already exists in the cache: return its exports object.
@@ -966,10 +983,12 @@ function getExportsForCircularRequire(module) {
966983
* 3. Otherwise, create a new module for the file and save it to the cache.
967984
* Then have it load the file contents before returning its exports object.
968985
* @param {string} request Specifier of module to load via `require`
969-
* @param {string} parent Absolute path of the module importing the child
986+
* @param {Module} parent Absolute path of the module importing the child
970987
* @param {boolean} isMain Whether the module is the main entry point
971988
*/
972989
Module._load = function(request, parent, isMain) {
990+
const start = hrtimeBigIntTimingFn();
991+
973992
let relResolveCacheIdentifier;
974993
if (parent) {
975994
debug('Module._load REQUEST %s parent: %s', request, parent.id);
@@ -984,8 +1003,14 @@ Module._load = function(request, parent, isMain) {
9841003
if (cachedModule !== undefined) {
9851004
updateChildren(parent, cachedModule, true);
9861005
if (!cachedModule.loaded) {
987-
return getExportsForCircularRequire(cachedModule);
1006+
const result = getExportsForCircularRequire(cachedModule);
1007+
1008+
logTiming(request, parent, start);
1009+
1010+
return result;
9881011
}
1012+
1013+
logTiming(request, parent, start);
9891014
return cachedModule.exports;
9901015
}
9911016
delete relativeResolveCache[relResolveCacheIdentifier];
@@ -1001,6 +1026,8 @@ Module._load = function(request, parent, isMain) {
10011026
}
10021027

10031028
const module = loadBuiltinModule(id, request);
1029+
1030+
logTiming(request, parent, start);
10041031
return module.exports;
10051032
}
10061033

@@ -1011,16 +1038,24 @@ Module._load = function(request, parent, isMain) {
10111038
if (!cachedModule.loaded) {
10121039
const parseCachedModule = cjsSourceCache.get(cachedModule);
10131040
if (!parseCachedModule || parseCachedModule.loaded) {
1014-
return getExportsForCircularRequire(cachedModule);
1041+
const result = getExportsForCircularRequire(cachedModule);
1042+
1043+
logTiming(request, parent, start);
1044+
1045+
return result;
10151046
}
10161047
parseCachedModule.loaded = true;
10171048
} else {
1049+
logTiming(request, parent, start);
10181050
return cachedModule.exports;
10191051
}
10201052
}
10211053

10221054
if (BuiltinModule.canBeRequiredWithoutScheme(filename)) {
10231055
const mod = loadBuiltinModule(filename, request);
1056+
1057+
logTiming(request, parent, start);
1058+
10241059
return mod.exports;
10251060
}
10261061

@@ -1068,6 +1103,8 @@ Module._load = function(request, parent, isMain) {
10681103
}
10691104
}
10701105

1106+
logTiming(request, parent, start);
1107+
10711108
return module.exports;
10721109
};
10731110

lib/internal/util/debuglog.js

+5
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,12 @@ function debuglog(set, cb) {
115115
return logger;
116116
}
117117

118+
function isDebugEnabled(set) {
119+
return testEnabled(set);
120+
}
121+
118122
module.exports = {
119123
debuglog,
124+
isDebugEnabled,
120125
initializeDebugEnv,
121126
};
+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import { spawnPromisified } from '../common/index.mjs';
2+
import assert from 'node:assert';
3+
import { execPath } from 'node:process';
4+
import { it } from 'node:test';
5+
6+
it('should print the timing information for cjs', async () => {
7+
process.env.NODE_DEBUG = 'timing_module_cjs';
8+
const result = await spawnPromisified(execPath, ['--eval', 'require("url");'], {
9+
env: {
10+
NODE_DEBUG: 'timing_module_cjs',
11+
},
12+
});
13+
14+
assert.strictEqual(result.code, 0);
15+
assert.strictEqual(result.signal, null);
16+
assert.strictEqual(result.stdout, '');
17+
18+
const firstLine = result.stderr.split('\n').find((line) => line.includes('[url]'));
19+
20+
assert.notStrictEqual(firstLine, undefined);
21+
assert.ok(firstLine.includes('TIMING_MODULE_CJS'), `Not found TIMING_MODULE_CJS on ${firstLine}`);
22+
assert.ok(firstLine.includes('[url]:'), `Not found [url]: on ${firstLine}`);
23+
assert.ok(firstLine.endsWith('ms'), `Not found ms on ${firstLine}`);
24+
});

0 commit comments

Comments
 (0)