зеркало из https://github.com/mozilla/pjs.git
Add a JIT stats object in the shell
This commit is contained in:
Родитель
2919373917
Коммит
a33aa687cd
|
@ -462,6 +462,13 @@ ProcessArgs(JSContext *cx, JSObject *obj, char **argv, int argc)
|
|||
|
||||
case 'j':
|
||||
JS_ToggleOptions(cx, JSOPTION_JIT);
|
||||
#ifdef DEBUG
|
||||
extern struct JSClass jitstats_class;
|
||||
extern void js_InitJITStatsClass(JSContext *cx, JSObject *glob);
|
||||
js_InitJITStatsClass(cx, JS_GetGlobalObject(cx));
|
||||
JS_DefineObject(cx, JS_GetGlobalObject(cx), "tracemonkey",
|
||||
&jitstats_class, NULL, 0);
|
||||
#endif
|
||||
break;
|
||||
|
||||
case 'o':
|
||||
|
|
|
@ -72,9 +72,7 @@
|
|||
#include "jsautooplen.h" // generated headers last
|
||||
|
||||
/* Number of iterations of a loop where we start tracing. That is, we don't
|
||||
start tracing until the beginning of the HOTLOOP-th iteration. If you
|
||||
change this value, make sure to update all the tests in trace-test.js that
|
||||
depend on it. */
|
||||
start tracing until the beginning of the HOTLOOP-th iteration. */
|
||||
#define HOTLOOP 2
|
||||
|
||||
/* Number of times we wait to exit on a side exit before we try to extend the tree. */
|
||||
|
@ -102,13 +100,79 @@
|
|||
#endif
|
||||
|
||||
#ifdef DEBUG
|
||||
static struct {
|
||||
uint64
|
||||
recorderStarted, recorderAborted, traceCompleted, sideExitIntoInterpreter,
|
||||
typeMapMismatchAtEntry, returnToDifferentLoopHeader, traceTriggered,
|
||||
globalShapeMismatchAtEntry, treesTrashed, slotPromoted,
|
||||
unstableLoopVariable, breakLoopExits, returnLoopExits;
|
||||
struct __jitstats {
|
||||
#define JITSTAT(x) uint64 x;
|
||||
#include "jitstats.tbl"
|
||||
#undef JITSTAT
|
||||
} stat = { 0LL, };
|
||||
|
||||
JS_STATIC_ASSERT(sizeof(stat) % sizeof(uint64) == 0);
|
||||
|
||||
enum jitstat_ids {
|
||||
#define JITSTAT(x) STAT ## x ## ID,
|
||||
#include "jitstats.tbl"
|
||||
#undef JITSTAT
|
||||
};
|
||||
|
||||
static JSPropertySpec jitstats_props[] = {
|
||||
#define JITSTAT(x) { #x, STAT ## x ## ID, JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT },
|
||||
#include "jitstats.tbl"
|
||||
#undef JITSTAT
|
||||
{ 0 }
|
||||
};
|
||||
|
||||
static JSBool
|
||||
jitstats_getProperty(JSContext *cx, JSObject *obj, jsid id, jsval *vp)
|
||||
{
|
||||
int index = -1;
|
||||
|
||||
if (JSVAL_IS_STRING(id)) {
|
||||
JSString* str = JSVAL_TO_STRING(id);
|
||||
if (strcmp(JS_GetStringBytes(str), "HOTLOOP") == 0) {
|
||||
*vp = INT_TO_JSVAL(HOTLOOP);
|
||||
return JS_TRUE;
|
||||
}
|
||||
}
|
||||
|
||||
if (JSVAL_IS_INT(id))
|
||||
index = JSVAL_TO_INT(id);
|
||||
|
||||
uint64 result = 0;
|
||||
switch (index) {
|
||||
#define JITSTAT(x) case STAT ## x ## ID: result = stat.x; break;
|
||||
#include "jitstats.tbl"
|
||||
#undef JITSTAT
|
||||
default:
|
||||
*vp = JSVAL_VOID;
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
if (result < JSVAL_INT_MAX) {
|
||||
*vp = INT_TO_JSVAL(result);
|
||||
return JS_TRUE;
|
||||
}
|
||||
char retstr[64];
|
||||
snprintf(retstr, JS_ARRAY_LENGTH(retstr), "%llu", result);
|
||||
*vp = STRING_TO_JSVAL(JS_NewStringCopyZ(cx, retstr));
|
||||
return JS_TRUE;
|
||||
}
|
||||
|
||||
JSClass jitstats_class = {
|
||||
"jitstats",
|
||||
JSCLASS_HAS_PRIVATE,
|
||||
JS_PropertyStub, JS_PropertyStub,
|
||||
jitstats_getProperty, JS_PropertyStub,
|
||||
JS_EnumerateStub, JS_ResolveStub,
|
||||
JS_ConvertStub, JS_FinalizeStub,
|
||||
JSCLASS_NO_OPTIONAL_MEMBERS
|
||||
};
|
||||
|
||||
void
|
||||
js_InitJITStatsClass(JSContext *cx, JSObject *glob)
|
||||
{
|
||||
JS_InitClass(cx, glob, NULL, &jitstats_class, NULL, 0, jitstats_props, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
#define AUDIT(x) (stat.x++)
|
||||
#else
|
||||
#define AUDIT(x) ((void)0)
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
* for.
|
||||
*/
|
||||
// The HOTLOOP constant we depend on
|
||||
const HOTLOOP = 2;
|
||||
const HOTLOOP = jitstats.HOTLOOP;
|
||||
// The loop count at which we trace
|
||||
const RECORDLOOP = HOTLOOP;
|
||||
// The loop count at which we run the trace
|
||||
|
@ -17,19 +17,53 @@ var fails = [], passes=[];
|
|||
|
||||
function test(f)
|
||||
{
|
||||
if (!testName || testName == f.name)
|
||||
check(f.name, f(), f.expected);
|
||||
if (!testName || testName == f.name) {
|
||||
// Collect our jit stats
|
||||
var localJITstats = {};
|
||||
if (!f.jitstats)
|
||||
f.jitstats = null;
|
||||
for (var propName in jitstats) {
|
||||
localJITstats[propName] = jitstats[propName];
|
||||
}
|
||||
check(f.name, f(), f.expected, localJITstats, f.jitstats);
|
||||
}
|
||||
}
|
||||
|
||||
function check(desc, actual, expected)
|
||||
function check(desc, actual, expected, oldJITstats, expectedJITstats)
|
||||
{
|
||||
if (expected == actual) {
|
||||
passes.push(desc);
|
||||
return print(desc, ": passed");
|
||||
var pass = true;
|
||||
for (var propName in expectedJITstats) {
|
||||
if (expectedJITstats[propName] !=
|
||||
jitstats[propName] - oldJITstats[propName]) {
|
||||
pass = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (pass) {
|
||||
passes.push(desc);
|
||||
return print(desc, ": passed");
|
||||
}
|
||||
}
|
||||
fails.push(desc);
|
||||
print(desc, ": FAILED: expected", typeof(expected), "(", expected, ") != actual",
|
||||
typeof(actual), "(", actual, ")");
|
||||
var expectedStats = "";
|
||||
for (var propName in expectedJITstats) {
|
||||
if (expectedStats)
|
||||
expectedStats += " ";
|
||||
expectedStats += propName + ": " + expectedJITstats[propName];
|
||||
}
|
||||
var actualStats = "";
|
||||
for (var propName in expectedJITstats) {
|
||||
if (actualStats)
|
||||
actualStats += " ";
|
||||
actualStats +=
|
||||
propName + ": " + (jitstats[propName] - oldJITstats[propName]);
|
||||
}
|
||||
print(desc, ": FAILED: expected", typeof(expected), "(", expected, ")",
|
||||
(expectedStats ? " [" + expectedStats + "] " : ""),
|
||||
"!= actual",
|
||||
typeof(actual), "(", actual, ")",
|
||||
(actualStats ? " [" + actualStats + "] " : ""));
|
||||
}
|
||||
|
||||
function ifInsideLoop()
|
||||
|
@ -1337,13 +1371,6 @@ function testStrict() {
|
|||
testStrict.expected = "true,false,false,false";
|
||||
test(testStrict);
|
||||
|
||||
function testGlobalProtoAccess() {
|
||||
return "ok";
|
||||
}
|
||||
this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
|
||||
testGlobalProtoAccess.expected = "ok";
|
||||
test(testGlobalProtoAccess);
|
||||
|
||||
function testSetPropNeitherMissNorHit() {
|
||||
for (var j = 0; j < 5; ++j) { if (({}).__proto__ = 1) { } }
|
||||
return "ok";
|
||||
|
@ -1487,8 +1514,26 @@ function testNestedExitStackOuter() {
|
|||
return counter;
|
||||
}
|
||||
testNestedExitStackOuter.expected = 81;
|
||||
testNestedExitStackOuter.jitstats = {};
|
||||
testNestedExitStackOuter.jitstats.recorderStarted = 4;
|
||||
testNestedExitStackOuter.jitstats.recorderAborted = 0;
|
||||
test(testNestedExitStackOuter);
|
||||
|
||||
function testHOTLOOPSize() {
|
||||
return HOTLOOP > 1;
|
||||
}
|
||||
testHOTLOOPSize.expected = true;
|
||||
test(testHOTLOOPSize);
|
||||
|
||||
// This test has to come last, since it messes with Object.prototype
|
||||
// and thus confuses jitstats.
|
||||
function testGlobalProtoAccess() {
|
||||
return "ok";
|
||||
}
|
||||
this.__proto__.a = 3; for (var j = 0; j < 4; ++j) { [a]; }
|
||||
testGlobalProtoAccess.expected = "ok";
|
||||
test(testGlobalProtoAccess);
|
||||
|
||||
/* Keep these at the end so that we can see the summary after the trace-debug spew. */
|
||||
print("\npassed:", passes.length && passes.join(","));
|
||||
print("\nFAILED:", fails.length && fails.join(","));
|
||||
|
|
Загрузка…
Ссылка в новой задаче