Skip to content

Commit

Permalink
testing \o/
Browse files Browse the repository at this point in the history
  • Loading branch information
Swatinem committed Oct 28, 2013
1 parent e61fb3a commit 1186f53
Show file tree
Hide file tree
Showing 3 changed files with 292 additions and 11 deletions.
10 changes: 5 additions & 5 deletions lib/accumulator.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,8 @@ module.exports = Accumulator;

function Accumulator() {
Transform.call(this, {objectMode: true});
this.head = new Sample({function: '(root)'}, 0);
this.sampleid = 0;
this.head = new Sample(this, {function: '(root)'}, 0);
this.samples = [];
this.uidMap = new Map();
this.uids = 0;
Expand All @@ -27,7 +28,7 @@ Accumulator.prototype._transform = function Accumulator__transform(stack, encodi
var sample;
if (j == parent.children.length) {
// we didnt find a matching child, so create a new one
sample = new Sample(frame, uid);
sample = new Sample(this, frame, uid);
parent.children.push(sample);
}
// the new parent is either the newly created sample,
Expand Down Expand Up @@ -68,9 +69,8 @@ function Symbol(frame) {
return symbol;
}

var id = 0;
function Sample(frame, uid) {
this.id = ++id;
function Sample(accumulator, frame, uid) {
this.id = ++accumulator.sampleid;
this.callUID = uid;
this.hitCount = 0;
this.lineNumber = 0;
Expand Down
4 changes: 4 additions & 0 deletions lib/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@

exports = module.exports = perfCpuprofile;

// expose for testing:
exports.Lines = require('./lines');
exports.Samples = require('./samples');

var Reader = exports.Reader = require('./reader');
var Accumulator = exports.Accumulator = require('./accumulator');

Expand Down
289 changes: 283 additions & 6 deletions test/perf-cpuprofile.js
Original file line number Diff line number Diff line change
@@ -1,14 +1,291 @@

var PassThrough = require('stream').PassThrough;
var perfCpuprofile = require('../');
var Lines = perfCpuprofile.Lines;
var Samples = perfCpuprofile.Samples;
var Accumulator = perfCpuprofile.Accumulator;

// fake inputstream:
var input = new PassThrough();
input.push('');
input.push(null);
describe('Lines', function () {
it('should split the input stream into lines', function (done) {
var input = new PassThrough();
var lines = new Lines();
input.pipe(lines);
input.push('one partial ');
input.push('line\nand a second one');
input.push(null);
toArray(lines, function (arr) {
arr.should.eql([
'one partial line\n',
'and a second one'
]);
done();
});
});
});

describe('Samples', function () {
it('should ignore comments', function (done) {
var input = new PassThrough({objectMode: true});
var samples = new Samples();
input.pipe(samples);
input.push('# one comment\n');
input.push(null);
toArray(samples, function (arr) {
arr.should.eql([]);
done();
});
});
it('should extract a sample', function (done) {
var input = new PassThrough({objectMode: true});
var samples = new Samples();
input.pipe(samples);
input.push('a-header 123456 cycles:\n');
input.push(' 00deadbeef functionname (libfoo.so.0.0)');
input.push(null);
toArray(samples, function (arr) {
arr.should.eql([[{
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}]]);
done();
});
});
it('should handle separate samples by a newline', function (done) {
var input = new PassThrough({objectMode: true});
var samples = new Samples();
input.pipe(samples);
input.push('a-header 123456 cycles:\n');
input.push(' 00deadbeef subcall (libfoo.so.0.0)\n');
input.push(' 00deadbeef functionname (libfoo.so.0.0)\n');
input.push('\n');
input.push('a-header 123456 cycles:\n');
input.push(' 00deadbeef2 functionname2 (libbar.so.0.0)\n');
input.push(null);
toArray(samples, function (arr) {
arr.should.eql([[{
function: 'subcall',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, {
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}], [{
function: 'functionname2',
object: 'libbar.so.0.0',
address: '00deadbeef2'
}]]);
done();
});
});
});

// TODO: actually write some tests :-)
describe('Accumulator', function () {
it('should create a sample tree', function (done) {
var input = new PassThrough({objectMode: true});
var accumulator = new Accumulator();
input.pipe(accumulator);
input.push([{
function: 'subcall',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, {
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}]);
input.push(null);
toArray(accumulator, function (arr) {
var out = example();
arr.should.eql([out]);
done();
});
});
it('should increment the hitcount for equal stackframes', function (done) {
var input = new PassThrough({objectMode: true});
var accumulator = new Accumulator();
input.pipe(accumulator);
var frame = [{
function: 'subcall',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, {
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}];
input.push(frame);
input.push(frame);
input.push(null);
toArray(accumulator, function (arr) {
var out = example();
out.endTime = 0.002;
out.samples.push(3);
out.head.children[0].children[0].hitCount = 2;
arr.should.eql([out]);
done();
});
});
it('should give equal functions the same callUID', function (done) {
var input = new PassThrough({objectMode: true});
var accumulator = new Accumulator();
input.pipe(accumulator);
var frame = [{
function: 'subcall',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, {
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}];
input.push(frame);
var frame2 = [frame[0], {
function: 'otherfunction',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}];
input.push(frame2);
input.push(null);
toArray(accumulator, function (arr) {
var out = example();
out.endTime = 0.002;
out.samples.push(5);
out.head.children.push(exampleSumtree);
arr.should.eql([out]);
done();
});
});
it('should use the address if the function name is `[unknown]`', function (done) {
var input = new PassThrough({objectMode: true});
var accumulator = new Accumulator();
input.pipe(accumulator);
var frame = [{
function: 'subcall',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, {
function: 'functionname',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}];
input.push(frame);
var frame2 = [{
function: '[unknown]',
object: 'libfoo.so.0.0',
address: '00deadbeef'
}, frame[1]];
input.push(frame2);
input.push(null);
toArray(accumulator, function (arr) {
var out = example();
out.endTime = 0.002;
out.samples.push(4);
out.head.children[0].children.push(exampleUnknown);
arr.should.eql([out]);
done();
});
});
});

describe('perfCpuprofile', function () {

it('should put all the pieces together', function (done) {
var input = new PassThrough();
input.push('# a comment\n\n');
input.push('a-header 123456 cycles:\n');
input.push(' 00deadbeef subcall (libfoo.so.0.0)\n');
input.push(' 00deadbeef functionname (libfoo.so.0.0)');
input.push(null);
perfCpuprofile(input, function (profile) {
profile.should.eql(exampleOut);
done();
});
});
});

var exampleOut = {
"samples": [
3
],
"startTime": 0,
"endTime": 0.001,
"head": {
"id": 1,
"callUID": 0,
"hitCount": 0,
"lineNumber": 0,
"url": "",
"functionName": "(root)",
"children": [
{
"id": 2,
"callUID": 1,
"hitCount": 0,
"lineNumber": 0,
"url": "libfoo.so.0.0",
"functionName": "functionname",
"children": [
{
"id": 3,
"callUID": 2,
"hitCount": 1,
"lineNumber": 0,
"url": "libfoo.so.0.0",
"functionName": "subcall",
"children": []
}
]
}
]
}
};
var exampleSumtree = {
"id": 4,
"callUID": 3,
"hitCount": 0,
"lineNumber": 0,
"url": "libfoo.so.0.0",
"functionName": "otherfunction",
"children": [
{
"id": 5,
"callUID": 2,
"hitCount": 1,
"lineNumber": 0,
"url": "libfoo.so.0.0",
"functionName": "subcall",
"children": []
}
]
};
var exampleUnknown = {
"id": 4,
"callUID": 3,
"hitCount": 1,
"lineNumber": 0,
"url": "libfoo.so.0.0",
"functionName": "00deadbeef",
"children": []
};


// just make a copy
function example() {
return JSON.parse(JSON.stringify(exampleOut));
}

function toArray(stream, callback) {
var arr = [];
function tryRead() {
var read;
while (read = stream.read()) {
arr.push(read);
}
stream.once('readable', tryRead);
}
stream.once('end', function () {
callback(arr);
});
tryRead();
}

0 comments on commit 1186f53

Please sign in to comment.