зеркало из https://github.com/mozilla/pjs.git
Bytecode succession metering (363529, r=crowder).
This commit is contained in:
Родитель
4542b94f81
Коммит
a96f565dbe
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче