From 7f92aea37118f39d742c98b5f86f0416ca1ff2fa Mon Sep 17 00:00:00 2001 From: Mike Armstrong Date: Tue, 15 Dec 2015 10:52:41 -0800 Subject: [PATCH] JSC Heap snapshot and capture Reviewed By: astreet Differential Revision: D2699681 fb-gh-sync-id: 81617187abec6d9bc1ffe3da02513c6875d0b93b --- .../src/main/jni/react/JSCExecutor.cpp | 3 + ReactAndroid/src/main/jni/react/JSCMemory.cpp | 157 ++++++++++++++++++ ReactAndroid/src/main/jni/react/JSCMemory.h | 11 ++ 3 files changed, 171 insertions(+) create mode 100644 ReactAndroid/src/main/jni/react/JSCMemory.cpp create mode 100644 ReactAndroid/src/main/jni/react/JSCMemory.h diff --git a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp index 8b954f156..e38e1a686 100644 --- a/ReactAndroid/src/main/jni/react/JSCExecutor.cpp +++ b/ReactAndroid/src/main/jni/react/JSCExecutor.cpp @@ -30,6 +30,7 @@ using fbsystrace::FbSystraceSection; // Add native performance markers support #include +#include #ifdef WITH_FB_JSC_TUNING #include @@ -132,6 +133,8 @@ JSCExecutor::JSCExecutor(FlushImmediateCallback cb) : addNativeProfilingHooks(m_context); addNativePerfLoggingHooks(m_context); #endif + + addNativeMemoryHooks(m_context); } JSCExecutor::~JSCExecutor() { diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.cpp b/ReactAndroid/src/main/jni/react/JSCMemory.cpp new file mode 100644 index 000000000..585fd64c4 --- /dev/null +++ b/ReactAndroid/src/main/jni/react/JSCMemory.cpp @@ -0,0 +1,157 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#include +#include +#include +#include +#include "JSCHelpers.h" + +#include "Value.h" + +#if WITH_FB_MEMORY_PROFILING + +static JSValueRef nativeEnableAllocationTag( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + + if (argumentCount < 1) { + if (exception) { + *exception = facebook::react::makeJSCException( + ctx, + "nativeEnableAllocationTag requires a single boolean argument"); + } + return JSValueMakeUndefined(ctx); + } + + JSEnableAllocationTag(ctx, JSValueToBoolean(ctx, arguments[0])); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeAllocationPushTag( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + std::string marker; + + if (argumentCount < 1) { + if (exception) { + *exception = facebook::react::makeJSCException( + ctx, + "nativeAllocationPushTag requires at least 1 argument"); + } + return JSValueMakeUndefined(ctx); + } + + JSStringRef tag = JSValueToStringCopy(ctx, arguments[0], exception); + JSPushAllocationTag(ctx, facebook::react::String::ref(tag).str().c_str()); + JSStringRelease(tag); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeAllocationPopTag( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + JSPopAllocationTag(ctx); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeForceSyncGC( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + JSSynchronousGarbageCollectForDebugging(ctx); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeCaptureStart( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + if (argumentCount < 1) { + if (exception) { + *exception = facebook::react::makeJSCException( + ctx, + "nativeCaptureStart requires at least 1 argument"); + } + return JSValueMakeUndefined(ctx); + } + + JSStringRef outputFilename = JSValueToStringCopy(ctx, arguments[0], exception); + std::string finalFilename = + std::string("/sdcard/") + + facebook::react::String::ref(outputFilename).str(); + JSHeapCaptureStart(ctx, finalFilename.c_str()); + JSStringRelease(outputFilename); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeCaptureEnd( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + JSHeapCaptureEnd(ctx); + return JSValueMakeUndefined(ctx); +} + +static JSValueRef nativeHeapDump( + JSContextRef ctx, + JSObjectRef function, + JSObjectRef thisObject, + size_t argumentCount, + const JSValueRef arguments[], + JSValueRef* exception) { + if (argumentCount < 1) { + if (exception) { + *exception = facebook::react::makeJSCException( + ctx, + "nativeHeapDump requires at least 1 argument"); + } + return JSValueMakeUndefined(ctx); + } + + JSStringRef outputFilename = JSValueToStringCopy(ctx, arguments[0], exception); + std::string finalFilename = + std::string("/sdcard/") + + facebook::react::String::ref(outputFilename).str(); + JSHeapDump(ctx, finalFilename.c_str()); + JSStringRelease(outputFilename); + return JSValueMakeUndefined(ctx); +} +#endif + +namespace facebook { +namespace react { + +void addNativeMemoryHooks(JSGlobalContextRef ctx) { +#if WITH_FB_MEMORY_PROFILING + installGlobalFunction(ctx, "nativeEnableAllocationTag", nativeEnableAllocationTag); + installGlobalFunction(ctx, "nativeAllocationPushTag", nativeAllocationPushTag); + installGlobalFunction(ctx, "nativeAllocationPopTag", nativeAllocationPopTag); + installGlobalFunction(ctx, "nativeForceSyncGC", nativeForceSyncGC); + installGlobalFunction(ctx, "nativeCaptureStart", nativeCaptureStart); + installGlobalFunction(ctx, "nativeCaptureEnd", nativeCaptureEnd); + installGlobalFunction(ctx, "nativeHeapDump", nativeHeapDump); +#endif +} + +} } diff --git a/ReactAndroid/src/main/jni/react/JSCMemory.h b/ReactAndroid/src/main/jni/react/JSCMemory.h new file mode 100644 index 000000000..6e05bba70 --- /dev/null +++ b/ReactAndroid/src/main/jni/react/JSCMemory.h @@ -0,0 +1,11 @@ +// Copyright 2004-present Facebook. All Rights Reserved. + +#pragma once + +#include +namespace facebook { +namespace react { + +void addNativeMemoryHooks(JSGlobalContextRef ctx); + +} }