Milliseconds to Millions! emoji unicode: 1f911

Benchmarking & Optimization for fun and profit!!​

Hello World!

Entrepreneur, Hacker, Developer
Open Source Advocate & Dog Lover

@AhmadNassri

AhmadNassri.com

Principal Architect at TELUS Digital, Founder at Bench CI, Founder at Tech Masters, Mentor at Node School Toronto, Board Member at Full Stack Toronto, Editor at The RESTful Web.

 


Tech Outlaw, Wanted by a third-world dictator
(true story)

PERFORMANCe

... maybe?

Agile SDLC

Agile SDLC

Agile SDLC

Benchmarking

&

Profiling

WHY SHOULD I CARE?

Measure Performance

Code quality is not enough, keep track of performance and efficient resource usage.

Reduce Resource Consumption

Memory capacity & CPU cycles are precious in resource constrained environments

Ship With Confidence

Ensure your software operates on and within any hardware & resource constraints.

WHY SHOULD I CARE?

Bank System SCenario

A Bank System manages a trillion dollars, processes millions of transactions per minute.

 

You are the best coder in the world, your error rate is 0.001.


Will your change save us a billion dollars or cost us billions?

Benchmarking

It's EAsy!

Discover optimizations that could impact the largest number of users

$ time for a in {1..10}; do node bench.js; done

real    0m13.042s
user    0m0.021s
sys     0m0.044s

IT'S SUPER EASY!

LET's GO Deeper!

Benchmark.js

https://benchmarkjs.com

new Benchmark.Suite()
  .add({
    name: 'JSON.parse',
    fn: () => JSON.parse(json)
  })

  .add({
    name: 'jsonparse',
    defer: true,
    fn: (deferred) => {
      let p = new Jsonparse()
      p.onValue = function (data) {
        if (this.stack.length === 0) {
          deferred.resolve()
        }
      }
      p.write(json)
    }
  })

  .add({
    name: 'vuvuzela',
    fn: () => vuvuzela.parse(json)
  })

  .run()

Benchmark.js

 clarinet          x  2,636 ops/sec ±2.13% (78 runs sampled)
 JSON.parse        x 80,639 ops/sec ±2.14% (88 runs sampled)
 jju               x  7,343 ops/sec ±3.12% (84 runs sampled)
 jsonparse         x 10,719 ops/sec ±4.54% (45 runs sampled)
 json-parse-stream x  2,039 ops/sec ±6.39% (69 runs sampled)
 stream-json       x  1,775 ops/sec ±1.14% (82 runs sampled)
 vuvuzela          x 15,644 ops/sec ±4.07% (87 runs sampled)

Benchmark.js

More Examples

https://github.com/ahmadnassri/benchmark-node-json-parse

 

https://github.com/ahmadnassri/benchmark-node-clone

Profiling!

Okay, this one is not as easy

app.get('/auth', function (req, res) {
  var username = req.query.username || '';
  var password = req.query.password || '';

  username = username.replace(/[!@#$%^&*]/g, '');

  if (!username || !password || !users[username]) {
    return res.sendStatus(400);
  }

  var hash = crypto.pbkdf2Sync(password, users[username].salt, 10000, 512);

  if (users[username].hash.toString() === hash.toString()) {
    res.sendStatus(200);
  } else {
    res.sendStatus(401);
  }
});

Node.js Profiler

node --prof ./app.js
node --prof-process ./the-generated-log-file

Node.js Profiler

[Summary]:
   ticks  total  nonlib   name
     79    0.2%    0.2%  JavaScript
  36703   97.2%   99.2%  C++
      7    0.0%    0.0%  GC
    767    2.0%          Shared libraries
    215    0.6%          Unaccounted

Node.js Profiler

 [C++]:
   ticks  total  nonlib   name
  19557   51.8%   52.9%  node::crypto::PBKDF2(v8::FunctionCallbackInfo<v8::Value> const&)
   4510   11.9%   12.2%  _sha1_block_data_order
   3165    8.4%    8.6%  _malloc_zone_malloc

Node.js Profiler

 [Bottom up (heavy) profile]
   ticks parent  name
  19557   51.8%  node::crypto::PBKDF2(v8::FunctionCallbackInfo<v8::Value> const&)
  19557  100.0%    v8::internal::Builtins::~Builtins()
  19557  100.0%      LazyCompile: ~pbkdf2 crypto.js:557:16

   4510   11.9%  _sha1_block_data_order
   4510  100.0%    LazyCompile: *pbkdf2 crypto.js:557:16
   4510  100.0%      LazyCompile: *exports.pbkdf2Sync crypto.js:552:30

   3165    8.4%  _malloc_zone_malloc
   3161   99.9%    LazyCompile: *pbkdf2 crypto.js:557:16
   3161  100.0%      LazyCompile: *exports.pbkdf2Sync crypto.js:552:30

Node.js Profiler

Node.js Profiler

app.get('/auth', function (req, res) {
  var username = req.query.username || '';
  var password = req.query.password || '';

  username = username.replace(/[!@#$%^&*]/g, '');

  if (!username || !password || !users[username]) {
    return res.sendStatus(400);
  }

  crypto.pbkdf2(password, users[username].salt, 10000, 512, function(err, hash) {
    if (users[username].hash.toString() === hash.toString()) {
      res.sendStatus(200);
    } else {
      res.sendStatus(401);
    }
  })
})

PRO MODE++

GOtchas

Transpilers!

Benchmarking != Monitoring

System calls!

Dependencies

Thank you!

@AhmadNassri

AhmadNassri.com

Slides & Links will be up on 
AhmadNassri.com/talks
TechMasters.chat
NodeSchool.io/toronto
FSTO.co

Milliseconds to Millions

By Ahmad Nassri

Milliseconds to Millions

Benchmarking & Optimization for fun and profit

  • 1,098