mirror of
https://github.com/zebrajr/react.git
synced 2026-01-15 12:15:22 +00:00
Add rudimentary jsc perf-counters runner
Works at least on a CentOS 7 machine after running `sudo yum install
webkitgtk webkitgtk-devel`.
The only globals you get are `print` and `PerfCounters`. No `console` nor the other globals provided by the `jsc` command-line tool (load, readFile, etc) though they're probably not hard to implement.
You can disable the JIT by setting the environment variable `JSC_useJIT=false`.
Test Plan:
```
~/local/react/scripts/perf-counters$ make
~/local/react/scripts/perf-counters$ build/jsc-perf <(echo 'PerfCounters.init(); var a = PerfCounters.getCounters().instructions; print("moo"); var b = PerfCounters.getCounters().instructions; print(b - a);')
moo
72182
~/local/react/scripts/perf-counters$
```
This commit is contained in:
3
scripts/perf-counters/Makefile
Normal file
3
scripts/perf-counters/Makefile
Normal file
@@ -0,0 +1,3 @@
|
||||
build/jsc-perf: src/*
|
||||
mkdir -p build
|
||||
g++ -std=c++11 -I/usr/include/webkitgtk-1.0/ -ljavascriptcoregtk-1.0 src/jsc-perf.cpp src/hardware-counter.cpp src/thread-local.cpp -o build/jsc-perf
|
||||
204
scripts/perf-counters/src/jsc-perf.cpp
Normal file
204
scripts/perf-counters/src/jsc-perf.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
/**
|
||||
* Copyright 2015, 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.
|
||||
*/
|
||||
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include <JavaScriptCore/JavaScript.h>
|
||||
|
||||
#include "hardware-counter.h"
|
||||
|
||||
using HPHP::HardwareCounter;
|
||||
|
||||
void add_native_hook(
|
||||
JSContextRef ctx,
|
||||
JSObjectRef obj,
|
||||
const char *name,
|
||||
JSObjectCallAsFunctionCallback hook
|
||||
) {
|
||||
JSStringRef jsName = JSStringCreateWithUTF8CString(name);
|
||||
JSObjectSetProperty(
|
||||
ctx,
|
||||
obj,
|
||||
jsName,
|
||||
JSObjectMakeFunctionWithCallback(ctx, jsName, hook),
|
||||
kJSPropertyAttributeNone,
|
||||
NULL
|
||||
);
|
||||
JSStringRelease(jsName);
|
||||
}
|
||||
|
||||
static void fprint_value(
|
||||
FILE *file,
|
||||
JSContextRef context,
|
||||
JSValueRef obj
|
||||
) {
|
||||
JSStringRef jsStr = JSValueToStringCopy(context, obj, NULL);
|
||||
size_t size = JSStringGetMaximumUTF8CStringSize(jsStr);
|
||||
char *str = (char *) calloc(
|
||||
size,
|
||||
1
|
||||
);
|
||||
JSStringGetUTF8CString(
|
||||
jsStr,
|
||||
str,
|
||||
size
|
||||
);
|
||||
JSStringRelease(jsStr);
|
||||
fprintf(file, "%s", str);
|
||||
free(str);
|
||||
}
|
||||
|
||||
static JSValueRef js_print(
|
||||
JSContextRef context,
|
||||
JSObjectRef object,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception
|
||||
) {
|
||||
for (int i = 0; i < argumentCount; i++) {
|
||||
if (i != 0) {
|
||||
printf(" ");
|
||||
}
|
||||
fprint_value(stdout, context, arguments[i]);
|
||||
}
|
||||
printf("\n");
|
||||
return JSValueMakeUndefined(context);
|
||||
}
|
||||
|
||||
static JSValueRef js_perf_counters_init(
|
||||
JSContextRef context,
|
||||
JSObjectRef object,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception
|
||||
) {
|
||||
// TODO: Allow customizing recorded events
|
||||
bool enable = true;
|
||||
std::string events = "";
|
||||
bool recordSubprocesses = false;
|
||||
HardwareCounter::Init(enable, events, recordSubprocesses);
|
||||
HardwareCounter::s_counter.getCheck();
|
||||
|
||||
return JSValueMakeUndefined(context);
|
||||
}
|
||||
|
||||
static JSValueRef js_perf_counters_get_counters(
|
||||
JSContextRef context,
|
||||
JSObjectRef object,
|
||||
JSObjectRef thisObject,
|
||||
size_t argumentCount,
|
||||
const JSValueRef arguments[],
|
||||
JSValueRef *exception
|
||||
) {
|
||||
JSObjectRef result = JSObjectMake(context, NULL, NULL);
|
||||
std::pair<JSContextRef, JSObjectRef> pair(context, result);
|
||||
|
||||
HardwareCounter::GetPerfEvents(
|
||||
[](const std::string& key, int64_t value, void* data) {
|
||||
std::pair<JSContextRef, JSObjectRef>& pair =
|
||||
*reinterpret_cast<std::pair<JSContextRef, JSObjectRef>*>(data);
|
||||
JSContextRef context = pair.first;
|
||||
JSObjectRef result = pair.second;
|
||||
|
||||
JSObjectSetProperty(
|
||||
context,
|
||||
result,
|
||||
JSStringCreateWithUTF8CString(key.c_str()),
|
||||
JSValueMakeNumber(context, value),
|
||||
kJSPropertyAttributeNone,
|
||||
NULL
|
||||
);
|
||||
},
|
||||
&pair);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
if (argc != 2) {
|
||||
fprintf(stderr, "usage: jsc-runner file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
char *filename = argv[1];
|
||||
std::ifstream ifs(filename);
|
||||
if (ifs.fail()) {
|
||||
std::cerr << "Error opening \"" << filename << "\": " << strerror(errno) << "\n";
|
||||
exit(1);
|
||||
}
|
||||
std::string script(
|
||||
(std::istreambuf_iterator<char>(ifs)),
|
||||
(std::istreambuf_iterator<char>())
|
||||
);
|
||||
JSStringRef jsScript = JSStringCreateWithUTF8CString(script.c_str());
|
||||
JSStringRef jsURL = JSStringCreateWithUTF8CString(argv[1]);
|
||||
|
||||
JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
|
||||
add_native_hook(
|
||||
ctx,
|
||||
JSContextGetGlobalObject(ctx),
|
||||
"print",
|
||||
js_print
|
||||
);
|
||||
|
||||
JSObjectRef jsPerfCounters = JSObjectMake(ctx, NULL, NULL);
|
||||
add_native_hook(
|
||||
ctx,
|
||||
jsPerfCounters,
|
||||
"init",
|
||||
js_perf_counters_init
|
||||
);
|
||||
add_native_hook(
|
||||
ctx,
|
||||
jsPerfCounters,
|
||||
"getCounters",
|
||||
js_perf_counters_get_counters
|
||||
);
|
||||
JSObjectSetProperty(
|
||||
ctx,
|
||||
JSContextGetGlobalObject(ctx),
|
||||
JSStringCreateWithUTF8CString("PerfCounters"),
|
||||
jsPerfCounters,
|
||||
kJSPropertyAttributeNone,
|
||||
NULL
|
||||
);
|
||||
|
||||
JSValueRef jsError = NULL;
|
||||
JSValueRef result = JSEvaluateScript(
|
||||
ctx,
|
||||
jsScript,
|
||||
NULL,
|
||||
jsURL,
|
||||
0,
|
||||
&jsError
|
||||
);
|
||||
if (!result) {
|
||||
fprintf(stderr, "Exception: ");
|
||||
fprint_value(stderr, ctx, jsError);
|
||||
fprintf(stderr, "\n");
|
||||
JSStringRef jsStackStr = JSStringCreateWithUTF8CString("stack");
|
||||
if (JSValueIsObject(ctx, jsError)) {
|
||||
JSValueRef jsStack = JSObjectGetProperty(ctx, (JSObjectRef)jsError, jsStackStr, NULL);
|
||||
JSStringRelease(jsStackStr);
|
||||
fprint_value(stderr, ctx, jsStack);
|
||||
fprintf(stderr, "\n");
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
JSGlobalContextRelease(ctx);
|
||||
}
|
||||
Reference in New Issue
Block a user