Some perf tools for debugging js stalls

Summary:
The stall watchdog is handy to detect stalls, but it doesn't really tell us what was
happening. This diff makes it easy to track React perf and bridge traffic during any stall, and
prints it out if the stall exceeds the threshold.

Reviewed By: yungsters

Differential Revision: D4479439

fbshipit-source-id: 87f94913ec341a648d7744249597dc30b29759ab
This commit is contained in:
Spencer Ahrens
2017-02-06 17:39:15 -08:00
committed by Facebook Github Bot
parent 031cb2045d
commit 5d4d62f474
4 changed files with 132 additions and 8 deletions

View File

@@ -195,12 +195,14 @@ class MessageQueue {
}
Systrace.counterEvent('pending_js_to_native_queue', this._queue[0].length);
if (__DEV__ && this.__spy && isFinite(moduleID)) {
this.__spy(
{ type: TO_NATIVE,
module: this._remoteModuleTable[moduleID],
method: this._remoteMethodTable[moduleID][methodID],
args: params }
);
this.__spy(
{ type: TO_NATIVE,
module: this._remoteModuleTable[moduleID],
method: this._remoteMethodTable[moduleID][methodID],
args: params }
);
} else if (this.__spy) {
this.__spy({type: TO_NATIVE, module: moduleID + '', method: methodID, args: params});
}
}
@@ -225,7 +227,7 @@ class MessageQueue {
this._lastFlush = new Date().getTime();
this._eventLoopStartTime = this._lastFlush;
Systrace.beginEvent(`${module}.${method}()`);
if (__DEV__ && this.__spy) {
if (this.__spy) {
this.__spy({ type: TO_JS, module, method, args});
}
const moduleMethods = this._callableModules[module];
@@ -265,7 +267,7 @@ class MessageQueue {
);
}
const profileName = debug ? '<callback for ' + module + '.' + method + '>' : cbID;
if (callback && this.__spy && __DEV__) {
if (callback && this.__spy) {
this.__spy({ type: TO_JS, module:null, method:profileName, args });
}
Systrace.beginEvent(

View File

@@ -0,0 +1,59 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule BridgeSpyStallHandler
* @flow
*/
'use strict';
const JSEventLoopWatchdog = require('JSEventLoopWatchdog');
const MessageQueue = require('MessageQueue');
const infoLog = require('infoLog');
const BridgeSpyStallHandler = {
register: function() {
let spyBuffer = [];
MessageQueue.spy((data) => {
spyBuffer.push(data);
});
const TO_JS = 0;
JSEventLoopWatchdog.addHandler({
onStall: () => {
infoLog(
spyBuffer.length + ' bridge messages during stall: ',
spyBuffer.map((info) => {
let args = '<args>';
try {
args = JSON.stringify(info.args);
} catch (e1) {
if (Array.isArray(info.args)) {
args = info.args.map((arg) => {
try {
return JSON.stringify(arg);
} catch (e2) {
return '?';
}
});
} else {
args = 'keys:' + JSON.stringify(Object.keys(info.args));
}
}
return `${info.type === TO_JS ? 'N->JS' : 'JS->N'} : ` +
`${info.module ? (info.module + '.') : ''}${info.method}(${args})`;
}),
);
},
onIterate: () => {
spyBuffer = [];
},
});
},
};
module.exports = BridgeSpyStallHandler;

View File

@@ -0,0 +1,28 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule InteractionStallDebugger
* @flow
*/
'use strict';
const BridgeSpyStallHandler = require('BridgeSpyStallHandler');
const JSEventLoopWatchdog = require('JSEventLoopWatchdog');
const ReactPerfStallHandler = require('ReactPerfStallHandler');
const InteractionStallDebugger = {
install: function(options: {thresholdMS: number}) {
JSEventLoopWatchdog.install(options);
BridgeSpyStallHandler.register();
if (__DEV__) {
ReactPerfStallHandler.register();
}
},
};
module.exports = InteractionStallDebugger;

View File

@@ -0,0 +1,35 @@
/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*
* @providesModule ReactPerfStallHandler
* @flow
*/
'use strict';
const JSEventLoopWatchdog = require('JSEventLoopWatchdog');
const ReactPerf = require('ReactPerf');
const ReactPerfStallHandler = {
register: function() {
ReactPerf.start();
JSEventLoopWatchdog.addHandler({
onStall: () => {
ReactPerf.stop();
ReactPerf.printInclusive();
ReactPerf.printWasted();
ReactPerf.start();
},
onIterate: () => {
ReactPerf.stop();
ReactPerf.start();
},
});
},
};
module.exports = ReactPerfStallHandler;