@samitouri / QOS-React-2 / commits / 3b28c72142

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$ ```

Ben Alpert committed Sep 30, 2015 at 18:36 UTC 3b28c72142ec937ff222463fc33243a9c43d6633
2 files changed +207
scripts/perf-counters/Makefile new
+3
@@ -0,0 +1,3 @@
1 +build/jsc-perf: src/*
2 + mkdir -p build
3 + 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
scripts/perf-counters/src/jsc-perf.cpp new
+204
@@ -0,0 +1,204 @@
1 +/**
2 + * Copyright 2015, Facebook, Inc.
3 + * All rights reserved.
4 + *
5 + * This source code is licensed under the BSD-style license found in the
6 + * LICENSE file in the root directory of this source tree. An additional grant
7 + * of patent rights can be found in the PATENTS file in the same directory.
8 + */
9 +
10 +#include <errno.h>
11 +#include <stdlib.h>
12 +#include <string.h>
13 +
14 +#include <fstream>
15 +#include <iostream>
16 +#include <string>
17 +
18 +#include <JavaScriptCore/JavaScript.h>
19 +
20 +#include "hardware-counter.h"
21 +
22 +using HPHP::HardwareCounter;
23 +
24 +void add_native_hook(
25 + JSContextRef ctx,
26 + JSObjectRef obj,
27 + const char *name,
28 + JSObjectCallAsFunctionCallback hook
29 +) {
30 + JSStringRef jsName = JSStringCreateWithUTF8CString(name);
31 + JSObjectSetProperty(
32 + ctx,
33 + obj,
34 + jsName,
35 + JSObjectMakeFunctionWithCallback(ctx, jsName, hook),
36 + kJSPropertyAttributeNone,
37 + NULL
38 + );
39 + JSStringRelease(jsName);
40 +}
41 +
42 +static void fprint_value(
43 + FILE *file,
44 + JSContextRef context,
45 + JSValueRef obj
46 +) {
47 + JSStringRef jsStr = JSValueToStringCopy(context, obj, NULL);
48 + size_t size = JSStringGetMaximumUTF8CStringSize(jsStr);
49 + char *str = (char *) calloc(
50 + size,
51 + 1
52 + );
53 + JSStringGetUTF8CString(
54 + jsStr,
55 + str,
56 + size
57 + );
58 + JSStringRelease(jsStr);
59 + fprintf(file, "%s", str);
60 + free(str);
61 +}
62 +
63 +static JSValueRef js_print(
64 + JSContextRef context,
65 + JSObjectRef object,
66 + JSObjectRef thisObject,
67 + size_t argumentCount,
68 + const JSValueRef arguments[],
69 + JSValueRef *exception
70 +) {
71 + for (int i = 0; i < argumentCount; i++) {
72 + if (i != 0) {
73 + printf(" ");
74 + }
75 + fprint_value(stdout, context, arguments[i]);
76 + }
77 + printf("\n");
78 + return JSValueMakeUndefined(context);
79 +}
80 +
81 +static JSValueRef js_perf_counters_init(
82 + JSContextRef context,
83 + JSObjectRef object,
84 + JSObjectRef thisObject,
85 + size_t argumentCount,
86 + const JSValueRef arguments[],
87 + JSValueRef *exception
88 +) {
89 + // TODO: Allow customizing recorded events
90 + bool enable = true;
91 + std::string events = "";
92 + bool recordSubprocesses = false;
93 + HardwareCounter::Init(enable, events, recordSubprocesses);
94 + HardwareCounter::s_counter.getCheck();
95 +
96 + return JSValueMakeUndefined(context);
97 +}
98 +
99 +static JSValueRef js_perf_counters_get_counters(
100 + JSContextRef context,
101 + JSObjectRef object,
102 + JSObjectRef thisObject,
103 + size_t argumentCount,
104 + const JSValueRef arguments[],
105 + JSValueRef *exception
106 +) {
107 + JSObjectRef result = JSObjectMake(context, NULL, NULL);
108 + std::pair<JSContextRef, JSObjectRef> pair(context, result);
109 +
110 + HardwareCounter::GetPerfEvents(
111 + [](const std::string& key, int64_t value, void* data) {
112 + std::pair<JSContextRef, JSObjectRef>& pair =
113 + *reinterpret_cast<std::pair<JSContextRef, JSObjectRef>*>(data);
114 + JSContextRef context = pair.first;
115 + JSObjectRef result = pair.second;
116 +
117 + JSObjectSetProperty(
118 + context,
119 + result,
120 + JSStringCreateWithUTF8CString(key.c_str()),
121 + JSValueMakeNumber(context, value),
122 + kJSPropertyAttributeNone,
123 + NULL
124 + );
125 + },
126 + &pair);
127 +
128 + return result;
129 +}
130 +
131 +int main(int argc, char **argv) {
132 + if (argc != 2) {
133 + fprintf(stderr, "usage: jsc-runner file\n");
134 + exit(1);
135 + }
136 +
137 + char *filename = argv[1];
138 + std::ifstream ifs(filename);
139 + if (ifs.fail()) {
140 + std::cerr << "Error opening \"" << filename << "\": " << strerror(errno) << "\n";
141 + exit(1);
142 + }
143 + std::string script(
144 + (std::istreambuf_iterator<char>(ifs)),
145 + (std::istreambuf_iterator<char>())
146 + );
147 + JSStringRef jsScript = JSStringCreateWithUTF8CString(script.c_str());
148 + JSStringRef jsURL = JSStringCreateWithUTF8CString(argv[1]);
149 +
150 + JSGlobalContextRef ctx = JSGlobalContextCreate(NULL);
151 + add_native_hook(
152 + ctx,
153 + JSContextGetGlobalObject(ctx),
154 + "print",
155 + js_print
156 + );
157 +
158 + JSObjectRef jsPerfCounters = JSObjectMake(ctx, NULL, NULL);
159 + add_native_hook(
160 + ctx,
161 + jsPerfCounters,
162 + "init",
163 + js_perf_counters_init
164 + );
165 + add_native_hook(
166 + ctx,
167 + jsPerfCounters,
168 + "getCounters",
169 + js_perf_counters_get_counters
170 + );
171 + JSObjectSetProperty(
172 + ctx,
173 + JSContextGetGlobalObject(ctx),
174 + JSStringCreateWithUTF8CString("PerfCounters"),
175 + jsPerfCounters,
176 + kJSPropertyAttributeNone,
177 + NULL
178 + );
179 +
180 + JSValueRef jsError = NULL;
181 + JSValueRef result = JSEvaluateScript(
182 + ctx,
183 + jsScript,
184 + NULL,
185 + jsURL,
186 + 0,
187 + &jsError
188 + );
189 + if (!result) {
190 + fprintf(stderr, "Exception: ");
191 + fprint_value(stderr, ctx, jsError);
192 + fprintf(stderr, "\n");
193 + JSStringRef jsStackStr = JSStringCreateWithUTF8CString("stack");
194 + if (JSValueIsObject(ctx, jsError)) {
195 + JSValueRef jsStack = JSObjectGetProperty(ctx, (JSObjectRef)jsError, jsStackStr, NULL);
196 + JSStringRelease(jsStackStr);
197 + fprint_value(stderr, ctx, jsStack);
198 + fprintf(stderr, "\n");
199 + }
200 + exit(1);
201 + }
202 +
203 + JSGlobalContextRelease(ctx);
204 +}