lib: faster FreeList
Make FreeList faster by using Reflect.apply and not using is_reused_symbol, but rather just checking whether any items are present in the list prior to calling alloc. PR-URL: https://github.com/nodejs/node/pull/27021 Reviewed-By: Anna Henningsen <anna@addaleax.net> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Gus Caplan <me@gus.host> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com>
This commit is contained in:
parent
547576f530
commit
47f5cc1ad1
@ -9,7 +9,9 @@ const bench = common.createBenchmark(main, {
|
|||||||
});
|
});
|
||||||
|
|
||||||
function main({ n }) {
|
function main({ n }) {
|
||||||
const { FreeList } = require('internal/freelist');
|
let FreeList = require('internal/freelist');
|
||||||
|
if (FreeList.FreeList)
|
||||||
|
FreeList = FreeList.FreeList;
|
||||||
const poolSize = 1000;
|
const poolSize = 1000;
|
||||||
const list = new FreeList('test', poolSize, Object);
|
const list = new FreeList('test', poolSize, Object);
|
||||||
var j;
|
var j;
|
||||||
|
@ -46,7 +46,6 @@ const {
|
|||||||
ERR_UNESCAPED_CHARACTERS
|
ERR_UNESCAPED_CHARACTERS
|
||||||
} = require('internal/errors').codes;
|
} = require('internal/errors').codes;
|
||||||
const { getTimerDuration } = require('internal/timers');
|
const { getTimerDuration } = require('internal/timers');
|
||||||
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
|
|
||||||
const {
|
const {
|
||||||
DTRACE_HTTP_CLIENT_REQUEST,
|
DTRACE_HTTP_CLIENT_REQUEST,
|
||||||
DTRACE_HTTP_CLIENT_RESPONSE
|
DTRACE_HTTP_CLIENT_RESPONSE
|
||||||
@ -631,10 +630,11 @@ function emitFreeNT(socket) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function tickOnSocket(req, socket) {
|
function tickOnSocket(req, socket) {
|
||||||
|
const isParserReused = parsers.hasItems();
|
||||||
const parser = parsers.alloc();
|
const parser = parsers.alloc();
|
||||||
req.socket = socket;
|
req.socket = socket;
|
||||||
req.connection = socket;
|
req.connection = socket;
|
||||||
parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol]);
|
parser.reinitialize(HTTPParser.RESPONSE, isParserReused);
|
||||||
parser.socket = socket;
|
parser.socket = socket;
|
||||||
parser.outgoing = req;
|
parser.outgoing = req;
|
||||||
req.parser = parser;
|
req.parser = parser;
|
||||||
|
@ -29,7 +29,7 @@ const { methods, HTTPParser } =
|
|||||||
getOptionValue('--http-parser') === 'legacy' ?
|
getOptionValue('--http-parser') === 'legacy' ?
|
||||||
internalBinding('http_parser') : internalBinding('http_parser_llhttp');
|
internalBinding('http_parser') : internalBinding('http_parser_llhttp');
|
||||||
|
|
||||||
const { FreeList } = require('internal/freelist');
|
const FreeList = require('internal/freelist');
|
||||||
const { ondrain } = require('internal/http');
|
const { ondrain } = require('internal/http');
|
||||||
const incoming = require('_http_incoming');
|
const incoming = require('_http_incoming');
|
||||||
const {
|
const {
|
||||||
|
@ -41,7 +41,6 @@ const {
|
|||||||
defaultTriggerAsyncIdScope,
|
defaultTriggerAsyncIdScope,
|
||||||
getOrSetAsyncId
|
getOrSetAsyncId
|
||||||
} = require('internal/async_hooks');
|
} = require('internal/async_hooks');
|
||||||
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
|
|
||||||
const { IncomingMessage } = require('_http_incoming');
|
const { IncomingMessage } = require('_http_incoming');
|
||||||
const {
|
const {
|
||||||
ERR_HTTP_HEADERS_SENT,
|
ERR_HTTP_HEADERS_SENT,
|
||||||
@ -348,8 +347,9 @@ function connectionListenerInternal(server, socket) {
|
|||||||
socket.setTimeout(server.timeout);
|
socket.setTimeout(server.timeout);
|
||||||
socket.on('timeout', socketOnTimeout);
|
socket.on('timeout', socketOnTimeout);
|
||||||
|
|
||||||
|
const isParserReused = parsers.hasItems();
|
||||||
const parser = parsers.alloc();
|
const parser = parsers.alloc();
|
||||||
parser.reinitialize(HTTPParser.REQUEST, parser[is_reused_symbol]);
|
parser.reinitialize(HTTPParser.REQUEST, isParserReused);
|
||||||
parser.socket = socket;
|
parser.socket = socket;
|
||||||
|
|
||||||
// We are starting to wait for our headers.
|
// We are starting to wait for our headers.
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
const is_reused_symbol = Symbol('isReused');
|
const { Reflect } = primordials;
|
||||||
|
|
||||||
class FreeList {
|
class FreeList {
|
||||||
constructor(name, max, ctor) {
|
constructor(name, max, ctor) {
|
||||||
@ -10,16 +10,14 @@ class FreeList {
|
|||||||
this.list = [];
|
this.list = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
alloc() {
|
hasItems() {
|
||||||
let item;
|
return this.list.length > 0;
|
||||||
if (this.list.length > 0) {
|
|
||||||
item = this.list.pop();
|
|
||||||
item[is_reused_symbol] = true;
|
|
||||||
} else {
|
|
||||||
item = this.ctor.apply(this, arguments);
|
|
||||||
item[is_reused_symbol] = false;
|
|
||||||
}
|
}
|
||||||
return item;
|
|
||||||
|
alloc() {
|
||||||
|
return this.list.length > 0 ?
|
||||||
|
this.list.pop() :
|
||||||
|
Reflect.apply(this.ctor, this, arguments);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(obj) {
|
free(obj) {
|
||||||
@ -31,9 +29,4 @@ class FreeList {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = FreeList;
|
||||||
FreeList,
|
|
||||||
symbols: {
|
|
||||||
is_reused_symbol
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
require('../common');
|
require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const { FreeList } = require('internal/freelist');
|
const FreeList = require('internal/freelist');
|
||||||
|
|
||||||
assert.strictEqual(typeof FreeList, 'function');
|
assert.strictEqual(typeof FreeList, 'function');
|
||||||
|
|
||||||
|
@ -6,7 +6,6 @@
|
|||||||
const common = require('../common');
|
const common = require('../common');
|
||||||
const assert = require('assert');
|
const assert = require('assert');
|
||||||
const httpCommon = require('_http_common');
|
const httpCommon = require('_http_common');
|
||||||
const is_reused_symbol = require('internal/freelist').symbols.is_reused_symbol;
|
|
||||||
const { HTTPParser } = require('_http_common');
|
const { HTTPParser } = require('_http_common');
|
||||||
const net = require('net');
|
const net = require('net');
|
||||||
|
|
||||||
@ -25,7 +24,7 @@ function execAndClose() {
|
|||||||
process.stdout.write('.');
|
process.stdout.write('.');
|
||||||
|
|
||||||
const parser = parsers.pop();
|
const parser = parsers.pop();
|
||||||
parser.reinitialize(HTTPParser.RESPONSE, parser[is_reused_symbol]);
|
parser.reinitialize(HTTPParser.RESPONSE, !!parser.reused);
|
||||||
|
|
||||||
const socket = net.connect(common.PORT);
|
const socket = net.connect(common.PORT);
|
||||||
socket.on('error', (e) => {
|
socket.on('error', (e) => {
|
||||||
@ -33,6 +32,7 @@ function execAndClose() {
|
|||||||
// https://github.com/nodejs/node/issues/2663.
|
// https://github.com/nodejs/node/issues/2663.
|
||||||
if (common.isSunOS && e.code === 'ECONNREFUSED') {
|
if (common.isSunOS && e.code === 'ECONNREFUSED') {
|
||||||
parsers.push(parser);
|
parsers.push(parser);
|
||||||
|
parser.reused = true;
|
||||||
socket.destroy();
|
socket.destroy();
|
||||||
setImmediate(execAndClose);
|
setImmediate(execAndClose);
|
||||||
return;
|
return;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user