Bytecode succession metering (363529, r=crowder).

This commit is contained in:
brendan%mozilla.org 2006-12-20 07:47:22 +00:00
Родитель 4542b94f81
Коммит a96f565dbe
2 изменённых файлов: 115 добавлений и 1 удалений

Просмотреть файл

@ -786,6 +786,12 @@ JS_DestroyRuntime(JSRuntime *rt)
JS_PUBLIC_API(void)
JS_ShutDown(void)
{
#ifdef JS_OPMETER
extern void js_DumpOpPairMeter();
js_DumpOpPairMeter();
#endif
js_FinishDtoa();
#ifdef JS_THREADSAFE
js_CleanupLocks();

Просмотреть файл

@ -2046,6 +2046,111 @@ InternNonIntElementId(JSContext *cx, jsval idval, jsid *idp)
# undef JS_THREADED_INTERP
#endif
/*
* Define JS_OPMETER to instrument bytecode succession, generating a .dot file
* on shutdown that shows the graph of significant predecessor/successor pairs
* executed, where the edge labels give the succession counts. The .dot file
* is named by the JS_OPMETER_FILE envariable, and defaults to /tmp/ops.dot.
*/
#ifndef JS_OPMETER
# define METER_OP_INIT(op) /* nothing */
# define METER_OP_PAIR(op1, op2) /* nothing */
#else
# include <stdlib.h>
/*
* The second dimension is hardcoded at 256 because we know that many bits fit
* in a byte, and mainly to optimize away multiplying by JSOP_LIMIT to address
* any particular row.
*/
static uint32 succeeds[JSOP_LIMIT][256];
# define METER_OP_INIT(op) ((op) = JSOP_STOP)
# define METER_OP_PAIR(op1,op2) ((op1) != JSOP_STOP && ++succeeds[op1][op2])
typedef struct Edge {
const char *from;
const char *to;
uint32 count;
} Edge;
static int
compare_edges(const void *a, const void *b)
{
const Edge *ea = (const Edge *) a;
const Edge *eb = (const Edge *) b;
return (int32)eb->count - (int32)ea->count;
}
void
js_DumpOpPairMeter()
{
const char *name, *from, *style;
FILE *fp;
uint32 total, count;
uint32 i, j, nedges;
Edge *graph;
name = getenv("JS_OPMETER_FILE");
if (!name)
name = "/tmp/ops.dot";
fp = fopen(name, "w");
if (!fp) {
perror(name);
return;
}
total = nedges = 0;
for (i = 0; i < JSOP_LIMIT; i++) {
for (j = 0; j < JSOP_LIMIT; j++) {
count = succeeds[i][j];
if (count != 0) {
total += count;
++nedges;
}
}
}
# define SIGNIFICANT(count,total) (200. * (count) >= (total))
graph = (Edge *) calloc(nedges, sizeof graph[0]);
for (i = nedges = 0; i < JSOP_LIMIT; i++) {
from = js_CodeSpec[i].name;
for (j = 0; j < JSOP_LIMIT; j++) {
count = succeeds[i][j];
if (count != 0 && SIGNIFICANT(count, total)) {
graph[nedges].from = from;
graph[nedges].to = js_CodeSpec[j].name;
graph[nedges].count = count;
++nedges;
}
}
}
qsort(graph, nedges, sizeof(Edge), compare_edges);
# undef SIGNIFICANT
fputs("digraph {\n", fp);
for (i = 0, style = NULL; i < nedges; i++) {
JS_ASSERT(i == 0 || graph[i-1].count >= graph[i].count);
if (!style || graph[i-1].count != graph[i].count) {
style = (i > nedges * .75) ? "dotted" :
(i > nedges * .50) ? "dashed" :
(i > nedges * .25) ? "solid" : "bold";
}
fprintf(fp, " %s -> %s [label=\"%lu\" style=%s]\n",
graph[i].from, graph[i].to,
(unsigned long)graph[i].count, style);
}
free(graph);
fputs("}\n", fp);
fclose(fp);
}
#endif /* JS_OPSMETER */
JSBool
js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
{
@ -2117,8 +2222,11 @@ js_Interpret(JSContext *cx, jsbytecode *pc, jsval *result)
register void **jumpTable = normalJumpTable;
METER_OP_INIT(op); /* to nullify first METER_OP_PAIR */
# define DO_OP() JS_EXTENSION_(goto *jumpTable[op])
# define DO_NEXT_OP(n) do { op = *(pc += (n)); DO_OP(); } while (0)
# define DO_NEXT_OP(n) do { METER_OP_PAIR(op, pc[n]); op = *(pc += (n)); \
DO_OP(); } while (0)
# define BEGIN_CASE(OP) L_##OP:
# define END_CASE(OP) DO_NEXT_OP(OP##_LENGTH);
# define END_VARLEN_CASE DO_NEXT_OP(len);