Tech Tips

  1. Uncategorized
  2. 124 view

[node.js][exprees]How to take snapshot of CPU and Heap

node-snap-cpu2
node-snap-heap
node-snap-heap2

Overview

I used to be annoyed by memory leak (and CPU load) when I use node.js for web app development.
I tried to take snapshots and found bottle necks.
This article is how to take snapshot with memory and CPU.
We can check the result of snapshot with Google Chrome browser’s developer tool.

Work Environment

  • OS
    • Linux www4322gi 3.2.0-64-generic #97-Ubuntu SMP Wed Jun 4 22:04:21 UTC 2014 x86_64 x86_64 x86_64 GNU/Linux
  • Node
    • version: v0.10.26
  • Library

Preparation

Install nvm and node.js here.

Bulding

Make template with express

$ vim package.json
{
  "name": "snapshot_test",
  "version": "0.0.1",
  "dependencies": {
    "express": "4.8.7",
    "ejs": "1.0.0",
    "express-generator": "4.8.0"
  }
}

$ npm install

$ ls node_modules/.bin/
express

$ ./node_modules/.bin/express -e -t ejs snapshot_test

$ ls snapshot_test/
app.js  bin  package.json  public  routes  views

Development sample app

$ cd snapshot_test
$ vim package.json
{
  "name": "snapshot_test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "express": "~4.8.6",
    "body-parser": "~1.6.6",
    "cookie-parser": "~1.3.2",
    "morgan": "~1.2.3",
    "serve-favicon": "~2.0.1",
    "debug": "~1.0.4",
    "ejs": "~0.8.5",
    "request": "2.40.0",
    "cheerio": "0.17.0"
  }
}

$ npm update

routes/index.js

var express = require('express');
var router = express.Router();

var request = require('request');
var cheerio = require('cheerio');

/* GET home page. */
router.get('/', function(req, res) {
  var url = 'http://160.16.71.152:12080/';

  request(url, function (error, response, body) {
    // Connection success
    if (!error && response.statusCode == 200) {
      // Parse
      var $ = cheerio.load(body);
      var hrefs = [];

      // Retrieve all link urls in the page
      $('a').each(function() {
        hrefs.push($(this).attr('href'));
      });

      // return response
      var result = {}
      result.status = 'success';
      result.contents = hrefs;
      res.send(JSON.stringify(result));
    // Error result
    } else {
      var result = {}
      result.status = 'error';
      result.contents = '';
      res.send(JSON.stringify(result));
    }
  })
});

module.exports = router;

Development snapshot part

$ vim package.json
{
  "name": "snapshot_test",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "express": "~4.8.6",
    "body-parser": "~1.6.6",
    "cookie-parser": "~1.3.2",
    "morgan": "~1.2.3",
    "serve-favicon": "~2.0.1",
    "debug": "~1.0.4",
    "ejs": "~0.8.5",
    "request": "2.40.0",
    "cheerio": "0.17.0",
    "nodegrind": "0.1.8",
    "heapdump": "0.2.10"
  }
}

$ npm update

routes/snapcpu.js

var express = require('express');
var router = express.Router();

var fs = require('fs');
var profiler = require('nodegrind');

router.get('/', function(req, res) {
  // filename
  var name =  (new Date().getTime()) + '.cpuprofile';

  // Start to measure
  profiler.startCPU(name);

  // Stop to measure after 5 sec
  setTimeout(function(){
    var cpuProfile = profiler.stopCPU(name, 'cpuprofile');

    //Write profile
    fs.writeFile(name, cpuProfile, function(err){
      if (err) res.send(err);
      else     res.send('OK:' + name);
    });
  }, 5000);
});

module.exports = router;

routes/snapheap.js

var express = require('express');
var router = express.Router();

var fs = require('fs');
var heapdump = require('heapdump');

router.get('/', function(req, res) {
  // filename
  var name = (new Date().getTime()) + '.heapsnapshot';

  // Take a snapshot of heap
  heapdump.writeSnapshot(name, function() {
    res.send('OK:' + name);
  });
});

module.exports = router;

Routing Setting

app.js

var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');

var routes = require('./routes/index');
var users = require('./routes/users');
var snapcpu = require('./routes/snapcpu');
var snapheap = require('./routes/snapheap');

var app = express();

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

// uncomment after placing your favicon in /public
//app.use(favicon(__dirname + '/public/favicon.ico'));
app.use(logger('dev'));
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.use('/', routes);
app.use('/users', users);
app.use('/snapcpu', snapcpu);
app.use('/snapheap', snapheap);

// catch 404 and forward to error handler
app.use(function(req, res, next) {
    var err = new Error('Not Found');
    err.status = 404;
    next(err);
});

// error handlers

// development error handler
// will print stacktrace
if (app.get('env') === 'development') {
    app.use(function(err, req, res, next) {
        res.status(err.status || 500);
        res.render('error', {
            message: err.message,
            error: err
        });
    });
}

// production error handler
// no stacktraces leaked to user
app.use(function(err, req, res, next) {
    res.status(err.status || 500);
    res.render('error', {
        message: err.message,
        error: {}
    });
});

module.exports = app;

Behavior Check

$ curl http://127.0.0.1:3000
{"status":"success","contents":["http://160.16.71.152:12080/","http://160.16.71.152:12080/?page_id=382",.....................,"http://www.adazing.com/"]}

Check result of snapshot

Take snapshot of heap

$ for i in `seq 5`; do curl 'http://127.0.0.1:3000/'; sleep 1s; done

$ curl http://127.0.0.1:3000/snapheap
OK:1409475822884.heapsnapshot

$ ls
1409475822884.heapsnapshot  app.js  bin  node_modules  package.json  public  routes  views

Take snapshot of CPU

$ for i in `seq 10`; do curl 'http://127.0.0.1:3000'; sleep 1s; done

# Do following command during for loop
$ curl http://127.0.0.1:3000/snapcpu

$ ls
1409475822884.heapsnapshot  1409477190566.cpuprofile  app.js  bin  node_modules  package.json  public  routes  views

Result Check

node-snap-cpu
node-snap-cpu2
node-snap-heap
node-snap-heap2

Uncategorized recent post

  1. Run Amazon FreeRTOS on M5Stack Core2 for AWS …

  2. Udacity Self-Driving Car Engineer Nanodegree …

  3. Install sbt 1.0.0 and run sample template

  4. Visualization of Neural Network and its Train…

  5. [Machine Learning]Created docker image includ…

関連記事

PAGE TOP