A NodeJS performance profiler and load-tester.
If you're on a Mac, run brew install gnu-time to install gtime, which allows for verbose output when timing how long a process takes to run.
All other dependencies ship with Quasimodo, requiring a simple npm install to get set up.
In the future, I may expose the configurations so you can tweak these as you wish.
- Which fibonacci algorithm runs fastest? (see /examples/fibonacci-bench)
- Which server implementation handles requests fastest? (see examples/server-bench)
- For each of the above, which code paths are bottlenecking performance?
// testing two different fibonacci algorithms for n = 40
const quasimodo = require('quasimodo');
quasimodo.registerTest({
  name: 'TEST_ONE',
  path: './fibonacci-recursive.js',
  flags: ['--some', '--fancy', '-v8-flags'], // optional
  args: ['40'], // optional
  env: ['NODE_ENV=test', 'NODE_FOO=bar'], // optional
  binary: '/path/to/custom/node/binary' // optional
});
quasimodo.registerTest({
  name: 'TEST_TWO',
  path: './fibonacci-dynamic.js',
  flags: ['--some', '--fancy', '-v8-flags'], // optional
  args: ['40'], // optional
  env: ['NODE_ENV=test', 'NODE_FOO=bar'], // optional
  binary: '/path/to/custom/node/binary' // optional
});
// HOOKS
quasimodo.beforeEach('echo Running next variant ...');
quasimodo.afterEach('echo Finishing variant ...');
quasimodo.after('echo Done with all tests');
quasimodo.run();This should have generated a quasimodo_tests/ folder with:
- profile-*.txt(profiling v8 CPU ticks)
- results.txt(time/memory per test)
- quasimodo.sh(the shell script that runs all the tests you registered)
- TODO: graphs of CPU/memory usage
- Quasimodo##configure(options=Object)
- Quasimodo##registerTest(options=Object)
- Quasimodo##before(command=String)
- Quasimodo##after(command=String)
- Quasimodo##beforeEach(command=String)
- Quasimodo##afterEach(command=String)
- Quasimodo##run()
quasimodo.registerTest({
  name: 'STRING', // required: test_name
  path: 'STRING', // required: path_to_script
  binary: 'STRING', // optional: path_to_binary (default: process.execPath)
  flags: ['--array', '--of', 'flags'], // optional: flags to pass to NodeJS (default: none)
  args: ['array', 'of', 'args'], // optional: args to pass to NodeJS (default: none)
  env: ['array', 'of', 'environment', 'variables'] // optional: env variables to pass to NodeJS (default: none)
});If you're testing server code or long-running processes, you can also pass loadtest options into Quasimodo##configure.
You can either manually pass in the string with all args/flags ...
quasimodo.configure({
  loadtest: '-c 8 -n 500 -p $TEST_FILE -T application/json http://localhost:3000/end_point'
});... or you can specify loadtest params as options
quasimodo.configure({
// -- Currently supported options from https://github.com/alexfernandez/loadtest --
  loadtest: {
    // requests
    concurrency: INTEGER, // required: # of concurrent clients to hit URL
    requests: INTEGER, // required: # of requests to make
    requests_per_second: INTEGER, // optional: requests per second sent to server
    target: 'String', // required: URL to hit
    // transport
    protocol: 'String', // optional: ssl2/tls1/etc
    insecure: BOOLEAN, // optional: allow invalid and self-signed certificates over https
    cert: 'String', // optional: path_to_cert_file. requires `key`
    key: 'String', // optional: path_to_key. requires `cert`
    timelimit: INTEGER, // optional: max # of secs to send requests
    timeout: INTEGER, // optional: max # of ms to wait on each request
    keepalive: BOOLEAN, // optional: (Connection: Keep-Alive)
    // data
    method: 'String', // optional: GET/POST/PUT/etc
    type: 'String', // optional: content-type
    data: 'String', // optional: raw data to send over the wire. require `type` and `method`
    postFile: 'String', // optional: path_of_file to post. requires `type`
    putFile: 'String', // optional: path_of_file to put. requires `type`
    patchFile: 'String', // optional: path_of_file to patch. requires `type`
    postBody: 'String', // optional: raw data to post. requires `type`
    patchBody: 'String', // optional: raw data to patch. requires `type`
    // headers
    headers: { // optional: headers to pass on each request
      'header-key': 'header-value',
      'another-header': 'another-value',
      ...
    },
    cookies: { // optional: cookies to pass on each request
      'cookie-key': 'cookie-value',
      'another-cookie': 'another-value',
      ...
    }
  }
});- Generate visualizations on heap usage and CPU usage over time
- TBD