mirror of
https://github.com/zhigang1992/react-native.git
synced 2026-04-28 20:25:33 +08:00
[ReactNative] Add JavaScriptCore legacy profiler
This commit is contained in:
161
JSCLegacyProfiler/JSCLegacyProfiler.mm
Normal file
161
JSCLegacyProfiler/JSCLegacyProfiler.mm
Normal file
@@ -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);
|
||||
}
|
||||
Reference in New Issue
Block a user