Commit ef27d6cb authored by Kevin Modzelewski's avatar Kevin Modzelewski

Convert many runtime functions to take llvm::StringRef

Should hopefully cut down on allocations to pass around
'const std::string&' objects (since we don't always store things
as std::strings anymore), or to calls to strlen if we pass around
const char*s.

Haven't looked yet at the calls that we embed in the llvm IR.

Here are the perf results:
  pyston django_migrate.py                  :    2.3s baseline: 2.3 (-1.7%)
  pyston django-template.py                 :   15.1s baseline: 15.4 (-1.6%)
  pyston interp2.py                         :    5.3s baseline: 6.3 (-15.1%)
  pyston raytrace.py                        :    6.1s baseline: 6.2 (-0.7%)
  pyston nbody.py                           :    8.4s baseline: 8.1 (+4.1%)
  pyston fannkuch.py                        :    7.5s baseline: 7.5 (+0.2%)
  pyston chaos.py                           :   20.2s baseline: 20.0 (+0.7%)
  pyston fasta.py                           :    5.4s baseline: 5.4 (+0.3%)
  pyston pidigits.py                        :    5.7s baseline: 5.7 (+0.0%)
  pyston richards.py                        :    2.5s baseline: 2.7 (-6.2%)
  pyston deltablue.py                       :    1.8s baseline: 1.8 (-0.0%)
  pyston (geomean-3424)                     :    5.7s baseline: 5.8 (-2.0%)

I looked into the regression in nbody.py, and it is in an unrelated piece of
code (list unpacking) that has the same assembly and gets called the same number
of times.  Maybe there's some weird cache collision.  It's an extremely small
benchmark (a single 13-line loop) so I'm happy to write it off as microbenchmark
sensitivity.  We can also optimize this if we want to; we could speculate on the
type that we are unpacking and inline the parts of the unpacking code we need.
parent 925c13d5
......@@ -959,15 +959,15 @@ Value ASTInterpreter::visit_print(AST_Print* node) {
// begin code for handling of softspace
bool new_softspace = (i < nvals - 1) || (!node->nl);
if (softspace(dest, new_softspace)) {
callattrInternal(dest, &write_str, CLASS_OR_INST, 0, ArgPassSpec(1), boxString(space_str), 0, 0, 0, 0);
callattrInternal(dest, write_str, CLASS_OR_INST, 0, ArgPassSpec(1), boxString(space_str), 0, 0, 0, 0);
}
Box* str_or_unicode_var = (var->cls == unicode_cls) ? var : str(var);
callattrInternal(dest, &write_str, CLASS_OR_INST, 0, ArgPassSpec(1), str_or_unicode_var, 0, 0, 0, 0);
callattrInternal(dest, write_str, CLASS_OR_INST, 0, ArgPassSpec(1), str_or_unicode_var, 0, 0, 0, 0);
}
if (node->nl) {
callattrInternal(dest, &write_str, CLASS_OR_INST, 0, ArgPassSpec(1), boxString(newline_str), 0, 0, 0, 0);
callattrInternal(dest, write_str, CLASS_OR_INST, 0, ArgPassSpec(1), boxString(newline_str), 0, 0, 0, 0);
if (nvals == 0) {
softspace(dest, false);
}
......
......@@ -480,18 +480,18 @@ public:
BoxedDict* getDict();
void setattr(const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(const std::string& attr, Box* val) {
void setattr(llvm::StringRef attr, Box* val, SetattrRewriteArgs* rewrite_args);
void giveAttr(llvm::StringRef attr, Box* val) {
assert(!this->hasattr(attr));
this->setattr(attr, val, NULL);
}
// getattr() does the equivalent of PyDict_GetItem(obj->dict, attr): it looks up the attribute's value on the
// object's attribute storage. it doesn't look at other objects or do any descriptor logic.
Box* getattr(const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(const std::string& attr) { return getattr(attr, NULL); }
bool hasattr(const std::string& attr) { return getattr(attr) != NULL; }
void delattr(const std::string& attr, DelattrRewriteArgs* rewrite_args);
Box* getattr(llvm::StringRef attr, GetattrRewriteArgs* rewrite_args);
Box* getattr(llvm::StringRef attr) { return getattr(attr, NULL); }
bool hasattr(llvm::StringRef attr) { return getattr(attr) != NULL; }
void delattr(llvm::StringRef attr, DelattrRewriteArgs* rewrite_args);
// Only valid for hc-backed instances:
Box* getAttrWrapper();
......
This diff is collapsed.
......@@ -53,7 +53,7 @@ extern "C" void my_assert(bool b);
extern "C" Box* getattr(Box* obj, const char* attr);
extern "C" void setattr(Box* obj, const char* attr, Box* attr_val);
extern "C" void delattr(Box* obj, const char* attr);
extern "C" void delattrGeneric(Box* obj, const std::string& attr, DelattrRewriteArgs* rewrite_args);
extern "C" void delattrGeneric(Box* obj, llvm::StringRef attr, DelattrRewriteArgs* rewrite_args);
extern "C" bool nonzero(Box* obj);
extern "C" Box* runtimeCall(Box*, ArgPassSpec, Box*, Box*, Box*, Box**, const std::vector<const std::string*>*);
extern "C" Box* callattr(Box*, const std::string*, CallattrFlags, ArgPassSpec, Box*, Box*, Box*, Box**,
......@@ -97,7 +97,7 @@ extern "C" void dump(void* p);
extern "C" void dumpEx(void* p, int levels = 0);
struct SetattrRewriteArgs;
void setattrGeneric(Box* obj, const std::string& attr, Box* val, SetattrRewriteArgs* rewrite_args);
void setattrGeneric(Box* obj, llvm::StringRef attr, Box* val, SetattrRewriteArgs* rewrite_args);
struct BinopRewriteArgs;
extern "C" Box* binopInternal(Box* lhs, Box* rhs, int op_type, bool inplace, BinopRewriteArgs* rewrite_args);
......@@ -119,27 +119,26 @@ enum LookupScope {
INST_ONLY = 2,
CLASS_OR_INST = 3,
};
extern "C" Box* callattrInternal(Box* obj, const std::string* attr, LookupScope, CallRewriteArgs* rewrite_args,
extern "C" Box* callattrInternal(Box* obj, llvm::StringRef attr, LookupScope, CallRewriteArgs* rewrite_args,
ArgPassSpec argspec, Box* arg1, Box* arg2, Box* arg3, Box** args,
const std::vector<const std::string*>* keyword_names);
extern "C" void delattr_internal(Box* obj, const std::string& attr, bool allow_custom,
DelattrRewriteArgs* rewrite_args);
extern "C" void delattr_internal(Box* obj, llvm::StringRef attr, bool allow_custom, DelattrRewriteArgs* rewrite_args);
struct CompareRewriteArgs;
Box* compareInternal(Box* lhs, Box* rhs, int op_type, CompareRewriteArgs* rewrite_args);
// This is the equivalent of PyObject_GetAttr. Unlike getattrInternalGeneric, it checks for custom __getattr__ or
// __getattribute__ methods.
Box* getattrInternal(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* getattrInternal(Box* obj, llvm::StringRef attr, GetattrRewriteArgs* rewrite_args);
// This is the equivalent of PyObject_GenericGetAttr, which performs the default lookup rules for getattr() (check for
// data descriptor, check for instance attribute, check for non-data descriptor). It does not check for __getattr__ or
// __getattribute__.
Box* getattrInternalGeneric(Box* obj, const std::string& attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
Box* getattrInternalGeneric(Box* obj, llvm::StringRef attr, GetattrRewriteArgs* rewrite_args, bool cls_only,
bool for_call, Box** bind_obj_out, RewriterVar** r_bind_obj_out);
// This is the equivalent of _PyType_Lookup(), which calls Box::getattr() on each item in the object's MRO in the
// appropriate order. It does not do any descriptor logic.
Box* typeLookup(BoxedClass* cls, const std::string& attr, GetattrRewriteArgs* rewrite_args);
Box* typeLookup(BoxedClass* cls, llvm::StringRef attr, GetattrRewriteArgs* rewrite_args);
extern "C" void raiseAttributeErrorStr(const char* typeName, const char* attr) __attribute__((__noreturn__));
extern "C" void raiseAttributeError(Box* obj, const char* attr) __attribute__((__noreturn__));
......
......@@ -1653,7 +1653,7 @@ public:
BoxedDict* dict = (BoxedDict*)AttrWrapper::copy(_self);
assert(dict->cls == dict_cls);
const std::string eq_str = "__eq__";
return callattrInternal(dict, &eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), _other, NULL, NULL, NULL,
return callattrInternal(dict, eq_str, LookupScope::CLASS_ONLY, NULL, ArgPassSpec(1), _other, NULL, NULL, NULL,
NULL);
}
......
......@@ -239,8 +239,7 @@ public:
int weaklist_offset, int instance_size, bool is_user_defined, BoxedString* name,
BoxedTuple* bases, size_t nslots);
static BoxedHeapClass* create(BoxedClass* metatype, BoxedClass* base, gcvisit_func gc_visit, int attrs_offset,
int weaklist_offset, int instance_size, bool is_user_defined,
const std::string& name);
int weaklist_offset, int instance_size, bool is_user_defined, llvm::StringRef name);
private:
// These functions are not meant for external callers and will mostly just be called
......@@ -354,10 +353,10 @@ public:
}
// Only valid for NORMAL hidden classes:
HiddenClass* getOrMakeChild(const std::string& attr);
HiddenClass* getOrMakeChild(llvm::StringRef attr);
// Only valid for NORMAL or SINGLETON hidden classes:
int getOffset(const std::string& attr) {
int getOffset(llvm::StringRef attr) {
assert(type == NORMAL || type == SINGLETON);
auto it = attr_offsets.find(attr);
if (it == attr_offsets.end())
......@@ -380,7 +379,7 @@ public:
HiddenClass* getAttrwrapperChild();
// Only valid for NORMAL hidden classes:
HiddenClass* delAttrToMakeHC(const std::string& attr);
HiddenClass* delAttrToMakeHC(llvm::StringRef attr);
};
class BoxedInt : public Box {
......
......@@ -6,7 +6,7 @@ def tally(fn):
for l in open(fn):
samples = int(l.split()[3])
func = l.split()[-1]
counts[func] = samples
counts[func] = counts.get(func, 0) + samples
return counts
......
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