[ReactNative] Add JavaScriptCore legacy profiler
This commit is contained in:
Родитель
5db42643cf
Коммит
72f7a1be6f
|
@ -0,0 +1,25 @@
|
|||
// Copyright 2004-present Facebook. All Rights Reserved.
|
||||
|
||||
#pragma once
|
||||
|
||||
#import "JSContextRef.h"
|
||||
|
||||
extern "C" {
|
||||
|
||||
JSValueRef nativeProfilerStart(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef function,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception);
|
||||
|
||||
JSValueRef nativeProfilerEnd(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef function,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception);
|
||||
|
||||
}
|
|
@ -0,0 +1,161 @@
|
|||
//#include "config.h"
|
||||
|
||||
#include "JSCLegacyProfiler.h"
|
||||
|
||||
#include "APICast.h"
|
||||
#include "LegacyProfiler.h"
|
||||
#include "OpaqueJSString.h"
|
||||
#include "JSProfilerPrivate.h"
|
||||
#include "JSStringRef.h"
|
||||
|
||||
#include <yajl/yajl_gen.h>
|
||||
|
||||
#define GEN_AND_CHECK(expr) \
|
||||
do { \
|
||||
yajl_gen_status GEN_AND_CHECK_status = (expr); \
|
||||
if (GEN_AND_CHECK_status != yajl_gen_status_ok) { \
|
||||
return GEN_AND_CHECK_status; \
|
||||
} \
|
||||
} while (false)
|
||||
|
||||
static inline yajl_gen_status yajl_gen_cstring(yajl_gen gen, const char *str) {
|
||||
return yajl_gen_string(gen, (const unsigned char*)str, strlen(str));
|
||||
}
|
||||
|
||||
static yajl_gen_status append_children_array_json(yajl_gen gen, const JSC::ProfileNode *node);
|
||||
static yajl_gen_status append_node_json(yajl_gen gen, const JSC::ProfileNode *node);
|
||||
|
||||
static yajl_gen_status append_root_json(yajl_gen gen, const JSC::Profile *profile) {
|
||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "rootNodes"));
|
||||
GEN_AND_CHECK(append_children_array_json(gen, profile->head()));
|
||||
GEN_AND_CHECK(yajl_gen_map_close(gen));
|
||||
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static yajl_gen_status append_children_array_json(yajl_gen gen, const JSC::ProfileNode *node) {
|
||||
GEN_AND_CHECK(yajl_gen_array_open(gen));
|
||||
for (RefPtr<JSC::ProfileNode> child : node->children()) {
|
||||
GEN_AND_CHECK(append_node_json(gen, child.get()));
|
||||
}
|
||||
GEN_AND_CHECK(yajl_gen_array_close(gen));
|
||||
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static yajl_gen_status append_node_json(yajl_gen gen, const JSC::ProfileNode *node) {
|
||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "id"));
|
||||
GEN_AND_CHECK(yajl_gen_integer(gen, node->id()));
|
||||
|
||||
if (!node->functionName().isEmpty()) {
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "functionName"));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, node->functionName().utf8().data()));
|
||||
}
|
||||
|
||||
if (!node->url().isEmpty()) {
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "url"));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, node->url().utf8().data()));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "lineNumber"));
|
||||
GEN_AND_CHECK(yajl_gen_integer(gen, node->lineNumber()));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "columnNumber"));
|
||||
GEN_AND_CHECK(yajl_gen_integer(gen, node->columnNumber()));
|
||||
}
|
||||
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "calls"));
|
||||
GEN_AND_CHECK(yajl_gen_array_open(gen));
|
||||
for (const JSC::ProfileNode::Call &call : node->calls()) {
|
||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "startTime"));
|
||||
GEN_AND_CHECK(yajl_gen_double(gen, call.startTime()));
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "totalTime"));
|
||||
GEN_AND_CHECK(yajl_gen_double(gen, call.totalTime()));
|
||||
GEN_AND_CHECK(yajl_gen_map_close(gen));
|
||||
}
|
||||
GEN_AND_CHECK(yajl_gen_array_close(gen));
|
||||
|
||||
if (!node->children().isEmpty()) {
|
||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "children"));
|
||||
GEN_AND_CHECK(append_children_array_json(gen, node));
|
||||
}
|
||||
|
||||
GEN_AND_CHECK(yajl_gen_map_close(gen));
|
||||
|
||||
return yajl_gen_status_ok;
|
||||
}
|
||||
|
||||
static char *render_error_code(yajl_gen_status status) {
|
||||
char err[1024];
|
||||
snprintf(err, sizeof(err), "{\"error\": %d}", (int)status);
|
||||
return strdup(err);
|
||||
}
|
||||
|
||||
static char *convert_to_json(const JSC::Profile *profile) {
|
||||
yajl_gen_status status;
|
||||
yajl_gen gen = yajl_gen_alloc(NULL);
|
||||
|
||||
status = append_root_json(gen, profile);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
yajl_gen_free(gen);
|
||||
return render_error_code(status);
|
||||
}
|
||||
|
||||
const unsigned char *buf;
|
||||
size_t buf_size;
|
||||
status = yajl_gen_get_buf(gen, &buf, &buf_size);
|
||||
if (status != yajl_gen_status_ok) {
|
||||
yajl_gen_free(gen);
|
||||
return render_error_code(status);
|
||||
}
|
||||
|
||||
char *json_copy = strdup((const char*)buf);
|
||||
yajl_gen_free(gen);
|
||||
return json_copy;
|
||||
}
|
||||
|
||||
static char *JSEndProfilingAndRender(JSContextRef ctx, JSStringRef title)
|
||||
{
|
||||
JSC::ExecState *exec = toJS(ctx);
|
||||
JSC::LegacyProfiler *profiler = JSC::LegacyProfiler::profiler();
|
||||
RefPtr<JSC::Profile> rawProfile = profiler->stopProfiling(exec, title->string());
|
||||
return convert_to_json(rawProfile.get());
|
||||
}
|
||||
|
||||
JSValueRef nativeProfilerStart(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef function,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception) {
|
||||
if (argumentCount < 1) {
|
||||
// Could raise an exception here.
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
JSStringRef title = JSValueToStringCopy(ctx, arguments[0], NULL);
|
||||
JSStartProfiling(ctx, title);
|
||||
JSStringRelease(title);
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
JSValueRef nativeProfilerEnd(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef function,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception) {
|
||||
if (argumentCount < 1) {
|
||||
// Could raise an exception here.
|
||||
return JSValueMakeUndefined(ctx);
|
||||
}
|
||||
|
||||
JSStringRef title = JSValueToStringCopy(ctx, arguments[0], NULL);
|
||||
char *rendered = JSEndProfilingAndRender(ctx, title);
|
||||
JSStringRelease(title);
|
||||
JSStringRef profile = JSStringCreateWithUTF8CString(rendered);
|
||||
free(rendered);
|
||||
return JSValueMakeString(ctx, profile);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
HEADER_PATHS := `find ./tmp/JavaScriptCore -name '*.h' | xargs -I{} dirname {} | uniq | xargs -I{} echo "-I {}"`
|
||||
CERT ?= "iPhone Developer"
|
||||
|
||||
ios8: prepare build generate
|
||||
|
||||
prepare: clean create download
|
||||
|
||||
build: x86_64 arm64 armv7
|
||||
|
||||
generate: lipo codesign
|
||||
|
||||
clean:
|
||||
@rm -rf tmp/ /tmp/RCTJSCProfiler
|
||||
|
||||
lipo:
|
||||
lipo -create -output /tmp/RCTJSCProfiler/RCTJSCProfiler.ios8.dylib ./tmp/RCTJSCProfiler_x86_64 ./tmp/RCTJSCProfiler_arm64 ./tmp/RCTJSCProfiler_armv7
|
||||
|
||||
codesign:
|
||||
codesign -f -s ${CERT} /tmp/RCTJSCProfiler/RCTJSCProfiler.ios8.dylib
|
||||
|
||||
create:
|
||||
mkdir -p ./tmp /tmp/RCTJSCProfiler/ ./tmp/CoreFoundation ./tmp/Foundation
|
||||
for file in ./tmp/CoreFoundation/CFUserNotification.h ./tmp/CoreFoundation/CFXMLNode.h ./tmp/CoreFoundation/CFXMLParser.h ./tmp/Foundation/Foundation.h; do echo '' > "$$file"; done
|
||||
|
||||
download: wtf jsc webcore yajl
|
||||
|
||||
wtf:
|
||||
curl -o tmp/WTF.tar.gz http://www.opensource.apple.com/tarballs/WTF/WTF-7600.1.24.tar.gz
|
||||
tar -zxvf tmp/WTF.tar.gz -C tmp
|
||||
|
||||
jsc:
|
||||
curl -o tmp/JSC.tar.gz http://www.opensource.apple.com/tarballs/JavaScriptCore/JavaScriptCore-7600.1.17.tar.gz
|
||||
tar -zxvf tmp/JSC.tar.gz -C tmp
|
||||
mv ./tmp/JavaScriptCore-7600.1.17 ./tmp/JavaScriptCore
|
||||
python ./tmp/JavaScriptCore/generate-bytecode-files --bytecodes_h ./tmp/JavaScriptCore/Bytecodes.h ./tmp/JavaScriptCore/bytecode/BytecodeList.json
|
||||
|
||||
webcore:
|
||||
curl -o tmp/WebCore.tar.gz http://www.opensource.apple.com/tarballs/WebCore/WebCore-7600.1.25.tar.gz
|
||||
tar -zxvf tmp/WebCore.tar.gz -C tmp
|
||||
|
||||
yajl:
|
||||
curl -o tmp/yajl.tar.gz https://codeload.github.com/lloyd/yajl/tar.gz/2.1.0
|
||||
tar -zxvf tmp/yajl.tar.gz -C tmp
|
||||
mkdir -p ./tmp/yajl-2.1.0/build && cd ./tmp/yajl-2.1.0/build && cmake .. && make
|
||||
echo `find . -name '*.c'`
|
||||
cd ./tmp/yajl-2.1.0/src && \
|
||||
clang -arch arm64 -arch armv7 -std=c99 \
|
||||
-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/include/ \
|
||||
-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/include/machine \
|
||||
-I ../build/yajl-2.1.0/include \
|
||||
-c `find . -name '*.c'`
|
||||
libtool -static -o ./tmp/yajl.a `find ./tmp/yajl-2.1.0/src/ -name '*.o'`
|
||||
|
||||
x86_64:
|
||||
clang -w -dynamiclib -o ./tmp/RCTJSCProfiler_x86_64 -std=c++11 \
|
||||
-install_name RCTJSCProfiler.ios8.dylib \
|
||||
-include ./tmp/JavaScriptCore/config.h \
|
||||
-I ./tmp \
|
||||
-I ./tmp/WebCore-7600.1.25/icu \
|
||||
-I ./tmp/WTF-7600.1.24 \
|
||||
-I ./tmp/yajl-2.1.0/build/yajl-2.1.0/include \
|
||||
-DNDEBUG=1\
|
||||
-miphoneos-version-min=8.0 \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/SDKs/iPhoneSimulator.sdk/usr/lib/system \
|
||||
${HEADER_PATHS} \
|
||||
-undefined dynamic_lookup \
|
||||
./JSCLegacyProfiler.mm ./tmp/yajl-2.1.0/build/yajl-2.1.0/lib/libyajl_s.a
|
||||
|
||||
arm64:
|
||||
echo $(HEADER_PATHS)
|
||||
clang -w -dynamiclib -o ./tmp/RCTJSCProfiler_arm64 -std=c++11 \
|
||||
-install_name RCTJSCProfiler.ios8.dylib \
|
||||
-arch arm64 \
|
||||
-include ./tmp/JavaScriptCore/config.h \
|
||||
-I ./tmp \
|
||||
-I ./tmp/WebCore-7600.1.25/icu \
|
||||
-I ./tmp/WTF-7600.1.24 \
|
||||
-I ./tmp/yajl-2.1.0/build/yajl-2.1.0/include \
|
||||
-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/include \
|
||||
-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/include/machine \
|
||||
-DNDEBUG=1\
|
||||
-miphoneos-version-min=8.0 \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/lib \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/lib/system \
|
||||
${HEADER_PATHS} \
|
||||
-undefined dynamic_lookup \
|
||||
./JSCLegacyProfiler.mm ./tmp/yajl.a
|
||||
|
||||
armv7:
|
||||
clang -w -dynamiclib -o ./tmp/RCTJSCProfiler_armv7 -std=c++11 \
|
||||
-install_name RCTJSCProfiler.ios8.dylib \
|
||||
-arch armv7 \
|
||||
-include ./tmp/JavaScriptCore/config.h \
|
||||
-I ./tmp \
|
||||
-I ./tmp/WebCore-7600.1.25/icu \
|
||||
-I ./tmp/WTF-7600.1.24 \
|
||||
-I ./tmp/yajl-2.1.0/build/yajl-2.1.0/include \
|
||||
-I /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/include \
|
||||
-DNDEBUG=1\
|
||||
-miphoneos-version-min=8.0 \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/lib \
|
||||
-L /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.3.sdk/usr/lib/system \
|
||||
${HEADER_PATHS} \
|
||||
-undefined dynamic_lookup \
|
||||
./JSCLegacyProfiler.mm ./tmp/yajl.a
|
||||
|
||||
.PHONY: ios8
|
|
@ -20,6 +20,22 @@
|
|||
#import "RCTPerformanceLogger.h"
|
||||
#import "RCTUtils.h"
|
||||
|
||||
#ifndef RCT_JSC_PROFILER
|
||||
#if RCT_DEV && DEBUG
|
||||
#define RCT_JSC_PROFILER 1
|
||||
#else
|
||||
#define RCT_JSC_PROFILER 0
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#if RCT_JSC_PROFILER
|
||||
#include <dlfcn.h>
|
||||
|
||||
#ifndef RCT_JSC_PROFILER_DYLIB
|
||||
#define RCT_JSC_PROFILER_DYLIB [[[NSBundle mainBundle] pathForResource:[NSString stringWithFormat:@"RCTJSCProfiler.ios%zd", [[NSProcessInfo processInfo] operatingSystemVersion].majorVersion] ofType:@"dylib" inDirectory:@"Frameworks"] UTF8String]
|
||||
#endif
|
||||
#endif
|
||||
|
||||
@interface RCTJavaScriptContext : NSObject <RCTInvalidating>
|
||||
|
||||
@property (nonatomic, assign, readonly) JSGlobalContextRef ctx;
|
||||
|
@ -269,6 +285,18 @@ static NSError *RCTNSErrorFromJSError(JSContextRef context, JSValueRef jsError)
|
|||
[strongSelf _addNativeHook:RCTConsoleProfile withName:"consoleProfile"];
|
||||
[strongSelf _addNativeHook:RCTConsoleProfileEnd withName:"consoleProfileEnd"];
|
||||
|
||||
#if RCT_JSC_PROFILER
|
||||
void *JSCProfiler = dlopen(RCT_JSC_PROFILER_DYLIB, RTLD_NOW);
|
||||
if (JSCProfiler != NULL) {
|
||||
JSObjectCallAsFunctionCallback nativeProfilerStart = dlsym(JSCProfiler, "nativeProfilerStart");
|
||||
JSObjectCallAsFunctionCallback nativeProfilerEnd = dlsym(JSCProfiler, "nativeProfilerEnd");
|
||||
if (nativeProfilerStart != NULL && nativeProfilerEnd != NULL) {
|
||||
[strongSelf _addNativeHook:nativeProfilerStart withName:"nativeProfilerStart"];
|
||||
[strongSelf _addNativeHook:nativeProfilerEnd withName:"nativeProfilerStop"];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:strongSelf
|
||||
selector:@selector(toggleProfilingFlag:)
|
||||
|
|
|
@ -472,6 +472,7 @@
|
|||
83CBBA2A1A601D0E00E9B192 /* Sources */,
|
||||
83CBBA2B1A601D0E00E9B192 /* Frameworks */,
|
||||
83CBBA2C1A601D0E00E9B192 /* Copy Files */,
|
||||
142C4F7F1B582EA6001F0B58 /* ShellScript */,
|
||||
);
|
||||
buildRules = (
|
||||
);
|
||||
|
@ -528,6 +529,20 @@
|
|||
shellPath = /bin/sh;
|
||||
shellScript = "if nc -w 5 -z localhost 8081 ; then\n if ! curl -s \"http://localhost:8081/status\" | grep -q \"packager-status:running\" ; then\n echo \"Port 8081 already in use, packager is either not running or not running correctly\"\n exit 2\n fi\nelse\n open $SRCROOT/../packager/launchPackager.command || echo \"Can't start packager automatically\"\nfi";
|
||||
};
|
||||
142C4F7F1B582EA6001F0B58 /* ShellScript */ = {
|
||||
isa = PBXShellScriptBuildPhase;
|
||||
buildActionMask = 2147483647;
|
||||
files = (
|
||||
);
|
||||
inputPaths = (
|
||||
);
|
||||
outputPaths = (
|
||||
);
|
||||
runOnlyForDeploymentPostprocessing = 0;
|
||||
shellPath = /bin/sh;
|
||||
shellScript = "if [[ \"$CONFIGURATION\" == \"Debug\" ]] && [[ -d \"/tmp/RCTJSCProfiler\" ]]; then\n find \"${CONFIGURATION_BUILD_DIR}\" -name '*.app' | xargs -I{} sh -c 'mkdir -p \"$1/Frameworks\" && cp -r /tmp/RCTJSCProfiler/* \"$1/Frameworks\"' -- {}\nfi";
|
||||
showEnvVarsInLog = 0;
|
||||
};
|
||||
/* End PBXShellScriptBuildPhase section */
|
||||
|
||||
/* Begin PBXSourcesBuildPhase section */
|
||||
|
|
Загрузка…
Ссылка в новой задаче