#15 Add a button in devtools to start/stop the Sampling Profiler
Differential Revision: D3555704 fbshipit-source-id: 4add16c923fcfd306892efec4630c24ae438d6dd
This commit is contained in:
parent
e762d961cd
commit
ec0ccf599a
|
@ -27,6 +27,7 @@ const JSTimersExecution = require('JSTimersExecution');
|
|||
BatchedBridge.registerCallableModule('Systrace', Systrace);
|
||||
BatchedBridge.registerCallableModule('JSTimersExecution', JSTimersExecution);
|
||||
BatchedBridge.registerCallableModule('HeapCapture', require('HeapCapture'));
|
||||
BatchedBridge.registerCallableModule('SamplingProfiler', require('SamplingProfiler'));
|
||||
|
||||
if (__DEV__) {
|
||||
BatchedBridge.registerCallableModule('HMRClient', require('HMRClient'));
|
||||
|
|
|
@ -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 SamplingProfiler
|
||||
* @flow
|
||||
*/
|
||||
'use strict';
|
||||
|
||||
var SamplingProfiler = {
|
||||
poke: function (token: number): void {
|
||||
var error = null;
|
||||
var result = null;
|
||||
try {
|
||||
result = global.pokeSamplingProfiler();
|
||||
if (result === null) {
|
||||
console.log('The JSC Sampling Profiler has started');
|
||||
} else {
|
||||
console.log('The JSC Sampling Profiler has stopped');
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(
|
||||
'Error occured when restarting Sampling Profiler: ' + e.toString());
|
||||
error = e.toString();
|
||||
}
|
||||
require('NativeModules').JSCSamplingProfiler.operationComplete(
|
||||
token, result, error);
|
||||
},
|
||||
};
|
||||
|
||||
module.exports = SamplingProfiler;
|
|
@ -18,6 +18,7 @@ import com.facebook.react.bridge.NativeModule;
|
|||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.common.build.ReactBuildConfig;
|
||||
import com.facebook.react.devsupport.JSCHeapCapture;
|
||||
import com.facebook.react.devsupport.JSCSamplingProfiler;
|
||||
import com.facebook.react.modules.core.DefaultHardwareBackBtnHandler;
|
||||
import com.facebook.react.modules.core.DeviceEventManagerModule;
|
||||
import com.facebook.react.modules.core.ExceptionsManagerModule;
|
||||
|
@ -84,6 +85,7 @@ import com.facebook.systrace.Systrace;
|
|||
new Timing(catalystApplicationContext, mReactInstanceManager.getDevSupportManager()),
|
||||
new SourceCodeModule(mReactInstanceManager.getSourceUrl()),
|
||||
uiManagerModule,
|
||||
new JSCSamplingProfiler(catalystApplicationContext),
|
||||
new DebugComponentOwnershipModule(catalystApplicationContext)));
|
||||
|
||||
if (ReactBuildConfig.DEBUG) {
|
||||
|
@ -103,6 +105,7 @@ import com.facebook.systrace.Systrace;
|
|||
AppRegistry.class,
|
||||
com.facebook.react.bridge.Systrace.class,
|
||||
HMRClient.class,
|
||||
JSCSamplingProfiler.SamplingProfiler.class,
|
||||
DebugComponentOwnershipModule.RCTDebugComponentOwnership.class));
|
||||
|
||||
if (ReactBuildConfig.DEBUG) {
|
||||
|
|
|
@ -375,6 +375,26 @@ public class DevSupportManagerImpl implements DevSupportManager {
|
|||
JSCHeapUpload.captureCallback(mDevServerHelper.getHeapCaptureUploadUrl()));
|
||||
}
|
||||
});
|
||||
options.put(
|
||||
mApplicationContext.getString(R.string.catalyst_poke_sampling_profiler),
|
||||
new DevOptionHandler() {
|
||||
@Override
|
||||
public void onOptionSelected() {
|
||||
try {
|
||||
List<String> pokeResults = JSCSamplingProfiler.poke(60000);
|
||||
for (String result : pokeResults) {
|
||||
Toast.makeText(
|
||||
mCurrentContext,
|
||||
result == null
|
||||
? "Started JSC Sampling Profiler"
|
||||
: "Stopped JSC Sampling Profiler",
|
||||
Toast.LENGTH_LONG).show();
|
||||
}
|
||||
} catch (JSCSamplingProfiler.ProfilerException e) {
|
||||
showNewJavaError(e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
});
|
||||
options.put(
|
||||
mApplicationContext.getString(R.string.catalyst_settings), new DevOptionHandler() {
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,147 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
package com.facebook.react.devsupport;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
|
||||
import com.facebook.react.bridge.JavaScriptModule;
|
||||
import com.facebook.react.bridge.ReactApplicationContext;
|
||||
import com.facebook.react.bridge.ReactContextBaseJavaModule;
|
||||
import com.facebook.react.bridge.ReactMethod;
|
||||
|
||||
public class JSCSamplingProfiler extends ReactContextBaseJavaModule {
|
||||
public interface SamplingProfiler extends JavaScriptModule {
|
||||
void poke(int token);
|
||||
}
|
||||
|
||||
public static class ProfilerException extends Exception {
|
||||
ProfilerException(String message) {
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
|
||||
private @Nullable SamplingProfiler mSamplingProfiler;
|
||||
private boolean mOperationInProgress;
|
||||
private int mOperationToken;
|
||||
private @Nullable String mOperationError;
|
||||
private @Nullable String mSamplingProfilerResult;
|
||||
|
||||
private static final HashSet<JSCSamplingProfiler> sRegisteredDumpers =
|
||||
new HashSet<>();
|
||||
|
||||
private static synchronized void registerSamplingProfiler(
|
||||
JSCSamplingProfiler dumper) {
|
||||
if (sRegisteredDumpers.contains(dumper)) {
|
||||
throw new RuntimeException(
|
||||
"a JSCSamplingProfiler registered more than once");
|
||||
}
|
||||
sRegisteredDumpers.add(dumper);
|
||||
}
|
||||
|
||||
private static synchronized void unregisterSamplingProfiler(
|
||||
JSCSamplingProfiler dumper) {
|
||||
sRegisteredDumpers.remove(dumper);
|
||||
}
|
||||
|
||||
public static synchronized List<String> poke(long timeout)
|
||||
throws ProfilerException {
|
||||
LinkedList<String> results = new LinkedList<>();
|
||||
if (sRegisteredDumpers.isEmpty()) {
|
||||
throw new ProfilerException("No JSC registered");
|
||||
}
|
||||
|
||||
for (JSCSamplingProfiler dumper : sRegisteredDumpers) {
|
||||
dumper.pokeHelper(timeout);
|
||||
results.add(dumper.mSamplingProfilerResult);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
public JSCSamplingProfiler(ReactApplicationContext reactContext) {
|
||||
super(reactContext);
|
||||
mSamplingProfiler = null;
|
||||
mOperationInProgress = false;
|
||||
mOperationToken = 0;
|
||||
mOperationError = null;
|
||||
mSamplingProfilerResult = null;
|
||||
}
|
||||
|
||||
private synchronized void pokeHelper(long timeout) throws ProfilerException {
|
||||
if (mSamplingProfiler == null) {
|
||||
throw new ProfilerException("SamplingProfiler.js module not connected");
|
||||
}
|
||||
mSamplingProfiler.poke(getOperationToken());
|
||||
waitForOperation(timeout);
|
||||
}
|
||||
|
||||
private int getOperationToken() throws ProfilerException {
|
||||
if (mOperationInProgress) {
|
||||
throw new ProfilerException("Another operation already in progress.");
|
||||
}
|
||||
mOperationInProgress = true;
|
||||
return ++mOperationToken;
|
||||
}
|
||||
|
||||
private void waitForOperation(long timeout) throws ProfilerException {
|
||||
try {
|
||||
wait(timeout);
|
||||
} catch (InterruptedException e) {
|
||||
throw new ProfilerException(
|
||||
"Waiting for heap capture failed: " + e.getMessage());
|
||||
}
|
||||
|
||||
if (mOperationInProgress) {
|
||||
mOperationInProgress = false;
|
||||
throw new ProfilerException("heap capture timed out.");
|
||||
}
|
||||
|
||||
if (mOperationError != null) {
|
||||
throw new ProfilerException(mOperationError);
|
||||
}
|
||||
}
|
||||
|
||||
@ReactMethod
|
||||
public synchronized void operationComplete(
|
||||
int token, String result, String error) {
|
||||
if (token == mOperationToken) {
|
||||
mOperationInProgress = false;
|
||||
mSamplingProfilerResult = result;
|
||||
mOperationError = error;
|
||||
this.notify();
|
||||
} else {
|
||||
throw new RuntimeException("Completed operation is not in progress.");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "JSCSamplingProfiler";
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initialize() {
|
||||
super.initialize();
|
||||
mSamplingProfiler =
|
||||
getReactApplicationContext().getJSModule(SamplingProfiler.class);
|
||||
registerSamplingProfiler(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCatalystInstanceDestroy() {
|
||||
super.onCatalystInstanceDestroy();
|
||||
unregisterSamplingProfiler(this);
|
||||
mSamplingProfiler = null;
|
||||
}
|
||||
}
|
|
@ -20,6 +20,7 @@
|
|||
<string name="catalyst_heap_capture" project="catalyst" translatable="false">Capture Heap</string>
|
||||
<string name="catalyst_dismiss_button" project="catalyst" translatable="false">Dismiss\n(ESC)</string>
|
||||
<string name="catalyst_reload_button" project="catalyst" translatable="false">Reload\n(R,\u00A0R)</string>
|
||||
<string name="catalyst_poke_sampling_profiler" project="catalyst" translatable="false">Start/Stop Sampling Profiler</string>
|
||||
<string name="catalyst_copy_button" project="catalyst" translatable="false">Copy</string>
|
||||
<string name="catalyst_report_button" project="catalyst" translatable="false">Report</string>
|
||||
</resources>
|
||||
|
|
|
@ -4,13 +4,30 @@
|
|||
|
||||
#include "JSCSamplingProfiler.h"
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <JavaScriptCore/API/JSProfilerPrivate.h>
|
||||
#include "JSCHelpers.h"
|
||||
|
||||
#include "Value.h"
|
||||
|
||||
namespace facebook {
|
||||
namespace react {
|
||||
namespace {
|
||||
static JSValueRef pokeSamplingProfiler(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef function,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef* exception) {
|
||||
return JSPokeSamplingProfiler(ctx);
|
||||
}
|
||||
}
|
||||
|
||||
void initSamplingProfilerOnMainJSCThread(JSGlobalContextRef ctx) {
|
||||
JSStartSamplingProfilingOnMainJSCThread(ctx);
|
||||
installGlobalFunction(ctx, "pokeSamplingProfiler", pokeSamplingProfiler);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue