-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Runtime] Switch MetadataCache to ConcurrentReadableHashMap. #34307
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
[Runtime] Switch MetadataCache to ConcurrentReadableHashMap. #34307
Conversation
@swift-ci please benchmark |
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.
So the actual entry in the hashtable now is an EntryType*
, right? Or is it indirected an extra step for some reason?
stdlib/public/runtime/Metadata.cpp
Outdated
} | ||
|
||
Key key{value.Data.NumElements, elements.data(), value.Data.Labels}; | ||
return hash_value(key); |
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.
Surely there's a way to do this without having to copy the elements into a local array. You could use a TransformRange
to project out the Metadata*
for hash_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.
I couldn't find a nice way to do it, but I didn't know we had TransformRange
. That looks nice and simple, I'll do that.
Note that entry hashes are only used when resizing the table, so it's not a performance impact for lookups. But it's still definitely worth doing better.
@@ -106,17 +106,14 @@ struct ConcurrencyControl { | |||
ConcurrencyControl() = default; | |||
}; | |||
|
|||
template <class EntryType, uint16_t Tag, bool ProvideDestructor = true> | |||
template <class EntryType, uint16_t Tag> |
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.
Is there just never a situation where we care about destructors for these?
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.
I couldn't find any. ConcurrentMap
doesn't support removal. It does support destroying the entire tree, but all uses of it just create it and let it live forever. I assume this was left over from a much earlier era when it was thought that these caches might not be permanent, or metadata might not be immortal.
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.
Mostly I was reluctant to write a class that might be useless in other contexts.
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.
Ah, that'll do it too.
That's right. The wrapper forwards key matching operations, but it's ultimately just a pointer, so there's just one level of indirection. As I mention in the PR description, I'd like to even get rid of that, but it's a bigger job. |
I think the entries usually have the metadata inline, and the metadata address isn't allowed to change, so I'm not sure how you could do that. |
The entries store a pointer:
I think the entry can be created before the size is known, so it has to be separate. |
It might be an interior pointer. It is for TupleCacheEntry, at least, and I think it is for some of the others as well. And I'm not sure you can safely copy a MetadataCacheEntryBase — you'll need to do serious surgery, at least. |
Ah, I didn't catch that it could be an interior pointer! I'm OK with major surgery to improve the cases that can benefit from it, but I will keep in mind that it won't be easy. I'll keep my eye out for better approaches, too. In the meantime, I need to figure out these benchmark regressions before I land this one.... |
@swift-ci please benchmark |
Playing with some perf improvements to the hashmap code. I'll make them a separate PR if they pan out. |
343a15d
to
9174785
Compare
9174785
to
1b59c52
Compare
I changed that copying |
@swift-ci please test |
Build failed |
The new table spills out of the available space when targeting 32-bit. Working out how to shrink it further... |
Use StableAddressConcurrentReadableHashMap for now. MetadataCacheEntry's methods for awaiting a particular state assume a stable address, where it will repeatedly examine `this` in a loop while waiting on a condition variable, so we give it a stable address to accommodate that. This code can be changed to perform the necessary table lookup each time through the loop instead, and thus allow us to use a plain ConcurrentReadableHashMap and avoid the extra indirection, and I'll take care of that in a followup. rdar://problem/70220660
…ntry and check that before doing a more expensive lookup.
…e it to get LockingConcurrentMapStorage to fit into the available space on 32-bit.
0a08cae
to
cf53ad2
Compare
Shrank it using some indirection. We really should adopt |
@swift-ci please test |
1 similar comment
@swift-ci please test |
Build failed |
@swift-ci please test os x platform |
@rjmccall Any other changes or comments before I merge? |
@swift-ci please test |
Re-testing to make sure nothing broke since last week. |
Build failed |
The OS X test failure is unrelated. Pushing the Big Red Button. |
* 'main' of github.com:apple/swift: [Runtime] Switch MetadataCache to ConcurrentReadableHashMap. (swiftlang#34307)
Use
StableAddressConcurrentReadableHashMap
for now.MetadataCacheEntry
's methods for awaiting a particular state assume a stable address, where it will repeatedly examinethis
in a loop while waiting on a condition variable, so we give it a stable address to accommodate that. This code can be changed to perform the necessary table lookup each time through the loop instead, and thus allow us to use a plainConcurrentReadableHashMap
and avoid the extra indirection, and I'll take care of that in a followup.rdar://problem/70220660