Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
78 changes: 78 additions & 0 deletions benchmark/console/log.js
Original file line number Diff line number Diff line change
@@ -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');
}
}
34 changes: 27 additions & 7 deletions lib/internal/console/constructor.js
Original file line number Diff line number Diff line change
Expand Up @@ -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]: {
Expand Down Expand Up @@ -264,6 +264,11 @@ ObjectDefineProperties(Console.prototype, {
...consolePropAttributes,
value: groupIndentation,
},
[kGroupIndentationString]: {
__proto__: null,
...consolePropAttributes,
value: '',
},
[SymbolToStringTag]: {
__proto__: null,
writable: false,
Expand All @@ -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;
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
Loading