Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

http: Don't hot-path end() for large buffers

The benefits of the hot-path optimization below start to fall off when
the buffer size gets up near 128KB, because the cost of the copy is more
than the cost of the extra write() call.  Switch to the write/end method
at that point.

Heuristics and magic numbers are awful, but slow http responses are
worse.

Fix #4975
  • Loading branch information...
commit 8cac97396af42f3aff8e4b56b865951267e35234 1 parent 028c630
@isaacs authored
Showing with 67 additions and 0 deletions.
  1. +59 −0 benchmark/http/end-vs-write-end.js
  2. +8 −0 lib/http.js
View
59 benchmark/http/end-vs-write-end.js
@@ -0,0 +1,59 @@
+// When calling .end(buffer) right away, this triggers a "hot path"
+// optimization in http.js, to avoid an extra write call.
+//
+// However, the overhead of copying a large buffer is higher than
+// the overhead of an extra write() call, so the hot path was not
+// always as hot as it could be.
+//
+// Verify that our assumptions are valid.
+
+var common = require('../common.js');
+var PORT = common.PORT;
+
+var bench = common.createBenchmark(main, {
+ type: ['asc', 'utf', 'buf'],
+ kb: [64, 128, 256, 1024],
+ c: [100],
+ method: ['write', 'end '] // two spaces added to line up each row
+});
+
+function main(conf) {
+ http = require('http');
+ var chunk;
+ var len = conf.kb * 1024;
+ switch (conf.type) {
+ case 'buf':
+ chunk = new Buffer(len);
+ chunk.fill('x');
+ break;
+ case 'utf':
+ encoding = 'utf8';
+ chunk = new Array(len / 2 + 1).join('ü');
+ break;
+ case 'asc':
+ chunk = new Array(len + 1).join('a');
+ break;
+ }
+
+ function write(res) {
+ res.write(chunk);
+ res.end();
+ }
+
+ function end(res) {
+ res.end(chunk);
+ }
+
+ var method = conf.method === 'write' ? write : end;
+ var args = ['-r', 5000, '-t', 8, '-c', conf.c];
+
+ var server = http.createServer(function(req, res) {
+ method(res);
+ });
+
+ server.listen(common.PORT, function() {
+ bench.http('/', args, function() {
+ server.close();
+ });
+ });
+}
View
8 lib/http.js
@@ -855,6 +855,14 @@ OutgoingMessage.prototype.end = function(data, encoding) {
this.connection.writable &&
this.connection._httpMessage === this;
+ // The benefits of the hot-path optimization below start to fall
+ // off when the buffer size gets up near 128KB, because the cost
+ // of the copy is more than the cost of the extra write() call.
+ // Switch to the write/end method at that point. Heuristics and
+ // magic numbers are awful, but slow http responses are worse.
+ if (hot && Buffer.isBuffer(data) && data.length > 120 * 1024)
+ hot = false;
+
if (hot) {
// Hot path. They're doing
// res.writeHead();

0 comments on commit 8cac973

Please sign in to comment.
Something went wrong with that request. Please try again.