Wednesday, November 14, 2012

Quick Dart Benchmarking Follow-up

‹prev | My Chain | next›

I was not terribly surprised to find that the relatively new server-side Dart HTTP server was significantly slower than the more established node.js / express.js. A simple express.js server was, in fact, 20% faster at serving static files than similar Dart code. That is about what I would expect, but before moving on, I would like to make sure that I am making an apples-to-apples comparison. That is, I would like to make sure that the express.js version is not doing any caching.

After a bit of investigation, I discover the staticCache middleware in express (which is actually part of the underlying connect.js). So I add this to my app's configuration:
app.configure(function(){
  app.set('views', __dirname + '/views');
  app.set('view engine', 'jade');
  app.use(express.bodyParser());
  app.use(express.methodOverride());
  app.use(app.router);
  app.use(express.staticCache());
  app.use(express.static(__dirname + '/public'));
});
Then re-run my benchmarks:
cstrom@londo:~/repos/dart-comics$ ab -n 10000 -c 2 http://localhost:3000/scripts/web/main.dart
...
Requests per second:    2199.68 [#/sec] (mean)
Time per request:       0.909 [ms] (mean)
Compare that with yesterday's non-cache results:
cstrom@londo:~/repos/dart-comics$ ab -n 10000 -c 2 http://localhost:3000/scripts/web/main.dart
...
Requests per second:    1602.96 [#/sec] (mean)
Time per request:       1.248 [ms] (mean)
And it is clear that node.js caching only makes the difference between server-side Dart and node.js that much bigger.

I am not going to dwell on the differences too much and definitely do not want to spend time optimizing Dart code further. I only want to implement a pure Dart backend for my sample application. That said, I am curious if route matching is causing most of the slow down or if it is just the underlying filesystem calls that are trouble.

So I rewrite my addRequetHandler() so that the route matching function always returns true and then let the response function do its thing:
#import('dart:io');

main() {
  HttpServer app = new HttpServer();

  var last_path;

  app.addRequestHandler(
    (req) => true,
    (req, res) {
      var file = new File(publicPath(req.path));
      var stream = file.openInputStream();
      stream.pipe(res.outputStream);
    }
  );
  app.listen('0.0.0.0', 8000);
}
With that, I find the following numbers:
cstrom@londo:~/repos/dart-comics$ ab -n 10000 -c 2 http://localhost:8000/scripts/web/main.dart
...
Requests per second:    1650.30 [#/sec] (mean)
Time per request:       1.212 [ms] (mean)
Which is a better than my best Dart solution from yesterday with a routing function:
Requests per second:    1566.07 [#/sec] (mean)
Time per request:       1.277 [ms] (mean)
Actually, that is also better than the non-caching express.js solution as well:
cstrom@londo:~/repos/dart-comics$ ab -n 10000 -c 2 http://localhost:3000/scripts/web/main.dart
...
Requests per second:    1602.96 [#/sec] (mean)
Time per request:       1.248 [ms] (mean)
So, if I cared about performance, I might look to improve the route matching function first. Most of my handler is spending its time in the response callback, but there is a good 20% overhead in my file-existence routing callback. It's a good thing I do not care. Instead of chasing numbers, tomorrow I will pick back up trying to replace functionality in my sample app.

Day #570

No comments:

Post a Comment