Commit ea8cb1f0 authored by Kevin Modzelewski's avatar Kevin Modzelewski

Rewriter "aggressiveness" and backoff

Add a concept of rewriter "aggressiveness" that decreases over time.
It starts off high and we will try to rewrite everything fully, but
as we succeed too often (megamorphic) or fail to rewrite, we will
decrease the aggressiveness and produce more generic rewrites.  This
means they are more likely to succeed both at the rewriting stage
and at the execution stage.
parent 6160ed80
......@@ -30,7 +30,6 @@ namespace pyston {
using namespace pyston::assembler;
#define MEGAMORPHIC_THRESHOLD 100
#define MAX_RETRY_BACKOFF 1024
// TODO not right place for this...
......@@ -121,7 +120,7 @@ void ICSlotRewrite::commit(CommitHook* hook) {
ic->times_rewritten++;
if (ic->times_rewritten == MEGAMORPHIC_THRESHOLD) {
if (ic->times_rewritten == IC_MEGAMORPHIC_THRESHOLD) {
static StatCounter megamorphic_ics("megamorphic_ics");
megamorphic_ics.log();
}
......@@ -298,6 +297,6 @@ bool ICInfo::shouldAttempt() {
}
bool ICInfo::isMegamorphic() {
return times_rewritten >= MEGAMORPHIC_THRESHOLD;
return times_rewritten >= IC_MEGAMORPHIC_THRESHOLD;
}
}
......@@ -33,6 +33,7 @@ class ICInfo;
class ICInvalidator;
#define IC_INVALDITION_HEADER_SIZE 6
#define IC_MEGAMORPHIC_THRESHOLD 100
struct ICSlotInfo {
public:
......@@ -134,6 +135,10 @@ public:
bool shouldAttempt();
bool isMegamorphic();
// For use of the rewriter for computing aggressiveness:
int percentMegamorphic() const { return times_rewritten * 100 / IC_MEGAMORPHIC_THRESHOLD; }
int percentBackedoff() const { return retry_backoff; }
friend class ICSlotRewrite;
};
......
......@@ -589,6 +589,17 @@ public:
static bool isLargeConstant(int64_t val) { return (val < (-1L << 31) || val >= (1L << 31) - 1); }
// The "aggressiveness" with which we should try to do this rewrite. It starts high, and decreases over time.
// The values are nominally in the range 0-100, with 0 being no aggressiveness and 100 being fully aggressive,
// but callers should be prepared to receive values from a larger range.
//
// It would be nice to have this be stateful so that we could support things like "Lower the aggressiveness for
// this sub-call and then increase it back afterwards".
int aggressiveness() {
const ICInfo* ic = rewrite->getICInfo();
return 100 - ic->percentBackedoff() - ic->percentMegamorphic();
}
friend class RewriterVar;
};
......
......@@ -1499,6 +1499,23 @@ Box* getattrInternalEx(Box* obj, BoxedString* attr, GetattrRewriteArgs* rewrite_
return NULL;
}
} else {
if (unlikely(rewrite_args && rewrite_args->rewriter->aggressiveness() < 20)) {
class Helper {
public:
static Box* call(Box* obj, BoxedString* attr, bool cls_only) {
return getattrInternalGeneric(obj, attr, NULL, cls_only, false, NULL, NULL);
}
};
rewrite_args->out_rtn
= rewrite_args->rewriter->call(true, (void*)Helper::call, rewrite_args->obj,
rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)),
rewrite_args->rewriter->loadConst(cls_only, Location::forArg(2)));
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr, cls_only);
}
return getattrInternalGeneric(obj, attr, rewrite_args, cls_only, for_call, bind_obj_out, r_bind_obj_out);
}
}
......@@ -1743,6 +1760,22 @@ Box* getattrInternalGeneric(Box* obj, BoxedString* attr, GetattrRewriteArgs* rew
if (!PyType_Check(obj)) {
// Look up the val in the object's dictionary and if you find it, return it.
if (unlikely(rewrite_args && !descr && obj->cls != instancemethod_cls
&& rewrite_args->rewriter->aggressiveness() < 40
&& attr->interned_state == SSTATE_INTERNED_IMMORTAL)) {
class Helper {
public:
static Box* call(Box* obj, BoxedString* attr) { return obj->getattr(attr); }
};
rewrite_args->out_rtn = rewrite_args->rewriter->call(
false, (void*)Helper::call, rewrite_args->obj,
rewrite_args->rewriter->loadConst((intptr_t)attr, Location::forArg(1)));
rewrite_args->out_success = true;
rewrite_args->out_return_convention = GetattrRewriteArgs::NOEXC_POSSIBLE;
return Helper::call(obj, attr);
}
Box* val;
RewriterVar* r_val = NULL;
if (rewrite_args) {
......@@ -1977,6 +2010,13 @@ template <ExceptionStyle S> Box* _getattrEntry(Box* obj, BoxedString* attr, void
ScopedStatTimer st(counter, 10);
#endif
if (unlikely(rewriter.get() && rewriter->aggressiveness() < 5)) {
RewriterVar* r_rtn = rewriter->call(true, (void*)_getattrEntry<S>, rewriter->getArg(0), rewriter->getArg(1),
rewriter->loadConst(0, Location::forArg(2)));
rewriter->commitReturning(r_rtn);
rewriter.reset(NULL);
}
// getattrInternal (what we call) can return NULL without setting an exception, but this function's
// convention is that an exception will need to be thrown.
// Here's a simple helper to help with that:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment