Add a JIT stats object in the shell

This commit is contained in:
Brian Crowder 2008-09-19 22:47:58 -04:00
parent 4b972f730f
commit d87b65397b
3 changed files with 140 additions and 24 deletions

View File

@ -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':

View File

@ -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)

View File

@ -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(","));