Update json generation code and save to file
Summary: @public * Change the JSON generation and remove the dependency on YAJL since it had a 128 depth limit * Enable the profiler bytecode generation to fix missing frames * Save the output to a file on the tmp dir instead of outputting it to the console Reviewed By: @jspahrsummers Differential Revision: D2420754
This commit is contained in:
parent
2a34239c17
commit
af05af7125
|
@ -6,7 +6,8 @@
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
|
|
||||||
|
void nativeProfilerEnableBytecode(void);
|
||||||
void nativeProfilerStart(JSContextRef ctx, const char *title);
|
void nativeProfilerStart(JSContextRef ctx, const char *title);
|
||||||
const char *nativeProfilerEnd(JSContextRef ctx, const char *title);
|
void nativeProfilerEnd(JSContextRef ctx, const char *title, const char *filename);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,125 +6,298 @@
|
||||||
#include "JSProfilerPrivate.h"
|
#include "JSProfilerPrivate.h"
|
||||||
#include "JSStringRef.h"
|
#include "JSStringRef.h"
|
||||||
#include "String.h"
|
#include "String.h"
|
||||||
|
#include "Options.h"
|
||||||
|
|
||||||
#include <YAJL/yajl_gen.h>
|
enum json_gen_status {
|
||||||
|
json_gen_status_ok = 0,
|
||||||
|
json_gen_status_error = 1,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum json_entry {
|
||||||
|
json_entry_key,
|
||||||
|
json_entry_value,
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
|
||||||
|
struct json_state {
|
||||||
|
FILE *fileOut;
|
||||||
|
bool hasFirst;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
typedef json_state *json_gen;
|
||||||
|
|
||||||
|
static void json_escaped_cstring_printf(json_gen gen, const char *str) {
|
||||||
|
const char *cursor = str;
|
||||||
|
fputc('"', gen->fileOut);
|
||||||
|
while (*cursor) {
|
||||||
|
const char *escape = nullptr;
|
||||||
|
switch (*cursor) {
|
||||||
|
case '"':
|
||||||
|
escape = "\\\"";
|
||||||
|
break;
|
||||||
|
case '\b':
|
||||||
|
escape = "\\b";
|
||||||
|
break;
|
||||||
|
case '\f':
|
||||||
|
escape = "\\f";
|
||||||
|
break;
|
||||||
|
case '\n':
|
||||||
|
escape = "\\n";
|
||||||
|
break;
|
||||||
|
case '\r':
|
||||||
|
escape = "\\r";
|
||||||
|
break;
|
||||||
|
case '\t':
|
||||||
|
escape = "\\t";
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
escape = "\\\\";
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (escape != nullptr) {
|
||||||
|
fwrite(escape, 1, strlen(escape), gen->fileOut);
|
||||||
|
} else {
|
||||||
|
fputc(*cursor, gen->fileOut);
|
||||||
|
}
|
||||||
|
cursor++;
|
||||||
|
}
|
||||||
|
fputc('"', gen->fileOut);
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_key_cstring(json_gen gen, const char *buffer) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
gen->hasFirst = true;
|
||||||
|
|
||||||
|
json_escaped_cstring_printf(gen, buffer);
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_map_open(json_gen gen, json_entry entryType) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryType == json_entry_value) {
|
||||||
|
fprintf(gen->fileOut, ":");
|
||||||
|
} else if (entryType == json_entry_key) {
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(gen->fileOut, "{");
|
||||||
|
gen->hasFirst = false;
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_map_close(json_gen gen) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(gen->fileOut, "}");
|
||||||
|
gen->hasFirst = true;
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_array_open(json_gen gen, json_entry entryType) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (entryType == json_entry_value) {
|
||||||
|
fprintf(gen->fileOut, ":");
|
||||||
|
} else if (entryType == json_entry_key) {
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fprintf(gen->fileOut, "[");
|
||||||
|
gen->hasFirst = false;
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_array_close(json_gen gen) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprintf(gen->fileOut, "]");
|
||||||
|
gen->hasFirst = true;
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_keyvalue_cstring(json_gen gen, const char *key, const char *value) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
gen->hasFirst = true;
|
||||||
|
|
||||||
|
fprintf(gen->fileOut, "\"%s\" : ", key);
|
||||||
|
json_escaped_cstring_printf(gen, value);
|
||||||
|
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static json_gen_status json_gen_keyvalue_integer(json_gen gen, const char *key, int value) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
gen->hasFirst = true;
|
||||||
|
|
||||||
|
fprintf(gen->fileOut, "\"%s\": %d", key, value);
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen_status json_gen_keyvalue_double(json_gen gen, const char *key, double value) {
|
||||||
|
if (gen->fileOut == nullptr) {
|
||||||
|
return json_gen_status_error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (gen->hasFirst) {
|
||||||
|
fprintf(gen->fileOut, ",");
|
||||||
|
}
|
||||||
|
gen->hasFirst = true;
|
||||||
|
|
||||||
|
fprintf(gen->fileOut, "\"%s\": %.20g", key, value);
|
||||||
|
return json_gen_status_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static json_gen json_gen_alloc(const char *fileName) {
|
||||||
|
json_gen gen = (json_gen)malloc(sizeof(json_state));
|
||||||
|
memset(gen, 0, sizeof(json_state));
|
||||||
|
gen->fileOut = fopen(fileName, "wb");
|
||||||
|
return gen;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void json_gen_free(json_gen gen) {
|
||||||
|
if (gen->fileOut) {
|
||||||
|
fclose(gen->fileOut);
|
||||||
|
}
|
||||||
|
free(gen);
|
||||||
|
}
|
||||||
|
|
||||||
#define GEN_AND_CHECK(expr) \
|
#define GEN_AND_CHECK(expr) \
|
||||||
do { \
|
do { \
|
||||||
yajl_gen_status GEN_AND_CHECK_status = (expr); \
|
json_gen_status GEN_AND_CHECK_status = (expr); \
|
||||||
if (GEN_AND_CHECK_status != yajl_gen_status_ok) { \
|
if (GEN_AND_CHECK_status != json_gen_status_ok) { \
|
||||||
return GEN_AND_CHECK_status; \
|
return GEN_AND_CHECK_status; \
|
||||||
} \
|
} \
|
||||||
} while (false)
|
} 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 json_gen_status append_children_array_json(json_gen gen, const JSC::ProfileNode *node);
|
||||||
static yajl_gen_status append_node_json(yajl_gen gen, const JSC::ProfileNode *node);
|
static json_gen_status append_node_json(json_gen gen, const JSC::ProfileNode *node);
|
||||||
|
|
||||||
static yajl_gen_status append_root_json(yajl_gen gen, const JSC::Profile *profile) {
|
static json_gen_status append_root_json(json_gen gen, const JSC::Profile *profile) {
|
||||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
GEN_AND_CHECK(json_gen_map_open(gen, json_entry_key));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "rootNodes"));
|
GEN_AND_CHECK(json_gen_key_cstring(gen, "rootNodes"));
|
||||||
GEN_AND_CHECK(append_children_array_json(gen, profile->head()));
|
GEN_AND_CHECK(append_children_array_json(gen, profile->head()));
|
||||||
GEN_AND_CHECK(yajl_gen_map_close(gen));
|
GEN_AND_CHECK(json_gen_map_close(gen));
|
||||||
|
|
||||||
return yajl_gen_status_ok;
|
return json_gen_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static yajl_gen_status append_children_array_json(yajl_gen gen, const JSC::ProfileNode *node) {
|
static json_gen_status append_children_array_json(json_gen gen, const JSC::ProfileNode *node) {
|
||||||
GEN_AND_CHECK(yajl_gen_array_open(gen));
|
GEN_AND_CHECK(json_gen_array_open(gen, json_entry_value));
|
||||||
for (RefPtr<JSC::ProfileNode> child : node->children()) {
|
for (RefPtr<JSC::ProfileNode> child : node->children()) {
|
||||||
GEN_AND_CHECK(append_node_json(gen, child.get()));
|
GEN_AND_CHECK(append_node_json(gen, child.get()));
|
||||||
}
|
}
|
||||||
GEN_AND_CHECK(yajl_gen_array_close(gen));
|
GEN_AND_CHECK(json_gen_array_close(gen));
|
||||||
|
|
||||||
return yajl_gen_status_ok;
|
return json_gen_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static yajl_gen_status append_node_json(yajl_gen gen, const JSC::ProfileNode *node) {
|
static json_gen_status append_node_json(json_gen gen, const JSC::ProfileNode *node) {
|
||||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
GEN_AND_CHECK(json_gen_map_open(gen, json_entry_key));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "id"));
|
GEN_AND_CHECK(json_gen_keyvalue_integer(gen, "id", node->id()));
|
||||||
GEN_AND_CHECK(yajl_gen_integer(gen, node->id()));
|
|
||||||
|
|
||||||
if (!node->functionName().isEmpty()) {
|
if (!node->functionName().isEmpty()) {
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "functionName"));
|
GEN_AND_CHECK(json_gen_keyvalue_cstring(gen, "functionName", node->functionName().utf8().data()));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, node->functionName().utf8().data()));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!node->url().isEmpty()) {
|
if (!node->url().isEmpty()) {
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "url"));
|
GEN_AND_CHECK(json_gen_keyvalue_cstring(gen, "url", node->url().utf8().data()));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, node->url().utf8().data()));
|
GEN_AND_CHECK(json_gen_keyvalue_integer(gen, "lineNumber", node->lineNumber()));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "lineNumber"));
|
GEN_AND_CHECK(json_gen_keyvalue_integer(gen, "columnNumber", node->columnNumber()));
|
||||||
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(json_gen_key_cstring(gen, "calls"));
|
||||||
GEN_AND_CHECK(yajl_gen_array_open(gen));
|
GEN_AND_CHECK(json_gen_array_open(gen, json_entry_value));
|
||||||
for (const JSC::ProfileNode::Call &call : node->calls()) {
|
for (const JSC::ProfileNode::Call &call : node->calls()) {
|
||||||
GEN_AND_CHECK(yajl_gen_map_open(gen));
|
GEN_AND_CHECK(json_gen_map_open(gen, json_entry_key));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "startTime"));
|
GEN_AND_CHECK(json_gen_keyvalue_double(gen, "startTime", call.startTime()));
|
||||||
GEN_AND_CHECK(yajl_gen_double(gen, call.startTime()));
|
GEN_AND_CHECK(json_gen_keyvalue_double(gen, "totalTime", call.totalTime()));
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "totalTime"));
|
GEN_AND_CHECK(json_gen_map_close(gen));
|
||||||
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));
|
GEN_AND_CHECK(json_gen_array_close(gen));
|
||||||
|
|
||||||
if (!node->children().isEmpty()) {
|
if (!node->children().isEmpty()) {
|
||||||
GEN_AND_CHECK(yajl_gen_cstring(gen, "children"));
|
GEN_AND_CHECK(json_gen_key_cstring(gen, "children"));
|
||||||
GEN_AND_CHECK(append_children_array_json(gen, node));
|
GEN_AND_CHECK(append_children_array_json(gen, node));
|
||||||
}
|
}
|
||||||
|
|
||||||
GEN_AND_CHECK(yajl_gen_map_close(gen));
|
GEN_AND_CHECK(json_gen_map_close(gen));
|
||||||
|
|
||||||
return yajl_gen_status_ok;
|
return json_gen_status_ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char *render_error_code(yajl_gen_status status) {
|
static void convert_to_json(const JSC::Profile *profile, const char *filename) {
|
||||||
char err[1024];
|
json_gen_status status;
|
||||||
snprintf(err, sizeof(err), "{\"error\": %d}", (int)status);
|
json_gen gen = json_gen_alloc(filename);
|
||||||
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);
|
status = append_root_json(gen, profile);
|
||||||
if (status != yajl_gen_status_ok) {
|
if (status != json_gen_status_ok) {
|
||||||
yajl_gen_free(gen);
|
FILE *fileOut = fopen(filename, "wb");
|
||||||
return render_error_code(status);
|
if (fileOut != nullptr) {
|
||||||
|
fprintf(fileOut, "{\"error\": %d}", (int)status);
|
||||||
|
fclose(fileOut);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
json_gen_free(gen);
|
||||||
}
|
}
|
||||||
|
|
||||||
const unsigned char *buf;
|
// Based on JSEndProfiling, with a little extra code to return the profile as JSON.
|
||||||
size_t buf_size;
|
static void JSEndProfilingAndRender(JSContextRef ctx, const char *title, const char *filename)
|
||||||
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 const char *JSEndProfilingAndRender(JSContextRef ctx, const char *title)
|
|
||||||
{
|
{
|
||||||
JSC::ExecState *exec = toJS(ctx);
|
JSC::ExecState *exec = toJS(ctx);
|
||||||
JSC::LegacyProfiler *profiler = JSC::LegacyProfiler::profiler();
|
JSC::LegacyProfiler *profiler = JSC::LegacyProfiler::profiler();
|
||||||
RefPtr<JSC::Profile> rawProfile = profiler->stopProfiling(exec, WTF::String(title));
|
RefPtr<JSC::Profile> rawProfile = profiler->stopProfiling(exec, WTF::String(title));
|
||||||
return convert_to_json(rawProfile.get());
|
convert_to_json(rawProfile.get(), filename);
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "C" {
|
||||||
|
|
||||||
|
void nativeProfilerEnableBytecode(void)
|
||||||
|
{
|
||||||
|
JSC::Options::setOption("forceProfilerBytecodeGeneration=true");
|
||||||
}
|
}
|
||||||
|
|
||||||
void nativeProfilerStart(JSContextRef ctx, const char *title) {
|
void nativeProfilerStart(JSContextRef ctx, const char *title) {
|
||||||
JSStartProfiling(ctx, JSStringCreateWithUTF8CString(title));
|
JSStartProfiling(ctx, JSStringCreateWithUTF8CString(title));
|
||||||
}
|
}
|
||||||
|
|
||||||
const char *nativeProfilerEnd( JSContextRef ctx, const char *title) {
|
void nativeProfilerEnd(JSContextRef ctx, const char *title, const char *filename) {
|
||||||
return JSEndProfilingAndRender(ctx, title);
|
JSEndProfilingAndRender(ctx, title, filename);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ PLATFORM = \
|
||||||
|
|
||||||
SYSROOT = -isysroot $(call SDK_PATH,$${PLATFORM})
|
SYSROOT = -isysroot $(call SDK_PATH,$${PLATFORM})
|
||||||
|
|
||||||
IOS8_LIBS = download/WebCore/WebCore-7600.1.25 download/WTF/WTF-7600.1.24 download/JavaScriptCore/JavaScriptCore-7600.1.17 download/JavaScriptCore/JavaScriptCore-7600.1.17/Bytecodes.h libyajl.a
|
IOS8_LIBS = download/WebCore/WebCore-7600.1.25 download/WTF/WTF-7600.1.24 download/JavaScriptCore/JavaScriptCore-7600.1.17 download/JavaScriptCore/JavaScriptCore-7600.1.17/Bytecodes.h
|
||||||
|
|
||||||
ios8: RCTJSCProfiler.ios8.dylib /tmp/RCTJSCProfiler
|
ios8: RCTJSCProfiler.ios8.dylib /tmp/RCTJSCProfiler
|
||||||
ifneq ($(SDK_VERSION), 8)
|
ifneq ($(SDK_VERSION), 8)
|
||||||
|
@ -47,43 +47,17 @@ RCTJSCProfiler_%.ios8.dylib: $(IOS8_LIBS)
|
||||||
-I download \
|
-I download \
|
||||||
-I download/WebCore/WebCore-7600.1.25/icu \
|
-I download/WebCore/WebCore-7600.1.25/icu \
|
||||||
-I download/WTF/WTF-7600.1.24 \
|
-I download/WTF/WTF-7600.1.24 \
|
||||||
-I download/yajl-2.1.0/build/yajl-2.1.0/include \
|
|
||||||
-DNDEBUG=1\
|
-DNDEBUG=1\
|
||||||
-miphoneos-version-min=8.0 \
|
-miphoneos-version-min=8.0 \
|
||||||
$(SYSROOT) \
|
$(SYSROOT) \
|
||||||
$(HEADER_PATHS) \
|
$(HEADER_PATHS) \
|
||||||
-undefined dynamic_lookup \
|
-undefined dynamic_lookup \
|
||||||
JSCLegacyProfiler.mm libyajl.a
|
JSCLegacyProfiler.mm
|
||||||
|
|
||||||
.PRECIOUS: %/Bytecodes.h
|
.PRECIOUS: %/Bytecodes.h
|
||||||
%/Bytecodes.h:
|
%/Bytecodes.h:
|
||||||
python $*/generate-bytecode-files --bytecodes_h $@ $*/bytecode/BytecodeList.json
|
python $*/generate-bytecode-files --bytecodes_h $@ $*/bytecode/BytecodeList.json
|
||||||
|
|
||||||
.PRECIOUS: libyajl.a
|
|
||||||
libyajl.a: $(patsubst %,libyajl_%.a,$(ARCHS))
|
|
||||||
lipo -create $^ -output $@
|
|
||||||
|
|
||||||
.PRECIOUS: libyajl_%.a
|
|
||||||
libyajl_%.a: download/yajl-2.1.0
|
|
||||||
$(PLATFORM) \
|
|
||||||
cd download/yajl-2.1.0/src; \
|
|
||||||
clang -arch $(*F) -std=c99 \
|
|
||||||
-miphoneos-version-min=8.0 \
|
|
||||||
$(SYSROOT) \
|
|
||||||
-I ../build/yajl-2.1.0/include \
|
|
||||||
-c `find . -name '*.c'`
|
|
||||||
find download/yajl-2.1.0/src/ -name '*.o' -exec libtool -static -o $@ {} +
|
|
||||||
|
|
||||||
.PRECIOUS: download/yajl-2.1.0
|
|
||||||
download/yajl-2.1.0: download/yajl-2.1.0.tar.gz
|
|
||||||
tar -zxvf $< -C download > /dev/null
|
|
||||||
mkdir -p download/yajl-2.1.0/build && cd download/yajl-2.1.0/build && cmake ..
|
|
||||||
|
|
||||||
.PRECIOUS: download/yajl-2.1.0.tar.gz
|
|
||||||
download/yajl-2.1.0.tar.gz:
|
|
||||||
mkdir -p `dirname $@`
|
|
||||||
curl -o $@ https://codeload.github.com/lloyd/yajl/tar.gz/2.1.0
|
|
||||||
|
|
||||||
.PRECIOUS: download/%
|
.PRECIOUS: download/%
|
||||||
download/%: download/%.tar.gz
|
download/%: download/%.tar.gz
|
||||||
tar -zxvf $< -C `dirname $@` > /dev/null
|
tar -zxvf $< -C `dirname $@` > /dev/null
|
||||||
|
@ -95,6 +69,6 @@ download/%: download/%.tar.gz
|
||||||
|
|
||||||
.PHONY: clean
|
.PHONY: clean
|
||||||
clean:
|
clean:
|
||||||
@rm -rf $(wildcard *.dylib)
|
-rm -rf $(wildcard *.dylib)
|
||||||
@rm -rf $(wildcard *.a)
|
-rm -rf $(wildcard *.a)
|
||||||
@rm -rf download
|
-rm -rf download
|
||||||
|
|
|
@ -206,6 +206,40 @@ static JSValueRef RCTNativeTraceEndSection(JSContextRef context, __unused JSObje
|
||||||
return JSValueMakeUndefined(context);
|
return JSValueMakeUndefined(context);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void RCTInstallJSCProfiler(RCTBridge *bridge, JSContextRef context)
|
||||||
|
{
|
||||||
|
#if RCT_JSC_PROFILER
|
||||||
|
void *JSCProfiler = dlopen(RCT_JSC_PROFILER_DYLIB, RTLD_NOW);
|
||||||
|
if (JSCProfiler != NULL) {
|
||||||
|
void (*nativeProfilerStart)(JSContextRef, const char *) =
|
||||||
|
(__typeof__(nativeProfilerStart))dlsym(JSCProfiler, "nativeProfilerStart");
|
||||||
|
void (*nativeProfilerEnd)(JSContextRef, const char *, const char *) =
|
||||||
|
(__typeof__(nativeProfilerEnd))dlsym(JSCProfiler, "nativeProfilerEnd");
|
||||||
|
|
||||||
|
if (nativeProfilerStart != NULL && nativeProfilerEnd != NULL) {
|
||||||
|
void (*nativeProfilerEnableByteCode)(void) =
|
||||||
|
(__typeof__(nativeProfilerEnableByteCode))dlsym(JSCProfiler, "nativeProfilerEnableByteCode");
|
||||||
|
|
||||||
|
if (nativeProfilerEnableByteCode != NULL) {
|
||||||
|
nativeProfilerEnableByteCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
__block BOOL isProfiling = NO;
|
||||||
|
[bridge.devMenu addItem:@"Profile" handler:^{
|
||||||
|
if (isProfiling) {
|
||||||
|
NSString *outputFile = [NSTemporaryDirectory() stringByAppendingPathComponent:@"cpu_profile.json"];
|
||||||
|
nativeProfilerEnd(context, "profile", outputFile.UTF8String);
|
||||||
|
RCTLogInfo(@"CPU profile outputed to '%@'", outputFile);
|
||||||
|
} else {
|
||||||
|
nativeProfilerStart(context, "profile");
|
||||||
|
}
|
||||||
|
isProfiling = !isProfiling;
|
||||||
|
}];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
+ (void)runRunLoopThread
|
+ (void)runRunLoopThread
|
||||||
|
@ -284,24 +318,7 @@ static JSValueRef RCTNativeTraceEndSection(JSContextRef context, __unused JSObje
|
||||||
[strongSelf _addNativeHook:RCTNativeTraceBeginSection withName:"nativeTraceBeginSection"];
|
[strongSelf _addNativeHook:RCTNativeTraceBeginSection withName:"nativeTraceBeginSection"];
|
||||||
[strongSelf _addNativeHook:RCTNativeTraceEndSection withName:"nativeTraceEndSection"];
|
[strongSelf _addNativeHook:RCTNativeTraceEndSection withName:"nativeTraceEndSection"];
|
||||||
|
|
||||||
#if RCT_JSC_PROFILER
|
RCTInstallJSCProfiler(_bridge, strongSelf->_context.ctx);
|
||||||
void *JSCProfiler = dlopen(RCT_JSC_PROFILER_DYLIB, RTLD_NOW);
|
|
||||||
if (JSCProfiler != NULL) {
|
|
||||||
void (*nativeProfilerStart)(JSContextRef, const char *) = (void (*)(JSContextRef, const char *))dlsym(JSCProfiler, "nativeProfilerStart");
|
|
||||||
const char *(*nativeProfilerEnd)(JSContextRef, const char *) = (const char *(*)(JSContextRef, const char *))dlsym(JSCProfiler, "nativeProfilerEnd");
|
|
||||||
if (nativeProfilerStart != NULL && nativeProfilerEnd != NULL) {
|
|
||||||
__block BOOL isProfiling = NO;
|
|
||||||
[_bridge.devMenu addItem:@"Profile" handler:^{
|
|
||||||
if (isProfiling) {
|
|
||||||
RCTLogInfo(@"%s", nativeProfilerEnd(strongSelf->_context.ctx, "profile"));
|
|
||||||
} else {
|
|
||||||
nativeProfilerStart(strongSelf->_context.ctx, "profile");
|
|
||||||
}
|
|
||||||
isProfiling = !isProfiling;
|
|
||||||
}];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
|
for (NSString *event in @[RCTProfileDidStartProfiling, RCTProfileDidEndProfiling]) {
|
||||||
[[NSNotificationCenter defaultCenter] addObserver:strongSelf
|
[[NSNotificationCenter defaultCenter] addObserver:strongSelf
|
||||||
|
|
Loading…
Reference in New Issue