1 | 'use strict'
|
2 |
|
3 | const stream = require('../lib/destroyable-stream')
|
4 | const endpoint = require('endpoint')
|
5 | const parser = require('@nearform/trace-events-parser')
|
6 |
|
7 |
|
8 |
|
9 | const gcEventNames = new Set([
|
10 | 'V8.GCCompactor',
|
11 | 'V8.GCFinalizeMC',
|
12 | 'V8.GCFinalizeMCReduceMemory',
|
13 | 'V8.GCIncrementalMarking',
|
14 | 'V8.GCIncrementalMarkingFinalize',
|
15 | 'V8.GCIncrementalMarkingStart',
|
16 | 'V8.GCPhantomHandleProcessingCallback',
|
17 | 'V8.GCScavenger'
|
18 | ])
|
19 |
|
20 | class TraceEventDecoder extends stream.Transform {
|
21 | constructor (systemInfoReader) {
|
22 | super({
|
23 | readableObjectMode: true,
|
24 | writableObjectMode: false
|
25 | })
|
26 |
|
27 | this.incremetalMarkingStart = 0
|
28 | this.incremetalMarkingStartFound = false
|
29 |
|
30 |
|
31 | this.systemInfoReader = systemInfoReader
|
32 | this.clockOffset = null
|
33 |
|
34 |
|
35 |
|
36 | this.parser = parser()
|
37 | this.parser.on('data', (data) => this._process(data))
|
38 | this.systemInfoReader.on('error', (err) => this.destroy(err))
|
39 | }
|
40 |
|
41 | _process (traceEvent) {
|
42 | if (traceEvent.cat !== 'v8' || !gcEventNames.has(traceEvent.name)) {
|
43 | return
|
44 | }
|
45 |
|
46 |
|
47 |
|
48 |
|
49 |
|
50 |
|
51 |
|
52 |
|
53 |
|
54 |
|
55 |
|
56 |
|
57 |
|
58 | if (traceEvent.name === 'V8.GCIncrementalMarkingStart') {
|
59 | this.incremetalMarkingStart = traceEvent.ts
|
60 | this.incremetalMarkingStartFound = true
|
61 | } else if (this.incremetalMarkingStartFound &&
|
62 | traceEvent.name === 'V8.GCIncrementalMarkingFinalize') {
|
63 |
|
64 | } else if (this.incremetalMarkingStartFound &&
|
65 | traceEvent.name === 'V8.GCIncrementalMarking') {
|
66 |
|
67 | } else if (this.incremetalMarkingStartFound &&
|
68 | traceEvent.name === 'V8.GCFinalizeMC') {
|
69 | this.incremetalMarkingStartFound = false
|
70 |
|
71 | const starttime = this.incremetalMarkingStart
|
72 | const endtime = traceEvent.ts + traceEvent.dur
|
73 | this.push({
|
74 | pid: traceEvent.pid,
|
75 | tid: traceEvent.tid,
|
76 | ts: starttime,
|
77 | ph: 'X',
|
78 | cat: 'v8',
|
79 | name: 'V8.GCMarkSweepCompact',
|
80 | dur: endtime - starttime,
|
81 | args: {
|
82 | startTimestamp: (starttime * 1e-3) + this.clockOffset,
|
83 | endTimestamp: (endtime * 1e-3) + this.clockOffset
|
84 | }
|
85 | })
|
86 | } else {
|
87 |
|
88 | const endtime = traceEvent.ts + traceEvent.dur
|
89 | traceEvent.args = {
|
90 | startTimestamp: (traceEvent.ts * 1e-3) + this.clockOffset,
|
91 | endTimestamp: (endtime * 1e-3) + this.clockOffset
|
92 | }
|
93 | this.push(traceEvent)
|
94 | }
|
95 | }
|
96 |
|
97 | _transform (chunk, encoding, callback) {
|
98 | const self = this
|
99 | if (this.clockOffset === null) {
|
100 | this.systemInfoReader
|
101 | .pipe(endpoint({ objectMode: true }, function (err, data) {
|
102 | if (err) return
|
103 |
|
104 |
|
105 | const systemInfo = data[0]
|
106 | self.clockOffset = systemInfo.clockOffset
|
107 |
|
108 |
|
109 | self.parser.write(chunk, encoding)
|
110 | callback(null)
|
111 | }))
|
112 | } else {
|
113 |
|
114 | this.parser.write(chunk, encoding)
|
115 | callback(null)
|
116 | }
|
117 | }
|
118 |
|
119 | _flush (callback) {
|
120 | this.parser.end()
|
121 | callback(null)
|
122 | }
|
123 | }
|
124 | module.exports = TraceEventDecoder
|