mirror of
https://github.com/nodejs/node.git
synced 2025-12-28 07:50:41 +00:00
console: optimize single-string logging
PR-URL: https://github.com/nodejs/node/pull/60422 Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rafael Gonzaga <rafael.nunu@hotmail.com> Reviewed-By: Benjamin Gruenbaum <benjamingr@gmail.com> Reviewed-By: Matteo Collina <matteo.collina@gmail.com>
This commit is contained in:
parent
601208b671
commit
c2a4acb100
78
benchmark/console/log.js
Normal file
78
benchmark/console/log.js
Normal file
@ -0,0 +1,78 @@
|
||||
'use strict';
|
||||
|
||||
// A console throughput benchmark.
|
||||
// Uses a custom Console with null Writable streams to avoid I/O latency.
|
||||
|
||||
const common = require('../common.js');
|
||||
const { Writable } = require('stream');
|
||||
const { Console } = require('console');
|
||||
|
||||
const bench = common.createBenchmark(main, {
|
||||
n: [2e6],
|
||||
variant: ['plain', 'format', 'object', 'group', 'info', 'warn', 'error'],
|
||||
});
|
||||
|
||||
class Null extends Writable {
|
||||
_write(chunk, enc, cb) { cb(); }
|
||||
}
|
||||
|
||||
function makeConsole() {
|
||||
const dn = new Null();
|
||||
return new Console({ stdout: dn, stderr: dn, ignoreErrors: true, colorMode: false });
|
||||
}
|
||||
|
||||
function main({ n, variant }) {
|
||||
const c = makeConsole();
|
||||
|
||||
switch (variant) {
|
||||
case 'plain': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.log('hello world');
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'format': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.log('%s %d %j', 'a', 42, { x: 1 });
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'object': {
|
||||
const obj = { a: 1, b: 2, c: 3 };
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.log(obj);
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'group': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) {
|
||||
c.group('g');
|
||||
c.log('x');
|
||||
c.groupEnd();
|
||||
}
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'info': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.info('hello world');
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'warn': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.warn('hello world');
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
case 'error': {
|
||||
bench.start();
|
||||
for (let i = 0; i < n; i++) c.error('hello world');
|
||||
bench.end(n);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw new Error('unknown variant');
|
||||
}
|
||||
}
|
||||
@ -190,7 +190,7 @@ ObjectDefineProperty(Console, SymbolHasInstance, {
|
||||
const kColorInspectOptions = { colors: true };
|
||||
const kNoColorInspectOptions = {};
|
||||
|
||||
const internalIndentationMap = new SafeWeakMap();
|
||||
const kGroupIndentationString = Symbol('kGroupIndentationString');
|
||||
|
||||
ObjectDefineProperties(Console.prototype, {
|
||||
[kBindStreamsEager]: {
|
||||
@ -264,6 +264,11 @@ ObjectDefineProperties(Console.prototype, {
|
||||
...consolePropAttributes,
|
||||
value: groupIndentation,
|
||||
},
|
||||
[kGroupIndentationString]: {
|
||||
__proto__: null,
|
||||
...consolePropAttributes,
|
||||
value: '',
|
||||
},
|
||||
[SymbolToStringTag]: {
|
||||
__proto__: null,
|
||||
writable: false,
|
||||
@ -279,7 +284,7 @@ ObjectDefineProperties(Console.prototype, {
|
||||
...consolePropAttributes,
|
||||
value: function(streamSymbol, string) {
|
||||
const ignoreErrors = this._ignoreErrors;
|
||||
const groupIndent = internalIndentationMap.get(this) || '';
|
||||
const groupIndent = this[kGroupIndentationString];
|
||||
|
||||
const useStdout = streamSymbol === kUseStdout;
|
||||
const stream = useStdout ? this._stdout : this._stderr;
|
||||
@ -342,6 +347,14 @@ ObjectDefineProperties(Console.prototype, {
|
||||
__proto__: null,
|
||||
...consolePropAttributes,
|
||||
value: function(args) {
|
||||
if (args.length === 1) {
|
||||
// Fast path: single string, don't call format.
|
||||
// Avoids ReflectApply and validation overhead.
|
||||
const a0 = args[0];
|
||||
if (typeof a0 === 'string') {
|
||||
return a0;
|
||||
}
|
||||
}
|
||||
const opts = this[kGetInspectOptions](this._stdout);
|
||||
ArrayPrototypeUnshift(args, opts);
|
||||
return ReflectApply(formatWithOptions, null, args);
|
||||
@ -351,6 +364,14 @@ ObjectDefineProperties(Console.prototype, {
|
||||
__proto__: null,
|
||||
...consolePropAttributes,
|
||||
value: function(args) {
|
||||
if (args.length === 1) {
|
||||
// Fast path: single string, don't call format.
|
||||
// Avoids ReflectApply and validation overhead.
|
||||
const a0 = args[0];
|
||||
if (typeof a0 === 'string') {
|
||||
return a0;
|
||||
}
|
||||
}
|
||||
const opts = this[kGetInspectOptions](this._stderr);
|
||||
ArrayPrototypeUnshift(args, opts);
|
||||
return ReflectApply(formatWithOptions, null, args);
|
||||
@ -513,21 +534,20 @@ const consoleMethods = {
|
||||
ReflectApply(this.log, this, data);
|
||||
}
|
||||
|
||||
let currentIndentation = internalIndentationMap.get(this) || '';
|
||||
let currentIndentation = this[kGroupIndentationString];
|
||||
currentIndentation += StringPrototypeRepeat(' ', this[kGroupIndentationWidth]);
|
||||
|
||||
internalIndentationMap.set(this, currentIndentation);
|
||||
this[kGroupIndentationString] = currentIndentation;
|
||||
},
|
||||
|
||||
groupEnd() {
|
||||
const currentIndentation = internalIndentationMap.get(this) || '';
|
||||
const currentIndentation = this[kGroupIndentationString];
|
||||
const newIndentation = StringPrototypeSlice(
|
||||
currentIndentation,
|
||||
0,
|
||||
currentIndentation.length - this[kGroupIndentationWidth],
|
||||
);
|
||||
|
||||
internalIndentationMap.set(this, newIndentation);
|
||||
this[kGroupIndentationString] = newIndentation;
|
||||
},
|
||||
|
||||
// https://console.spec.whatwg.org/#table
|
||||
|
||||
Loading…
Reference in New Issue
Block a user