Randomize penalties for aborts and add blacklisting.

This commit is contained in:
Mike Pall 2010-02-23 18:27:39 +01:00
parent d5c8fe4b90
commit 8ae2f9feaa
6 changed files with 50 additions and 23 deletions

View File

@ -203,7 +203,7 @@ Here are the parameters and their default settings:
<tr class="odd"> <tr class="odd">
<td class="param_name">maxsnap</td><td class="param_default">100</td><td class="param_desc">Max. number of snapshots for a trace</td></tr> <td class="param_name">maxsnap</td><td class="param_default">100</td><td class="param_desc">Max. number of snapshots for a trace</td></tr>
<tr class="even separate"> <tr class="even separate">
<td class="param_name">hotloop</td><td class="param_default">57</td><td class="param_desc">Number of iterations to detect a hot loop</td></tr> <td class="param_name">hotloop</td><td class="param_default">56</td><td class="param_desc">Number of iterations to detect a hot loop or hot call</td></tr>
<tr class="odd"> <tr class="odd">
<td class="param_name">hotexit</td><td class="param_default">10</td><td class="param_desc">Number of taken exits to start a side trace</td></tr> <td class="param_name">hotexit</td><td class="param_default">10</td><td class="param_desc">Number of taken exits to start a side trace</td></tr>
<tr class="even"> <tr class="even">
@ -214,9 +214,11 @@ Here are the parameters and their default settings:
<td class="param_name">loopunroll</td><td class="param_default">7</td><td class="param_desc">Max. unroll factor for loop ops in side traces</td></tr> <td class="param_name">loopunroll</td><td class="param_default">7</td><td class="param_desc">Max. unroll factor for loop ops in side traces</td></tr>
<tr class="odd"> <tr class="odd">
<td class="param_name">callunroll</td><td class="param_default">3</td><td class="param_desc">Max. unroll factor for pseudo-recursive calls</td></tr> <td class="param_name">callunroll</td><td class="param_default">3</td><td class="param_desc">Max. unroll factor for pseudo-recursive calls</td></tr>
<tr class="even separate"> <tr class="even">
<td class="param_name">recunroll</td><td class="param_default">2</td><td class="param_desc">Min. unroll factor for true recursion</td></tr>
<tr class="odd separate">
<td class="param_name">sizemcode</td><td class="param_default">32</td><td class="param_desc">Size of each machine code area in KBytes (Windows: 64K)</td></tr> <td class="param_name">sizemcode</td><td class="param_default">32</td><td class="param_desc">Size of each machine code area in KBytes (Windows: 64K)</td></tr>
<tr class="odd"> <tr class="even">
<td class="param_name">maxmcode</td><td class="param_default">512</td><td class="param_desc">Max. total size of all machine code areas in KBytes</td></tr> <td class="param_name">maxmcode</td><td class="param_default">512</td><td class="param_desc">Max. total size of all machine code areas in KBytes</td></tr>
</table> </table>
<br class="flush"> <br class="flush">

View File

@ -19,8 +19,6 @@ typedef uint16_t HotCount;
/* Number of hot counter hash table entries (must be a power of two). */ /* Number of hot counter hash table entries (must be a power of two). */
#define HOTCOUNT_SIZE 64 #define HOTCOUNT_SIZE 64
#define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount)) #define HOTCOUNT_PCMASK ((HOTCOUNT_SIZE-1)*sizeof(HotCount))
#define HOTCOUNT_MIN_PENALTY 103
#define HOTCOUNT_MAX_PENALTY 60000
/* This solves a circular dependency problem -- bump as needed. Sigh. */ /* This solves a circular dependency problem -- bump as needed. Sigh. */
#define GG_NUM_ASMFF 62 #define GG_NUM_ASMFF 62

View File

@ -69,14 +69,14 @@
_(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \ _(\007, maxside, 100) /* Max. # of side traces of a root trace. */ \
_(\007, maxsnap, 100) /* Max. # of snapshots for a trace. */ \ _(\007, maxsnap, 100) /* Max. # of snapshots for a trace. */ \
\ \
_(\007, hotloop, 57) /* # of iterations to detect a hot loop. */ \ _(\007, hotloop, 56) /* # of iter. to detect a hot loop/call. */ \
_(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \ _(\007, hotexit, 10) /* # of taken exits to start a side trace. */ \
_(\007, tryside, 4) /* # of attempts to compile a side trace. */ \ _(\007, tryside, 4) /* # of attempts to compile a side trace. */ \
\ \
_(\012, instunroll, 4) /* Max. unroll for instable loops. */ \ _(\012, instunroll, 4) /* Max. unroll for instable loops. */ \
_(\012, loopunroll, 7) /* Max. unroll for loop ops in side traces. */ \ _(\012, loopunroll, 7) /* Max. unroll for loop ops in side traces. */ \
_(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \ _(\012, callunroll, 3) /* Max. unroll for recursive calls. */ \
_(\011, recunroll, 2) /* Max. unroll for true recursion. */ \ _(\011, recunroll, 2) /* Min. unroll for true recursion. */ \
\ \
/* Size of each machine code area (in KBytes). */ \ /* Size of each machine code area (in KBytes). */ \
_(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \ _(\011, sizemcode, JIT_P_sizemcode_DEFAULT) \
@ -181,13 +181,15 @@ typedef struct Trace {
/* Round-robin penalty cache for bytecodes leading to aborted traces. */ /* Round-robin penalty cache for bytecodes leading to aborted traces. */
typedef struct HotPenalty { typedef struct HotPenalty {
const BCIns *pc; /* Starting bytecode PC. */ MRef pc; /* Starting bytecode PC. */
uint16_t val; /* Penalty value, i.e. hotcount start. */ uint16_t val; /* Penalty value, i.e. hotcount start. */
uint16_t reason; /* Abort reason (really TraceErr). */ uint16_t reason; /* Abort reason (really TraceErr). */
} HotPenalty; } HotPenalty;
/* Number of slots for the penalty cache. Must be a power of 2. */ #define PENALTY_SLOTS 64 /* Penalty cache slot. Must be a power of 2. */
#define PENALTY_SLOTS 16 #define PENALTY_MIN 36 /* Minimum penalty value. */
#define PENALTY_MAX 60000 /* Maximum penalty value. */
#define PENALTY_RNDBITS 4 /* # of random bits to add to penalty value. */
/* Round-robin backpropagation cache for narrowing conversions. */ /* Round-robin backpropagation cache for narrowing conversions. */
typedef struct BPropEntry { typedef struct BPropEntry {
@ -264,6 +266,7 @@ typedef struct jit_State {
HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */ HotPenalty penalty[PENALTY_SLOTS]; /* Penalty slots. */
uint32_t penaltyslot; /* Round-robin index into penalty slots. */ uint32_t penaltyslot; /* Round-robin index into penalty slots. */
uint32_t prngstate; /* PRNG state for penalty randomization. */
BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */ BPropEntry bpropcache[BPROP_SLOTS]; /* Backpropagation cache slots. */
uint32_t bpropslot; /* Round-robin index into bpropcache slots. */ uint32_t bpropslot; /* Round-robin index into bpropcache slots. */

View File

@ -419,9 +419,9 @@ static int innerloopleft(jit_State *J, const BCIns *pc)
{ {
ptrdiff_t i; ptrdiff_t i;
for (i = 0; i < PENALTY_SLOTS; i++) for (i = 0; i < PENALTY_SLOTS; i++)
if (J->penalty[i].pc == pc) { if (mref(J->penalty[i].pc, const BCIns) == pc) {
if (J->penalty[i].reason == LJ_TRERR_LLEAVE && if (J->penalty[i].reason == LJ_TRERR_LLEAVE &&
J->penalty[i].val >= 2*HOTCOUNT_MIN_PENALTY) J->penalty[i].val >= 2*PENALTY_MIN)
return 1; return 1;
break; break;
} }
@ -2149,7 +2149,7 @@ void lj_record_ins(jit_State *J)
case BC_ILOOP: case BC_ILOOP:
case BC_IFUNCF: case BC_IFUNCF:
case BC_IFUNCV: case BC_IFUNCV:
lj_trace_err(J, LJ_TRERR_LBLACKL); lj_trace_err(J, LJ_TRERR_BLACKL);
break; break;
case BC_JMP: case BC_JMP:

View File

@ -294,27 +294,50 @@ void lj_trace_freestate(global_State *g)
lj_mem_freevec(g, J->trace, J->sizetrace, Trace *); lj_mem_freevec(g, J->trace, J->sizetrace, Trace *);
} }
/* -- Trace compiler state machine ---------------------------------------- */ /* -- Penalties and blacklisting ------------------------------------------ */
/* Penalize a bytecode instruction by bumping its hot counter. */ /* Trivial PRNG for randomization of penalties. */
static void hotpenalty(jit_State *J, const BCIns *pc, TraceError e) static uint32_t penalty_prng(jit_State *J, int bits)
{ {
uint32_t i, val = HOTCOUNT_MIN_PENALTY; /* Yes, this LCG is very weak, but that doesn't matter for our use case. */
J->prngstate = J->prngstate * 1103515245 + 12345;
return J->prngstate >> (32-bits);
}
/* Blacklist a bytecode instruction. */
static void blacklist_pc(GCproto *pt, BCIns *pc)
{
setbc_op(pc, (int)bc_op(*pc)+(int)BC_ILOOP-(int)BC_LOOP);
pt->flags |= PROTO_HAS_ILOOP;
}
/* Penalize a bytecode instruction. */
static void penalty_pc(jit_State *J, GCproto *pt, BCIns *pc, TraceError e)
{
uint32_t i, val = PENALTY_MIN;
for (i = 0; i < PENALTY_SLOTS; i++) for (i = 0; i < PENALTY_SLOTS; i++)
if (J->penalty[i].pc == pc) { if (mref(J->penalty[i].pc, const BCIns) == pc) { /* Cache slot found? */
val = ((uint32_t)J->penalty[i].val << 1) + 1; /* First try to bump its hotcount several times. */
if (val > HOTCOUNT_MAX_PENALTY) val = HOTCOUNT_MAX_PENALTY; val = ((uint32_t)J->penalty[i].val << 1) +
penalty_prng(J, PENALTY_RNDBITS);
if (val > PENALTY_MAX) {
blacklist_pc(pt, pc); /* Blacklist it, if that didn't help. */
return;
}
goto setpenalty; goto setpenalty;
} }
/* Assign a new penalty cache slot. */
i = J->penaltyslot; i = J->penaltyslot;
J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1); J->penaltyslot = (J->penaltyslot + 1) & (PENALTY_SLOTS-1);
J->penalty[i].pc = pc; setmref(J->penalty[i].pc, pc);
setpenalty: setpenalty:
J->penalty[i].val = (uint16_t)val; J->penalty[i].val = (uint16_t)val;
J->penalty[i].reason = e; J->penalty[i].reason = e;
hotcount_set(J2GG(J), pc+1, val); hotcount_set(J2GG(J), pc+1, val);
} }
/* -- Trace compiler state machine ---------------------------------------- */
/* Start tracing. */ /* Start tracing. */
static void trace_start(jit_State *J) static void trace_start(jit_State *J)
{ {
@ -433,8 +456,9 @@ static int trace_abort(jit_State *J)
J->state = LJ_TRACE_ASM; J->state = LJ_TRACE_ASM;
return 1; /* Retry ASM with new MCode area. */ return 1; /* Retry ASM with new MCode area. */
} }
/* Penalize or blacklist starting bytecode instruction. */
if (J->parent == 0) if (J->parent == 0)
hotpenalty(J, J->startpc, e); /* Penalize starting instruction. */ penalty_pc(J, &gcref(J->cur.startpt)->pt, (BCIns *)J->startpc, e);
if (J->curtrace) { /* Is there anything to abort? */ if (J->curtrace) { /* Is there anything to abort? */
ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */ ptrdiff_t errobj = savestack(L, L->top-1); /* Stack may be resized. */
lj_vmevent_send(L, TRACE, lj_vmevent_send(L, TRACE,

View File

@ -10,13 +10,13 @@ TREDEF(RECERR, "error thrown or hook called during recording")
TREDEF(TRACEOV, "trace too long") TREDEF(TRACEOV, "trace too long")
TREDEF(STACKOV, "trace too deep") TREDEF(STACKOV, "trace too deep")
TREDEF(SNAPOV, "too many snapshots") TREDEF(SNAPOV, "too many snapshots")
TREDEF(BLACKL, "blacklisted")
TREDEF(NYIBC, "NYI: bytecode %d") TREDEF(NYIBC, "NYI: bytecode %d")
/* Recording loop ops. */ /* Recording loop ops. */
TREDEF(LLEAVE, "leaving loop in root trace") TREDEF(LLEAVE, "leaving loop in root trace")
TREDEF(LINNER, "inner loop in root trace") TREDEF(LINNER, "inner loop in root trace")
TREDEF(LUNROLL, "loop unroll limit reached") TREDEF(LUNROLL, "loop unroll limit reached")
TREDEF(LBLACKL, "blacklisted loop")
/* Recording calls/returns. */ /* Recording calls/returns. */
TREDEF(BADTYPE, "bad argument type") TREDEF(BADTYPE, "bad argument type")