@parcel/workers 2.0.0-nightly.130 → 2.0.0-nightly.1303
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +23 -0
- package/lib/Handle.js +14 -45
- package/lib/Worker.js +100 -27
- package/lib/WorkerFarm.js +260 -104
- package/lib/bus.js +10 -2
- package/lib/child.js +129 -62
- package/lib/childState.js +1 -1
- package/lib/cpuCount.js +28 -7
- package/lib/index.js +41 -10
- package/lib/process/ProcessChild.js +22 -11
- package/lib/process/ProcessWorker.js +30 -19
- package/lib/threads/ThreadsChild.js +32 -14
- package/lib/threads/ThreadsWorker.js +28 -16
- package/package.json +19 -8
- package/src/Handle.js +10 -39
- package/src/Worker.js +82 -15
- package/src/WorkerFarm.js +219 -54
- package/src/bus.js +1 -1
- package/src/child.js +83 -24
- package/src/cpuCount.js +9 -4
- package/src/index.js +8 -2
- package/src/process/ProcessChild.js +2 -1
- package/src/process/ProcessWorker.js +1 -1
- package/src/threads/ThreadsWorker.js +2 -2
- package/test/cpuCount.test.js +1 -1
- package/test/integration/workerfarm/console.js +1 -1
- package/test/integration/workerfarm/logging.js +1 -1
- package/test/integration/workerfarm/reverse-handle.js +2 -2
- package/test/workerfarm.js +5 -5
- package/lib/Profiler.js +0 -70
- package/lib/Trace.js +0 -126
- package/src/Profiler.js +0 -93
- package/src/Trace.js +0 -121
package/src/child.js
CHANGED
@@ -9,16 +9,20 @@ import type {
|
|
9
9
|
WorkerResponse,
|
10
10
|
ChildImpl,
|
11
11
|
} from './types';
|
12
|
-
import type {IDisposable} from '@parcel/types';
|
13
|
-
import type {
|
12
|
+
import type {Async, IDisposable} from '@parcel/types';
|
13
|
+
import type {SharedReference} from './WorkerFarm';
|
14
14
|
|
15
15
|
import invariant from 'assert';
|
16
16
|
import nullthrows from 'nullthrows';
|
17
17
|
import Logger, {patchConsole, unpatchConsole} from '@parcel/logger';
|
18
18
|
import ThrowableDiagnostic, {anyToDiagnostic} from '@parcel/diagnostic';
|
19
|
+
import {deserialize} from '@parcel/core';
|
19
20
|
import bus from './bus';
|
20
|
-
import
|
21
|
-
import
|
21
|
+
import {SamplingProfiler, tracer} from '@parcel/profiler';
|
22
|
+
import _Handle from './Handle';
|
23
|
+
|
24
|
+
// The import of './Handle' should really be imported eagerly (with @babel/plugin-transform-modules-commonjs's lazy mode).
|
25
|
+
const Handle = _Handle;
|
22
26
|
|
23
27
|
type ChildCall = WorkerRequest & {|
|
24
28
|
resolve: (result: Promise<any> | any) => void,
|
@@ -30,20 +34,22 @@ export class Child {
|
|
30
34
|
childId: ?number;
|
31
35
|
maxConcurrentCalls: number = 10;
|
32
36
|
module: ?any;
|
33
|
-
responseId = 0;
|
37
|
+
responseId: number = 0;
|
34
38
|
responseQueue: Map<number, ChildCall> = new Map();
|
35
39
|
loggerDisposable: IDisposable;
|
40
|
+
tracerDisposable: IDisposable;
|
36
41
|
child: ChildImpl;
|
37
|
-
profiler: ?
|
38
|
-
workerApi: WorkerApi;
|
42
|
+
profiler: ?SamplingProfiler;
|
39
43
|
handles: Map<number, Handle> = new Map();
|
40
|
-
sharedReferences: Map<
|
41
|
-
sharedReferencesByValue: Map<mixed,
|
44
|
+
sharedReferences: Map<SharedReference, mixed> = new Map();
|
45
|
+
sharedReferencesByValue: Map<mixed, SharedReference> = new Map();
|
42
46
|
|
43
47
|
constructor(ChildBackend: Class<ChildImpl>) {
|
44
48
|
this.child = new ChildBackend(
|
45
|
-
|
46
|
-
|
49
|
+
m => {
|
50
|
+
this.messageListener(m);
|
51
|
+
},
|
52
|
+
() => this.handleEnd(),
|
47
53
|
);
|
48
54
|
|
49
55
|
// Monitior all logging events inside this child process and forward to
|
@@ -51,21 +57,37 @@ export class Child {
|
|
51
57
|
this.loggerDisposable = Logger.onLog(event => {
|
52
58
|
bus.emit('logEvent', event);
|
53
59
|
});
|
60
|
+
// .. and do the same for trace events
|
61
|
+
this.tracerDisposable = tracer.onTrace(event => {
|
62
|
+
bus.emit('traceEvent', event);
|
63
|
+
});
|
54
64
|
}
|
55
65
|
|
56
|
-
workerApi
|
66
|
+
workerApi: {|
|
67
|
+
callMaster: (
|
68
|
+
request: CallRequest,
|
69
|
+
awaitResponse?: ?boolean,
|
70
|
+
) => Promise<mixed>,
|
71
|
+
createReverseHandle: (fn: (...args: Array<any>) => mixed) => Handle,
|
72
|
+
getSharedReference: (ref: SharedReference) => mixed,
|
73
|
+
resolveSharedReference: (value: mixed) => void | SharedReference,
|
74
|
+
runHandle: (handle: Handle, args: Array<any>) => Promise<mixed>,
|
75
|
+
|} = {
|
57
76
|
callMaster: (
|
58
77
|
request: CallRequest,
|
59
78
|
awaitResponse: ?boolean = true,
|
60
79
|
): Promise<mixed> => this.addCall(request, awaitResponse),
|
61
80
|
createReverseHandle: (fn: (...args: Array<any>) => mixed): Handle =>
|
62
81
|
this.createReverseHandle(fn),
|
63
|
-
|
82
|
+
runHandle: (handle: Handle, args: Array<any>): Promise<mixed> =>
|
83
|
+
this.workerApi.callMaster({handle: handle.id, args}, true),
|
84
|
+
getSharedReference: (ref: SharedReference) =>
|
85
|
+
this.sharedReferences.get(ref),
|
64
86
|
resolveSharedReference: (value: mixed) =>
|
65
87
|
this.sharedReferencesByValue.get(value),
|
66
88
|
};
|
67
89
|
|
68
|
-
messageListener(message: WorkerMessage):
|
90
|
+
messageListener(message: WorkerMessage): Async<void> {
|
69
91
|
if (message.type === 'response') {
|
70
92
|
return this.handleResponse(message);
|
71
93
|
} else if (message.type === 'request') {
|
@@ -77,10 +99,14 @@ export class Child {
|
|
77
99
|
this.child.send(data);
|
78
100
|
}
|
79
101
|
|
80
|
-
childInit(module: string, childId: number): void {
|
102
|
+
async childInit(module: string, childId: number): Promise<void> {
|
81
103
|
// $FlowFixMe this must be dynamic
|
82
104
|
this.module = require(module);
|
83
105
|
this.childId = childId;
|
106
|
+
|
107
|
+
if (this.module.childInit != null) {
|
108
|
+
await this.module.childInit();
|
109
|
+
}
|
84
110
|
}
|
85
111
|
|
86
112
|
async handleRequest(data: WorkerRequest): Promise<void> {
|
@@ -106,7 +132,7 @@ export class Child {
|
|
106
132
|
let result;
|
107
133
|
if (handleId != null) {
|
108
134
|
try {
|
109
|
-
let fn = nullthrows(this.handles.get(handleId))
|
135
|
+
let fn = nullthrows(this.handles.get(handleId)?.fn);
|
110
136
|
result = responseFromContent(fn(...args));
|
111
137
|
} catch (e) {
|
112
138
|
result = errorResponseFromError(e);
|
@@ -114,18 +140,22 @@ export class Child {
|
|
114
140
|
} else if (method === 'childInit') {
|
115
141
|
try {
|
116
142
|
let [moduleName, childOptions] = args;
|
117
|
-
if (childOptions.
|
143
|
+
if (childOptions.shouldPatchConsole) {
|
118
144
|
patchConsole();
|
119
145
|
} else {
|
120
146
|
unpatchConsole();
|
121
147
|
}
|
122
148
|
|
123
|
-
|
149
|
+
if (childOptions.shouldTrace) {
|
150
|
+
tracer.enable();
|
151
|
+
}
|
152
|
+
|
153
|
+
result = responseFromContent(await this.childInit(moduleName, child));
|
124
154
|
} catch (e) {
|
125
155
|
result = errorResponseFromError(e);
|
126
156
|
}
|
127
157
|
} else if (method === 'startProfile') {
|
128
|
-
this.profiler = new
|
158
|
+
this.profiler = new SamplingProfiler();
|
129
159
|
try {
|
130
160
|
result = responseFromContent(await this.profiler.startProfiling());
|
131
161
|
} catch (e) {
|
@@ -138,13 +168,37 @@ export class Child {
|
|
138
168
|
} catch (e) {
|
139
169
|
result = errorResponseFromError(e);
|
140
170
|
}
|
171
|
+
} else if (method === 'takeHeapSnapshot') {
|
172
|
+
try {
|
173
|
+
let v8 = require('v8');
|
174
|
+
result = responseFromContent(
|
175
|
+
v8.writeHeapSnapshot(
|
176
|
+
'heap-' +
|
177
|
+
args[0] +
|
178
|
+
'-' +
|
179
|
+
(this.childId ? 'worker' + this.childId : 'main') +
|
180
|
+
'.heapsnapshot',
|
181
|
+
),
|
182
|
+
);
|
183
|
+
} catch (e) {
|
184
|
+
result = errorResponseFromError(e);
|
185
|
+
}
|
141
186
|
} else if (method === 'createSharedReference') {
|
142
|
-
let [ref,
|
187
|
+
let [ref, _value] = args;
|
188
|
+
let value =
|
189
|
+
_value instanceof ArrayBuffer
|
190
|
+
? // In the case the value is pre-serialized as a buffer,
|
191
|
+
// deserialize it.
|
192
|
+
deserialize(Buffer.from(_value))
|
193
|
+
: _value;
|
143
194
|
this.sharedReferences.set(ref, value);
|
144
195
|
this.sharedReferencesByValue.set(value, ref);
|
145
196
|
result = responseFromContent(null);
|
146
197
|
} else if (method === 'deleteSharedReference') {
|
147
|
-
|
198
|
+
let ref = args[0];
|
199
|
+
let value = this.sharedReferences.get(ref);
|
200
|
+
this.sharedReferencesByValue.delete(value);
|
201
|
+
this.sharedReferences.delete(ref);
|
148
202
|
result = responseFromContent(null);
|
149
203
|
} else {
|
150
204
|
try {
|
@@ -157,7 +211,11 @@ export class Child {
|
|
157
211
|
}
|
158
212
|
}
|
159
213
|
|
160
|
-
|
214
|
+
try {
|
215
|
+
this.send(result);
|
216
|
+
} catch (e) {
|
217
|
+
result = this.send(errorResponseFromError(e));
|
218
|
+
}
|
161
219
|
}
|
162
220
|
|
163
221
|
handleResponse(data: WorkerResponse): void {
|
@@ -189,6 +247,7 @@ export class Child {
|
|
189
247
|
...request,
|
190
248
|
type: 'request',
|
191
249
|
child: this.childId,
|
250
|
+
// $FlowFixMe Added in Flow 0.121.0 upgrade in #4381
|
192
251
|
awaitResponse,
|
193
252
|
resolve: () => {},
|
194
253
|
reject: () => {},
|
@@ -239,12 +298,12 @@ export class Child {
|
|
239
298
|
|
240
299
|
handleEnd(): void {
|
241
300
|
this.loggerDisposable.dispose();
|
301
|
+
this.tracerDisposable.dispose();
|
242
302
|
}
|
243
303
|
|
244
|
-
createReverseHandle(fn: (...args: Array<any>) => mixed) {
|
304
|
+
createReverseHandle(fn: (...args: Array<any>) => mixed): Handle {
|
245
305
|
let handle = new Handle({
|
246
306
|
fn,
|
247
|
-
workerApi: this.workerApi,
|
248
307
|
childId: this.childId,
|
249
308
|
});
|
250
309
|
this.handles.set(handle.id, handle);
|
package/src/cpuCount.js
CHANGED
@@ -26,6 +26,11 @@ export function detectRealCores(): number {
|
|
26
26
|
);
|
27
27
|
} else if (platform === 'darwin') {
|
28
28
|
amount = parseInt(exec('sysctl -n hw.physicalcpu_max'), 10);
|
29
|
+
} else if (platform === 'win32') {
|
30
|
+
const str = exec('wmic cpu get NumberOfCores').match(/\d+/g);
|
31
|
+
if (str !== null) {
|
32
|
+
amount = parseInt(str.filter(n => n !== '')[0], 10);
|
33
|
+
}
|
29
34
|
}
|
30
35
|
|
31
36
|
if (!amount || amount <= 0) {
|
@@ -36,9 +41,8 @@ export function detectRealCores(): number {
|
|
36
41
|
}
|
37
42
|
|
38
43
|
let cores;
|
39
|
-
export default function getCores(bypassCache?: boolean = false) {
|
44
|
+
export default function getCores(bypassCache?: boolean = false): number {
|
40
45
|
// Do not re-run commands if we already have the count...
|
41
|
-
// $FlowFixMe
|
42
46
|
if (cores && !bypassCache) {
|
43
47
|
return cores;
|
44
48
|
}
|
@@ -49,8 +53,9 @@ export default function getCores(bypassCache?: boolean = false) {
|
|
49
53
|
// Guess the amount of real cores
|
50
54
|
cores = os
|
51
55
|
.cpus()
|
52
|
-
.filter(
|
53
|
-
|
56
|
+
.filter(
|
57
|
+
(cpu, index) => !cpu.model.includes('Intel') || index % 2 === 1,
|
58
|
+
).length;
|
54
59
|
}
|
55
60
|
|
56
61
|
// Another fallback
|
package/src/index.js
CHANGED
@@ -1,9 +1,10 @@
|
|
1
1
|
// @flow
|
2
|
-
import type {LogEvent} from '@parcel/types';
|
2
|
+
import type {TraceEvent, LogEvent} from '@parcel/types';
|
3
3
|
import invariant from 'assert';
|
4
4
|
import WorkerFarm from './WorkerFarm';
|
5
5
|
import Logger from '@parcel/logger';
|
6
6
|
import bus from './bus';
|
7
|
+
import {tracer} from '@parcel/profiler';
|
7
8
|
|
8
9
|
if (!WorkerFarm.isWorker()) {
|
9
10
|
// Forward all logger events originating from workers into the main process
|
@@ -29,9 +30,14 @@ if (!WorkerFarm.isWorker()) {
|
|
29
30
|
throw new Error('Unknown log level');
|
30
31
|
}
|
31
32
|
});
|
33
|
+
|
34
|
+
// Forward all trace events originating from workers into the main process
|
35
|
+
bus.on('traceEvent', (e: TraceEvent) => {
|
36
|
+
tracer.trace(e);
|
37
|
+
});
|
32
38
|
}
|
33
39
|
|
34
40
|
export default WorkerFarm;
|
35
41
|
export {bus};
|
36
42
|
export {Handle} from './WorkerFarm';
|
37
|
-
export type {WorkerApi, FarmOptions} from './WorkerFarm';
|
43
|
+
export type {WorkerApi, FarmOptions, SharedReference} from './WorkerFarm';
|
@@ -25,7 +25,7 @@ export default class ProcessChild implements ChildImpl {
|
|
25
25
|
process.on('message', data => this.handleMessage(data));
|
26
26
|
}
|
27
27
|
|
28
|
-
handleMessage(data: string) {
|
28
|
+
handleMessage(data: string): void {
|
29
29
|
if (data === 'die') {
|
30
30
|
return this.stop();
|
31
31
|
}
|
@@ -37,6 +37,7 @@ export default class ProcessChild implements ChildImpl {
|
|
37
37
|
let processSend = nullthrows(process.send).bind(process);
|
38
38
|
processSend(serialize(data).toString('base64'), err => {
|
39
39
|
if (err && err instanceof Error) {
|
40
|
+
// $FlowFixMe[prop-missing]
|
40
41
|
if (err.code === 'ERR_IPC_CHANNEL_CLOSED') {
|
41
42
|
// IPC connection closed
|
42
43
|
// no need to keep the worker running if it can't send or receive data
|
@@ -32,7 +32,7 @@ export default class ThreadsWorker implements WorkerImpl {
|
|
32
32
|
this.onExit = onExit;
|
33
33
|
}
|
34
34
|
|
35
|
-
start() {
|
35
|
+
start(): Promise<void> {
|
36
36
|
this.worker = new Worker(WORKER_PATH, {
|
37
37
|
execArgv: this.execArgv,
|
38
38
|
env: process.env,
|
@@ -47,7 +47,7 @@ export default class ThreadsWorker implements WorkerImpl {
|
|
47
47
|
});
|
48
48
|
}
|
49
49
|
|
50
|
-
stop() {
|
50
|
+
stop(): Promise<void> {
|
51
51
|
// In node 12, this returns a promise, but previously it accepted a callback
|
52
52
|
// TODO: Pass a callback in earlier versions of Node
|
53
53
|
return Promise.resolve(this.worker.terminate());
|
package/test/cpuCount.test.js
CHANGED
@@ -3,7 +3,7 @@ import os from 'os';
|
|
3
3
|
|
4
4
|
import getCores, {detectRealCores} from '../src/cpuCount';
|
5
5
|
|
6
|
-
describe('cpuCount', function() {
|
6
|
+
describe('cpuCount', function () {
|
7
7
|
it('Should be able to detect real cpu count', () => {
|
8
8
|
// Windows not supported as getting the cpu count takes a couple seconds...
|
9
9
|
if (os.platform() === 'win32') return;
|
package/test/workerfarm.js
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
import Logger from '@parcel/logger';
|
2
2
|
import assert from 'assert';
|
3
|
-
import WorkerFarm from '../';
|
3
|
+
import WorkerFarm from '../src';
|
4
4
|
|
5
|
-
describe('WorkerFarm', function() {
|
5
|
+
describe('WorkerFarm', function () {
|
6
6
|
this.timeout(30000);
|
7
7
|
|
8
8
|
it('Should start up workers', async () => {
|
@@ -132,7 +132,7 @@ describe('WorkerFarm', function() {
|
|
132
132
|
await workerfarm.end();
|
133
133
|
});
|
134
134
|
|
135
|
-
it('Forwards stdio from the child process and levels event source if
|
135
|
+
it('Forwards stdio from the child process and levels event source if shouldPatchConsole is true', async () => {
|
136
136
|
let events = [];
|
137
137
|
let logDisposable = Logger.onLog(event => events.push(event));
|
138
138
|
|
@@ -140,7 +140,7 @@ describe('WorkerFarm', function() {
|
|
140
140
|
warmWorkers: true,
|
141
141
|
useLocalWorker: false,
|
142
142
|
workerPath: require.resolve('./integration/workerfarm/console.js'),
|
143
|
-
|
143
|
+
shouldPatchConsole: true,
|
144
144
|
});
|
145
145
|
|
146
146
|
await workerfarm.run();
|
@@ -291,7 +291,7 @@ describe('WorkerFarm', function() {
|
|
291
291
|
assert.equal(result, 'Shared reference does not exist');
|
292
292
|
});
|
293
293
|
|
294
|
-
it('
|
294
|
+
it('Should resolve shared references in workers', async () => {
|
295
295
|
let workerfarm = new WorkerFarm({
|
296
296
|
warmWorkers: true,
|
297
297
|
useLocalWorker: false,
|
package/lib/Profiler.js
DELETED
@@ -1,70 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
4
|
-
value: true
|
5
|
-
});
|
6
|
-
exports.default = void 0;
|
7
|
-
|
8
|
-
var _assert = _interopRequireDefault(require("assert"));
|
9
|
-
|
10
|
-
var _diagnostic = _interopRequireDefault(require("@parcel/diagnostic"));
|
11
|
-
|
12
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
13
|
-
|
14
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
15
|
-
|
16
|
-
class Profiler {
|
17
|
-
constructor() {
|
18
|
-
_defineProperty(this, "session", void 0);
|
19
|
-
}
|
20
|
-
|
21
|
-
startProfiling() {
|
22
|
-
let inspector;
|
23
|
-
|
24
|
-
try {
|
25
|
-
inspector = require('inspector');
|
26
|
-
} catch (err) {
|
27
|
-
throw new _diagnostic.default({
|
28
|
-
diagnostic: {
|
29
|
-
message: `The inspector module isn't available`,
|
30
|
-
origin: '@parcel/workers',
|
31
|
-
hints: ['Disable build profiling']
|
32
|
-
}
|
33
|
-
});
|
34
|
-
}
|
35
|
-
|
36
|
-
this.session = new inspector.Session();
|
37
|
-
this.session.connect();
|
38
|
-
return Promise.all([this.sendCommand('Profiler.setSamplingInterval', {
|
39
|
-
interval: 100
|
40
|
-
}), this.sendCommand('Profiler.enable'), this.sendCommand('Profiler.start')]);
|
41
|
-
}
|
42
|
-
|
43
|
-
sendCommand(method, params) {
|
44
|
-
(0, _assert.default)(this.session != null);
|
45
|
-
return new Promise((resolve, reject) => {
|
46
|
-
this.session.post(method, params, (err, params) => {
|
47
|
-
if (err == null) {
|
48
|
-
resolve(params);
|
49
|
-
} else {
|
50
|
-
reject(err);
|
51
|
-
}
|
52
|
-
});
|
53
|
-
});
|
54
|
-
}
|
55
|
-
|
56
|
-
destroy() {
|
57
|
-
if (this.session != null) {
|
58
|
-
this.session.disconnect();
|
59
|
-
}
|
60
|
-
}
|
61
|
-
|
62
|
-
async stopProfiling() {
|
63
|
-
let res = await this.sendCommand('Profiler.stop');
|
64
|
-
this.destroy();
|
65
|
-
return res.profile;
|
66
|
-
}
|
67
|
-
|
68
|
-
}
|
69
|
-
|
70
|
-
exports.default = Profiler;
|
package/lib/Trace.js
DELETED
@@ -1,126 +0,0 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
Object.defineProperty(exports, "__esModule", {
|
4
|
-
value: true
|
5
|
-
});
|
6
|
-
exports.default = void 0;
|
7
|
-
|
8
|
-
var _chromeTraceEvent = require("chrome-trace-event");
|
9
|
-
|
10
|
-
function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; }
|
11
|
-
|
12
|
-
class Trace {
|
13
|
-
constructor() {
|
14
|
-
_defineProperty(this, "tracer", void 0);
|
15
|
-
|
16
|
-
_defineProperty(this, "tid", void 0);
|
17
|
-
|
18
|
-
_defineProperty(this, "eventId", void 0);
|
19
|
-
|
20
|
-
this.tracer = new _chromeTraceEvent.Tracer();
|
21
|
-
this.tid = 0;
|
22
|
-
this.eventId = 0;
|
23
|
-
this.init();
|
24
|
-
}
|
25
|
-
|
26
|
-
getEventId() {
|
27
|
-
return this.eventId++;
|
28
|
-
}
|
29
|
-
|
30
|
-
init() {
|
31
|
-
this.tracer.instantEvent({
|
32
|
-
name: 'TracingStartedInPage',
|
33
|
-
id: this.getEventId(),
|
34
|
-
cat: ['disabled-by-default-devtools.timeline'],
|
35
|
-
args: {
|
36
|
-
data: {
|
37
|
-
sessionId: '-1',
|
38
|
-
page: '0xfff',
|
39
|
-
frames: [{
|
40
|
-
frame: '0xfff',
|
41
|
-
url: 'parcel',
|
42
|
-
name: ''
|
43
|
-
}]
|
44
|
-
}
|
45
|
-
}
|
46
|
-
});
|
47
|
-
this.tracer.instantEvent({
|
48
|
-
name: 'TracingStartedInBrowser',
|
49
|
-
id: this.getEventId(),
|
50
|
-
cat: ['disabled-by-default-devtools.timeline'],
|
51
|
-
args: {
|
52
|
-
data: {
|
53
|
-
sessionId: '-1'
|
54
|
-
}
|
55
|
-
}
|
56
|
-
});
|
57
|
-
}
|
58
|
-
|
59
|
-
addCPUProfile(name, profile) {
|
60
|
-
const trace = this.tracer;
|
61
|
-
const tid = this.tid;
|
62
|
-
this.tid++;
|
63
|
-
const cpuStartTime = profile.startTime;
|
64
|
-
const cpuEndTime = profile.endTime;
|
65
|
-
trace.instantEvent({
|
66
|
-
tid,
|
67
|
-
id: this.getEventId(),
|
68
|
-
cat: ['toplevel'],
|
69
|
-
name: 'TaskQueueManager::ProcessTaskFromWorkQueue',
|
70
|
-
args: {
|
71
|
-
src_file: '../../ipc/ipc_moji_bootstrap.cc',
|
72
|
-
src_func: 'Accept'
|
73
|
-
},
|
74
|
-
ts: cpuStartTime
|
75
|
-
});
|
76
|
-
trace.completeEvent({
|
77
|
-
tid,
|
78
|
-
name: 'EvaluateScript',
|
79
|
-
id: this.getEventId(),
|
80
|
-
cat: ['devtools.timeline'],
|
81
|
-
ts: cpuStartTime,
|
82
|
-
dur: cpuEndTime - cpuStartTime,
|
83
|
-
args: {
|
84
|
-
data: {
|
85
|
-
url: 'parcel',
|
86
|
-
lineNumber: 1,
|
87
|
-
columnNumber: 1,
|
88
|
-
frame: '0xFFF'
|
89
|
-
}
|
90
|
-
}
|
91
|
-
});
|
92
|
-
trace.instantEvent({
|
93
|
-
tid,
|
94
|
-
ts: 0,
|
95
|
-
ph: 'M',
|
96
|
-
cat: ['__metadata'],
|
97
|
-
name: 'thread_name',
|
98
|
-
args: {
|
99
|
-
name
|
100
|
-
}
|
101
|
-
});
|
102
|
-
trace.instantEvent({
|
103
|
-
tid,
|
104
|
-
name: 'CpuProfile',
|
105
|
-
id: this.getEventId(),
|
106
|
-
cat: ['disabled-by-default-devtools.timeline'],
|
107
|
-
ts: cpuEndTime,
|
108
|
-
args: {
|
109
|
-
data: {
|
110
|
-
cpuProfile: profile
|
111
|
-
}
|
112
|
-
}
|
113
|
-
});
|
114
|
-
}
|
115
|
-
|
116
|
-
pipe(writable) {
|
117
|
-
return this.tracer.pipe(writable);
|
118
|
-
}
|
119
|
-
|
120
|
-
flush() {
|
121
|
-
this.tracer.push(null);
|
122
|
-
}
|
123
|
-
|
124
|
-
}
|
125
|
-
|
126
|
-
exports.default = Trace;
|
package/src/Profiler.js
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
// @flow
|
2
|
-
import type {Session} from 'inspector';
|
3
|
-
import invariant from 'assert';
|
4
|
-
import ThrowableDiagnostic from '@parcel/diagnostic';
|
5
|
-
|
6
|
-
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-Profile
|
7
|
-
export type Profile = {|
|
8
|
-
nodes: Array<ProfileNode>,
|
9
|
-
startTime: number,
|
10
|
-
endTime: number,
|
11
|
-
samples?: Array<number>,
|
12
|
-
timeDeltas?: Array<number>,
|
13
|
-
|};
|
14
|
-
|
15
|
-
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-ProfileNode
|
16
|
-
type ProfileNode = {|
|
17
|
-
id: number,
|
18
|
-
callFrame: CallFrame,
|
19
|
-
hitCount?: number,
|
20
|
-
children?: Array<number>,
|
21
|
-
deoptReason?: string,
|
22
|
-
positionTicks?: PositionTickInfo,
|
23
|
-
|};
|
24
|
-
|
25
|
-
// https://chromedevtools.github.io/devtools-protocol/tot/Runtime#type-CallFrame
|
26
|
-
type CallFrame = {|
|
27
|
-
functionName: string,
|
28
|
-
scriptId: string,
|
29
|
-
url: string,
|
30
|
-
lineNumber: string,
|
31
|
-
columnNumber: string,
|
32
|
-
|};
|
33
|
-
|
34
|
-
// https://chromedevtools.github.io/devtools-protocol/tot/Profiler#type-PositionTickInfo
|
35
|
-
type PositionTickInfo = {|
|
36
|
-
line: number,
|
37
|
-
ticks: number,
|
38
|
-
|};
|
39
|
-
|
40
|
-
export default class Profiler {
|
41
|
-
session: Session;
|
42
|
-
|
43
|
-
startProfiling() {
|
44
|
-
let inspector;
|
45
|
-
try {
|
46
|
-
inspector = require('inspector');
|
47
|
-
} catch (err) {
|
48
|
-
throw new ThrowableDiagnostic({
|
49
|
-
diagnostic: {
|
50
|
-
message: `The inspector module isn't available`,
|
51
|
-
origin: '@parcel/workers',
|
52
|
-
hints: ['Disable build profiling'],
|
53
|
-
},
|
54
|
-
});
|
55
|
-
}
|
56
|
-
|
57
|
-
this.session = new inspector.Session();
|
58
|
-
this.session.connect();
|
59
|
-
|
60
|
-
return Promise.all([
|
61
|
-
this.sendCommand('Profiler.setSamplingInterval', {
|
62
|
-
interval: 100,
|
63
|
-
}),
|
64
|
-
this.sendCommand('Profiler.enable'),
|
65
|
-
this.sendCommand('Profiler.start'),
|
66
|
-
]);
|
67
|
-
}
|
68
|
-
|
69
|
-
sendCommand(method: string, params: mixed): Promise<{profile: Profile, ...}> {
|
70
|
-
invariant(this.session != null);
|
71
|
-
return new Promise((resolve, reject) => {
|
72
|
-
this.session.post(method, params, (err, params) => {
|
73
|
-
if (err == null) {
|
74
|
-
resolve(params);
|
75
|
-
} else {
|
76
|
-
reject(err);
|
77
|
-
}
|
78
|
-
});
|
79
|
-
});
|
80
|
-
}
|
81
|
-
|
82
|
-
destroy() {
|
83
|
-
if (this.session != null) {
|
84
|
-
this.session.disconnect();
|
85
|
-
}
|
86
|
-
}
|
87
|
-
|
88
|
-
async stopProfiling(): Promise<Profile> {
|
89
|
-
let res = await this.sendCommand('Profiler.stop');
|
90
|
-
this.destroy();
|
91
|
-
return res.profile;
|
92
|
-
}
|
93
|
-
}
|