Skip to content

Commit

Permalink
Speed up jl_egal
Browse files Browse the repository at this point in the history
jl_egal is an exported and recursively called function which puts
some constraints on the optimizer.  The way jl_egal is currently
structured it pretty much as all the code needed for the comparisons
inlined, including the more complex parts to compare tuples and
fields.  The code goes to great length to optimize special cases
which can be treated simpler but the generalization of the rest of
the code causes problems.

Specifically, the more complex parts of the comparison process require
more registers for the optimized code to use.  The results in the
function starting with a large prologue which saves all the callee-save
registers that are used, followed in the end by the respective epilogue.

This means that even though in some cases the function will almost
immediately return because of the special case handling, all the work
for of the prologue and epilogue still has to be done.

I ran limited profiling (mostly the arrayops test case) and the jl_egal
function shows up on position 3 with 5.48%.  With the simple change in
this patch this is reduced to 4.64%.

The patch is trivial, no real code changes.  To prevent the complex
prologue/epilogue from unconditionally bing created the complex code
blocks are moved into their own functions and then these functions are
called.  To prevent the optimizer from negating this work the functions
must be marked appropriately.  Fortunately I've found that this is
already done in some cases elsewhere in the code base so I'm sure the
change will not create any problem.
  • Loading branch information
drepper committed Jan 12, 2015
1 parent 6402cf8 commit 89f3b58
Showing 1 changed file with 46 additions and 27 deletions.
73 changes: 46 additions & 27 deletions src/builtins.c
Original file line number Diff line number Diff line change
Expand Up @@ -205,37 +205,30 @@ static int bits_equal(void *a, void *b, int sz)
}
}

int jl_egal(jl_value_t *a, jl_value_t *b)
#if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_)
static int __declspec(noinline)
#else
static int __attribute__((noinline))
#endif
compare_tuple(jl_value_t *a, jl_value_t *b)
{
if (a == b)
return 1;
jl_value_t *ta = (jl_value_t*)jl_typeof(a);
if (ta != (jl_value_t*)jl_typeof(b))
size_t l = jl_tuple_len(a);
if (l != jl_tuple_len(b))
return 0;
if (jl_is_tuple(a)) {
size_t l = jl_tuple_len(a);
if (l != jl_tuple_len(b))
for(size_t i=0; i < l; i++) {
if (!jl_egal(jl_tupleref(a,i),jl_tupleref(b,i)))
return 0;
for(size_t i=0; i < l; i++) {
if (!jl_egal(jl_tupleref(a,i),jl_tupleref(b,i)))
return 0;
}
return 1;
}
jl_datatype_t *dt = (jl_datatype_t*)ta;
if (dt == jl_datatype_type) {
jl_datatype_t *dta = (jl_datatype_t*)a;
jl_datatype_t *dtb = (jl_datatype_t*)b;
return dta->name == dtb->name &&
jl_egal((jl_value_t*)dta->parameters, (jl_value_t*)dtb->parameters);
}
if (dt->mutabl) return 0;
size_t sz = dt->size;
if (sz == 0) return 1;
size_t nf = jl_tuple_len(dt->names);
if (nf == 0) {
return bits_equal(jl_data_ptr(a), jl_data_ptr(b), sz);
}
return 1;
}

#if defined(_OS_WINDOWS_) && !defined(_COMPILER_MINGW_)
static int __declspec(noinline)
#else
static int __attribute__((noinline))
#endif
compare_fields(jl_value_t *a, jl_value_t *b, jl_datatype_t *dt, size_t nf)
{
for (size_t f=0; f < nf; f++) {
size_t offs = dt->fields[f].offset;
char *ao = (char*)jl_data_ptr(a) + offs;
Expand All @@ -256,6 +249,32 @@ int jl_egal(jl_value_t *a, jl_value_t *b)
return 1;
}

int jl_egal(jl_value_t *a, jl_value_t *b)
{
if (a == b)
return 1;
jl_value_t *ta = (jl_value_t*)jl_typeof(a);
if (ta != (jl_value_t*)jl_typeof(b))
return 0;
if (jl_is_tuple(a))
return compare_tuple(a, b);
jl_datatype_t *dt = (jl_datatype_t*)ta;
if (dt == jl_datatype_type) {
jl_datatype_t *dta = (jl_datatype_t*)a;
jl_datatype_t *dtb = (jl_datatype_t*)b;
return dta->name == dtb->name &&
jl_egal((jl_value_t*)dta->parameters, (jl_value_t*)dtb->parameters);
}
if (dt->mutabl) return 0;
size_t sz = dt->size;
if (sz == 0) return 1;
size_t nf = jl_tuple_len(dt->names);
if (nf == 0) {
return bits_equal(jl_data_ptr(a), jl_data_ptr(b), sz);
}
return compare_fields(a, b, dt, nf);
}

JL_CALLABLE(jl_f_is)
{
JL_NARGS(is, 2, 2);
Expand Down

0 comments on commit 89f3b58

Please sign in to comment.