Alexander Gall
2014-09-30 07:34:31 UTC
I'm currently working on an implementation of a pure Lua Bloom filter for
the Snabb Switch project (https://github.com/SnabbCo/snabbswitch, my code
isn't public yet, though). I just spent a week puzzling over extremely
weird anomalies of my code that only occurs when it is compiled. I could
finally narrow it down to the attached simple standalone program, which is
a variant of the Murmur3 hash function. In particular, it's a simplified
version of MurmurHash3_x64_128 as per the reference implementation at
https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp,
applicable to one-byte values.
The code was distilled down to the bare minimum that exhibits a similar
anomaly as my Bloom filter code, namely that it behaves differently when it
is compiled as when it is not compiled. What it does is simply hashing the
one-byte value 0x01 15 times in a loop and comapring the lowest 32 bits of
the 128-bit hash value to the expected number 0x8374fe16 (the code is not
endian-save, so if you run it on a big-endian machine, that number will
differ).
The manner in which the hash value is stored and accessed from the loop may
look weird, but it should work correctly when compiled nevertheless, I
believe.
When executed with the compiler turned off, all is fine
$ luajit -v
LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/
$ luajit -joff murmur.lua
All fine
But with JIT turned on
$ luajit -jon murmur.lua
Expected 8374fe16, got 8374fe16 12 true deadbeef
Expected 8374fe16, got 8374fe16 13 true deadbeef
Expected 8374fe16, got 8374fe16 14 true deadbeef
Expected 8374fe16, got 8374fe16 15 true deadbeef
Note that I use hotloop=10. Changing this will cause the effect to be
delayed until the number of iterations exceeds the value of of that
parameter. This is clearly due to the fact the code is interpreted up to
that point and thus works as expected.
What seems to be happening is that as soon as the loop is compiled, the
assignment of the variable foo as well as the expression in the if
statement operate on the value that was set before the hash is calculated.
However, that value is always overwritten by the hash function.
The effect disappears if any of the following optimizations are turned off:
fold, cse, fwd. This is why I suspect a bug in the JIT optimizer code.
I checked the current HEAD of the v2.1 branch as well as random older
versions of that branch. All of them exhibit this problem.
Any insights would be highly appreciated.
the Snabb Switch project (https://github.com/SnabbCo/snabbswitch, my code
isn't public yet, though). I just spent a week puzzling over extremely
weird anomalies of my code that only occurs when it is compiled. I could
finally narrow it down to the attached simple standalone program, which is
a variant of the Murmur3 hash function. In particular, it's a simplified
version of MurmurHash3_x64_128 as per the reference implementation at
https://code.google.com/p/smhasher/source/browse/trunk/MurmurHash3.cpp,
applicable to one-byte values.
The code was distilled down to the bare minimum that exhibits a similar
anomaly as my Bloom filter code, namely that it behaves differently when it
is compiled as when it is not compiled. What it does is simply hashing the
one-byte value 0x01 15 times in a loop and comapring the lowest 32 bits of
the 128-bit hash value to the expected number 0x8374fe16 (the code is not
endian-save, so if you run it on a big-endian machine, that number will
differ).
The manner in which the hash value is stored and accessed from the loop may
look weird, but it should work correctly when compiled nevertheless, I
believe.
When executed with the compiler turned off, all is fine
$ luajit -v
LuaJIT 2.1.0-alpha -- Copyright (C) 2005-2014 Mike Pall. http://luajit.org/
$ luajit -joff murmur.lua
All fine
But with JIT turned on
$ luajit -jon murmur.lua
Expected 8374fe16, got 8374fe16 12 true deadbeef
Expected 8374fe16, got 8374fe16 13 true deadbeef
Expected 8374fe16, got 8374fe16 14 true deadbeef
Expected 8374fe16, got 8374fe16 15 true deadbeef
Note that I use hotloop=10. Changing this will cause the effect to be
delayed until the number of iterations exceeds the value of of that
parameter. This is clearly due to the fact the code is interpreted up to
that point and thus works as expected.
What seems to be happening is that as soon as the loop is compiled, the
assignment of the variable foo as well as the expression in the if
statement operate on the value that was set before the hash is calculated.
However, that value is always overwritten by the hash function.
The effect disappears if any of the following optimizations are turned off:
fold, cse, fwd. This is why I suspect a bug in the JIT optimizer code.
I checked the current HEAD of the v2.1 branch as well as random older
versions of that branch. All of them exhibit this problem.
Any insights would be highly appreciated.
--
Alex
Alex