-
Notifications
You must be signed in to change notification settings - Fork 14
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
Feature/tighten hash usage 2 (fixing Issues #316, #423, and probably #492) #493
base: develop
Are you sure you want to change the base?
Conversation
I saw you left DOMEASURE on in this PR. Shouldn't it be off by default? |
@MuTsunTsai, that's set in |
…herefore always decrement, just like we always increment it when allocating.
…ise usage, we may be able to work with a smaller maximum alignment than what the system would require in general. This update allows us to select such a value as a compile-time flag. This, of course, would have to be carefully tested for each such system.
I did a bit more testing on this, and I'm fairly confident that the differences I see can be ascribed to using somewhat larger memory allocations for each object. There are two factors at play here:
(1) can (now) be mitigated by manually setting the Setting |
This looks very good!
It would be helpful to understand these differences before we merge the pull request. |
DHT/dht.c
Outdated
if (KeyV==0) | ||
assert(key.value.object_pointer!=0); /* TODO: This assert assumes that object_pointer is the active member. | ||
Is there a more generic test we could do? Do we need one? */ | ||
if ((ht->procs.DupKeyValue)(key.value, &KeyV.value)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.
Before, we signaled "key duplication failed" if DupKey returned 0.
Now, we signal it if DupKeyValue doesn't.
Can this be correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It's admittedly confusing. Previously we assert
ed that key
is non-NULL
, so now I assert
that key
's stored object pointer is non-NULL
. I've replaced the previous call to DupKey
with a call to DupKeyValue
, which is specified to return 0 on success and nonzero on failure (e.g., memory exhaustion), hence the nonzero return value corresponds to DupKey
returning NULL
. (DupKeyValue
is allowed [and supposed] to "duplicate" a NULL
object pointer and return 0; this is needed elsewhere in this file, as discussed below.)
DHT/dht.c
Outdated
{ | ||
(ht->procs.FreeKey)((dhtValue)KeyV); | ||
(ht->procs.FreeKeyValue)(KeyV.value); | ||
TraceText("data duplication failed\n"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm.
Before, we signaled "data duplication failed" if DupData returned 0.
Now, we signal it if it doesn't.
Can this be correct?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Analogously to above, DupData
is specified to return 0 on success and nonzero on failure, so we're still checking the analogous condition. What's special here was that previously we allowed for the original data
to be NULL
and (in that case) just set DataV
to NULL
without signaling an error, hence I had to allow the same here. To make that work I had to require DupData
to simply copy a NULL
object pointer and return 0.
return 1; | ||
while (length > ((size_t)-1)) | ||
{ | ||
if (memcmp(data1, data2, ((size_t)-1))) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The 3rd argument looks very strange.
Assuming that size_t is an unsigned type, this argument is very big.
Shouldn't we use the (equal) Length value of the two objects?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is one of my insanely pedantic portability idioms. The loop is intended to handle the extremely unlikely case that, somehow, length > ((size_t)-1)
, the latter being the largest third argument that memcmp
can take. In that case, rather than have that third argument silently truncated, I loop over the buffer in chunks of length (size_t)-1
until what's left is small enough to check correctly. I doubt this loop will ever (or even can ever) execute on a real system.
Agreed, and this is what I'm currently investigating. This is a big update, and we shouldn't push it out until all concerns are resolved. Thanks for taking a first pass. |
I have reduced the haan chess example that produces a difference and ended up with this: anfang If I test this with -maxmem 15k, with DOMEASURE activated, I notice that the executable from this pull request prints higher numbers than the executable from branch develop. The reason is that compresshash() is invoked after move compresshash() removes some elements from the hash table, which has the effect of the moves played to differ starting at move 2039:
|
There are a few things in this pull request that increase the sizes of allocated blocks.
At the time I believed (1) was necessary for correctness, and implementing it did eliminate some crashes that were otherwise unexplainable. Also, it's clear that we need to do this if we're going to pretend that (2) was implemented to resolve Issue #423. As @MuTsunTsai noted in PR #360, we could sometimes require more than 255 bytes to encode a position. My updates to UPDATE: I think I better understand (1) now. The current version of |
…. Also, implementing my TODO as a compile-time option. Primarily pushing now so that I can pull this into my testing infrastructure.
As a sanity check, I tried running the non-lengthy regression testing with the alignment set to 1 and
I'll continue digging here. |
This is interesting. I:
I then tested each version on |
For those who wish to help figure this out, I'd like to lay out my thoughts. I believe that many of the observed differences can be explained by my version simply allocating larger sizes than the current version. We can discuss the costs and benefits of doing so, but I consider that secondary (until/unless we find a bug in that particular logic, of course). For now, the most important thing is to figure out why we see differences even when the allocations are the same size. To simulate this in my (current) code:
With these changes my |
…ipulation functions.
…hange our minimum allocation).
…ended answer anyway.
…heck ensures that there's no overflow.
…peye specifically uses it.
…o more with this alignment information, but for now let's just be sure our assumptions hold.
…he alignment we want, taking the bottom bit should be safe.
I'm ready to open this branch up to independent testing and, perhaps, eventual merging. I restored the previous behavior of putting even allocations at the top of the range and uneven ones at the bottom. Though the There is the downside that it's impossible to verify that these settings are correct across all systems or that they will remain correct as the code continues to evolve. As a mitigation, I modified the |
This branch is an implementation of the same changes as those in
feature/tighten_hash_usage
but based off ofdevelop
commit #5ffb472. See PR #441 for the full explanation of what's going on here.I believe this resolves Issues #316 and #423. Additionally, I assume it resolves Issue #492, though as per the discussion there one could take the relevant changes even further if desired.