Skip to content
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

[SharedCache] Reduce lock contention in SharedCache::LoadSectionAtAddress #6202

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from

Conversation

WeiN76LQh
Copy link

@WeiN76LQh WeiN76LQh commented Nov 26, 2024

When loading a number of sections, for instance when an image is loaded, many of the analysis threads bottleneck in SharedCache::LoadSectionAtAddress trying to acquire the viewOperationsThatInfluenceMetadataMutex lock. This is a very expensive lock to try and acquire as it is used in a lot of places and held for long durations.

This commit improves performance in SharedCache::LoadSectionAtAddress by not acquiring the viewOperationsThatInfluenceMetadataMutex lock until absolutely necessary, i.e. when something actually needs to be loaded. Often what happens is many threads try to load the same sections but ending up queuing up to do this one at a time. The commit adds per memory region locking so that threads only block waiting for the memory region they require to be loaded. In most cases though, if the region is already loaded they won't wait at all because no lock is required to determine if this is the case.

Note: this PR is built on @bdash's PR #6196 due to the fixes and improvements in view-specific state, as this commit adds view-specific mutexes. I thought it would be prudent to make use of those changes.

To be honest I'm not 100% sure about the use of a map of mutexes to provide per memory region locking. It just feels a bit excessive but it works and the memory consumption of it won't be anything significant.

bdash and others added 3 commits November 25, 2024 10:40
The existing view-specific state was stored in several global unordered
maps. Many of these were accessed without locking, including
`viewSpecificMutexes`, which is racy in the face of multiple threads.

View-specific state is stored in a new heap-allocated
`ViewSpecificState` struct that is reference counted via
`std::shared_ptr`. A static map holds a `std::weak_ptr` to each
view-specific state, keyed by session id. `SharedCache` retrieves its
view-specific state during its constructor.

Since `ViewSpecificState` is reference counted it will naturally be
deallocated when the last `SharedCache` instance that references it goes
away. Its corresponding entry will remain in the static map, though
since it only holds a `std::weak_ptr` rather than any state it will not
use much memory. The next time view-specific state is retrieved any
expired entries will be removed from the map.
They're surprisingly expensive to look up.
…dress`

When loading a number of sections, for instance when an image is loaded, many of the analysis threads bottleneck in `SharedCache::LoadSectionAtAddress` trying to acquire the `viewOperationsThatInfluenceMetadataMutex` lock. This is a very expensive lock to try and acquire as it is used in a lot of places and held for long durations.

This commit improves performance in `SharedCache::LoadSectionAtAddress` by not acquiring the `viewOperationsThatInfluenceMetadataMutex` lock until absolutely necessary. I.e. when something actually needs to be loaded. Often what happens is many threads try to load the same sections but ending up queuing up to do this one at a time. The commit adds per memory region locking so that threads only block waiting for the memory region they require to be loaded. In most cases though, if the region is already loaded they won't wait at all because no lock is required to determine if this is the case.

// The region appears not to be loaded. Acquire the loading lock, re-check
// that it hasn't been loaded and if it still hasn't then actually load it.
std::unique_lock<std::mutex> memoryRegionLoadingLockslock(ViewSpecificStateForView(m_dscView)->memoryRegionLoadingMutexesMutex);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The view-specific state can be found in m_viewSpecificState rather than using ViewSpecificStateForView(…) to look it up in the global hash table.

…okup

This is just correcting a silly mistake
@plafosse plafosse added this to the Gallifrey milestone Dec 4, 2024
@plafosse plafosse added the File Format: SharedCache Issue with the dyld_shared_cache plugin label Dec 10, 2024
@0cyn
Copy link
Member

0cyn commented Dec 10, 2024

Thank you for the PR! We're looking into getting this merged over the next couple of weeks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
File Format: SharedCache Issue with the dyld_shared_cache plugin
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants