UNPKG

3.36 kBJavaScriptView Raw
1'use strict'
2
3const async = require('async')
4const endpoint = require('endpoint')
5const stream = require('../lib/destroyable-stream')
6const guessInterval = require('./guess-interval.js')
7const analyseCPU = require('./analyse-cpu.js')
8const analyseDelay = require('./analyse-delay.js')
9const analyseMemory = require('./analyse-memory.js')
10const analyseHandles = require('./analyse-handles.js')
11const issueCategory = require('./issue-category.js')
12
13class Analysis extends stream.Readable {
14 constructor (systemInfoReader, traceEventReader, processStatReader) {
15 super({ objectMode: true })
16
17 async.waterfall([
18 collectData.bind(null, systemInfoReader, traceEventReader, processStatReader),
19 analyseData
20 ], this._done.bind(this))
21 }
22
23 _done (err, result) {
24 if (err) this.destroy(err)
25 this.push(result)
26 this.push(null)
27 }
28
29 _read () {
30 // will call push when all data is collected
31 }
32}
33
34function collectData (systemInfoReader, traceEventReader, processStatReader, callback) {
35 async.parallel({
36 systemInfo (done) {
37 systemInfoReader.pipe(endpoint({ objectMode: true }, function (err, data) {
38 if (err) return done(err)
39 done(null, data[0])
40 }))
41 },
42 traceEvent (done) {
43 traceEventReader.pipe(endpoint({ objectMode: true }, done))
44 },
45 processStat (done) {
46 processStatReader.pipe(endpoint({ objectMode: true }, done))
47 }
48 }, callback)
49}
50
51function analyseData ({ systemInfo, traceEvent, processStat }, callback) {
52 // guess the interval for where the benchmarker ran
53 const intervalIndex = guessInterval(processStat)
54
55 if (processStat.length < 2) {
56 return callback(null, {
57 interval: [-Infinity, Infinity],
58 issues: {
59 delay: 'data',
60 cpu: 'data',
61 memory: {
62 external: 'data',
63 rss: 'data',
64 heapTotal: 'data',
65 heapUsed: 'data'
66 },
67 handles: 'data'
68 },
69 issueCategory: 'data'
70 })
71 }
72
73 const intervalTime = [
74 processStat[intervalIndex[0]].timestamp,
75 processStat[intervalIndex[1] - 1].timestamp
76 ]
77
78 const { processStatSubset, traceEventSubset } = subsetData(
79 traceEvent, processStat, intervalIndex, intervalTime
80 )
81
82 // Check for issues, the CPU analysis is async
83 analyseCPU(systemInfo, processStatSubset, traceEventSubset, function (err, cpuIssue) {
84 /* istanbul ignore if: it is very rare that HMM doesn't converge */
85 if (err) return callback(err)
86
87 const issues = {
88 delay: analyseDelay(systemInfo, processStatSubset, traceEventSubset),
89 cpu: cpuIssue,
90 memory: analyseMemory(systemInfo, processStatSubset, traceEventSubset),
91 handles: analyseHandles(systemInfo, processStatSubset, traceEventSubset)
92 }
93
94 const category = issueCategory(issues)
95
96 callback(null, {
97 interval: intervalTime,
98 issues: issues,
99 issueCategory: category
100 })
101 })
102}
103
104function subsetData (traceEvent, processStat, intervalIndex, intervalTime) {
105 const processStatSubset = processStat.slice(...intervalIndex)
106 const traceEventSubset = []
107 for (const datum of traceEvent) {
108 if (datum.args.startTimestamp >= intervalTime[0] &&
109 datum.args.endTimestamp <= intervalTime[1]) {
110 traceEventSubset.push(datum)
111 }
112 }
113
114 return { processStatSubset, traceEventSubset }
115}
116
117module.exports = Analysis