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
+}