-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allocator alignment problems - remove it? #452
Conversation
@MichaelRawson, how did you get your second column vampire - was it simply via |
No, To get the right-hand column, in this branch I manually removed |
So in my randomized setup, a discount10 strategy running for 50000Mi would lose around 80 problems (from first-order TPTP) on average. This was done just with the USE_SYSTEM_ALLOCATION=1 switch. But generally, I would be hesitant to endorse such a degradation "just to be" standard complying. (Do we know what is the alignment important on the compiler side?) Having said that, here is a thought. With the TermList/Term representation in Vampire, we are ourselves relying on Term pointers to be 4-byte aligned (and use the two lowest bits for tagging). Since you brought up the issue with no alignment guarantee by |
Interesting - and not as bad as I feared. Thanks for running the experiment so quickly!
Fair enough - it's arguably the major problem with this line of thinking. It might be possible to claw something back with some targeted optimisation if we knew what causes the slowdown - any ideas? I'll look into that.
The
I'm parsing this as "Why is alignment important for the compiler?" - sorry for condescension if I misunderstood. Alignment is important for compilers - some architectures cannot do unaligned loads/stores, and for some it's inefficient, so the compiler has to work out if some data is aligned, and work around it if it is not. Intel is actually pretty permissive in this respect, it can do both and in most cases there's not much difference in terms of performance. Architectures may have separate aligned/unaligned instructions - e.g. As a result, e.g. Clang will emit aligned instructions by preference if it can prove that something "should" (in a standard-compliant program) be aligned. If it turns out not to be aligned, even Intel chips will fault and the program will crash immediately. Contrived example: https://godbolt.org/z/r36Y5Kqj5 - if Vampire did not put the allocation on a 16-byte boundary, we'd crash here. |
An update - I will try to implement a less-complex allocator that is both standards-compliant and doesn't have a performance hit. If I succeed I will close this and open a new PR for that one. If not, we can return to this. |
38837bb
to
7e25f7f
Compare
8c1a4c5
to
732afe7
Compare
9676d32
to
db1e34c
Compare
This reverts commit 9eccf67. Not actually necessary with USE_SYSTEM_ALLOCATION!
Not intended for merge.
Recently I started running a sanitizer for undefined behaviour (
-fsanitize=undefined
) and to my surprise there are relatively few issues, mostly easy to fix.Unfortunately, one of them is not so easy: Vampire's allocator returns memory that is not sufficiently aligned for some objects.
Allocator
seems to align to pointer-sized (8 bytes on my machine) boundaries, but some types - for examplestd::ifstream
- have larger alignment requirements. So far I've seen up tostd::max_align_t
(16 bytes), but even greater alignment is theoretically possible, so-called "over-aligned" types.There are several possible approaches here:
Allocator
anyway.Allocator
by always aligning tostd::max_align_t
intervals. This is what the standard says it must do, but I suspect carries some performance hit as each allocation must take up at least 16 bytes. It will also not work with over-aligned types, should these be necessary in future. System allocators tend to support over-aligned types: the GNU C++ environment supports over-aligned types with-faligned-new
, switched on by default from C++17.Allocator
by working out what the alignment should be (or falling back toalignof(std::max_align_t)
) and allocating with variable alignment. I tried this yesterday! Wiring up Vampire this way is possible if tedious, but changingAllocator
to handle variably-aligned allocations seems near-impossible in the current implementation and would amount to a rewrite, possibly introducing significant slowdown along the way.Allocator
and use the system allocator instead. This is what this PR does - the minimal change required to fall back to the system allocator. If we go down this route we should also change some other things, such as removing the need forSTLAllocator
,vvector
and friends, and possibly removing e.g.USE_ALLOCATOR
from the whole source tree. Pros and cons discussed below.Solutions (2) or (4) seem promising, but we will probably have to accept some slowdown in either case. (2) is more conservative, but as you can tell, I'm considering (4). This has disadvantages:
But also some advantages:
Allocator
suitably.BYPASSING_ALLOCATOR
whack-a-mole. This is not such a big deal for seasoned Vampire hackers, but new contributors consistently run into this. This is not as simple as "just useLib::Stack
rather thanstd::vector
" - calling almost anything instd
might allocate if you are not careful, like I/O routines. We also have to patch or work around third-party code like MiniSat or Z3.USE_ALLOCATOR
oddities.In summary, there is a bug wandering around, and it will most likely bite us eventually. In my view the best solution is to remove
Allocator
and use the system allocator, like the majority of other programs. There is a performance hit, but in exchange we get significant convenience and the system allocator is fully correct.I'd like your thoughts on this.
To attempt to quantify the performance hit, I ran 10-second DISCOUNT runs on a random subset of TPTP until Michaela started complaining about the fan noise. Log attached - format is
problem master system-allocator
, problems where neither solved it are removed.comparison.txt