├── .gitignore ├── .npmrc ├── package.json ├── 2-server-with-optimized-function.js ├── 3-server-with-reduced-call-graph.js ├── 4-server-with-manual-serialization.js ├── 1-server-with-slow-function.js ├── LICENSE └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | -------------------------------------------------------------------------------- /.npmrc: -------------------------------------------------------------------------------- 1 | package-lock=false 2 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "node-clinic-flame-demo", 3 | "version": "1.0.0", 4 | "description": "A flame example", 5 | "repository": { 6 | "type": "git", 7 | "url": "git+https://github.com/nearform/node-clinic-flame-demo.git" 8 | }, 9 | "author": "David Mark Clements (@davidmarkclem)", 10 | "license": "Apache-2.0", 11 | "bugs": { 12 | "url": "https://github.com/nearform/node-clinic-flame-demo/issues" 13 | }, 14 | "homepage": "https://github.com/nearform/node-clinic-flame-demoe#readme", 15 | "dependencies": { 16 | "express": "^4.16.3", 17 | "fastify": "^1.8.0" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /2-server-with-optimized-function.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const express = require('express') 4 | 5 | const app = express() 6 | const payload = initPayload() 7 | 8 | app.get('/', (req, res) => { 9 | res.send(payload()) 10 | }) 11 | 12 | app.listen(3000) 13 | 14 | function initPayload (idSize = 20) { 15 | if (idSize < 6) throw Error('idSize must be greater than 5') 16 | const max = 2147483647 17 | var count = 0 18 | return function payload () { 19 | count = (count + 1) % max 20 | const date = Date.now() 21 | const chars = count.toString(36).toUpperCase() 22 | const id = '0'.repeat(idSize - chars.length) + chars 23 | return {date, id} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /3-server-with-reduced-call-graph.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fastify = require('fastify') 4 | 5 | const app = fastify() 6 | const payload = initPayload() 7 | 8 | app.get('/', (req, reply) => { 9 | reply.send(payload()) 10 | }) 11 | 12 | app.listen(3000) 13 | 14 | function initPayload (idSize = 20) { 15 | if (idSize < 6) throw Error('idSize must be greater than 5') 16 | const max = 2147483647 17 | var count = 0 18 | return function payload () { 19 | count = (count + 1) % max 20 | const date = Date.now() 21 | const chars = count.toString(36).toUpperCase() 22 | const id = '0'.repeat(idSize - chars.length) + chars 23 | return {date, id} 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /4-server-with-manual-serialization.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const fastify = require('fastify') 4 | 5 | const app = fastify() 6 | const payload = initPayload() 7 | 8 | app.get('/', (req, reply) => { 9 | reply.send(payload()) 10 | }) 11 | 12 | app.listen(3000) 13 | 14 | function initPayload (idSize = 20) { 15 | if (idSize < 6) throw Error('idSize must be greater than 5') 16 | const max = 2147483647 17 | var count = 0 18 | return function payload () { 19 | count = (count + 1) % max 20 | const date = Date.now() 21 | const chars = count.toString(36).toUpperCase() 22 | const id = '0'.repeat(idSize - chars.length) + chars 23 | return `{"date": ${date}, "id": "${id}"}` 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /1-server-with-slow-function.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | const express = require('express') 4 | 5 | const app = express() 6 | const payload = initPayload() 7 | 8 | app.get('/', (req, res) => { 9 | res.send(payload()) 10 | }) 11 | 12 | app.listen(3000) 13 | 14 | function initPayload (idSize = 20) { 15 | if (idSize < 6) throw Error('idSize must be greater than 5') 16 | return function payload () { 17 | let chars = '' 18 | let n = idSize 19 | const date = Date.now() 20 | const radix = 36 21 | n *= n * idSize 22 | while (n--) { 23 | const num = date + n 24 | chars += num.toString(radix).toUpperCase() 25 | } 26 | const id = chars.slice(-idSize) 27 | return { date, id } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (C) NearForm and Clinic.js Contributors 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in 11 | all copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 19 | THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Flame Example 2 | 3 | This is an example of a small real world-ish program. 4 | 5 | The only setup required after cloning is to run `npm install`. 6 | 7 | There are 3 iterations of a server that responds with a JSON payload containing 8 | an millisecond timestamp date, and an ID. 9 | 10 | 1. Responds with a payload generated by a sub-optimal function 11 | 1. Responds with a payload generated by an optimal function 12 | 1. Responds with a payload generated by with a smaller call-graph 13 | 1. Responds with a payload generated without a serializer (without `JSON.stringify`) 14 | 15 | Each should produce different Flame results indicating the stack profiles of each. 16 | 17 | Upon profiling `1` you should see a very few request per second. 18 | 19 | Running `2` you should see much higher requests per second, about 50x faster than `1`. 20 | 21 | Running `3` you should see around double the amount of requests per second versus `2`. 22 | 23 | Running `4` you should see roughly a 10% improvement versus `3`. 24 | 25 | 26 | To get started, generate a flame graph for the first server: 27 | 28 | ```sh 29 | clinic flame --autocannon [ / ] -- node 1-server-with-slow-function.js 30 | ``` 31 | --------------------------------------------------------------------------------