-
Notifications
You must be signed in to change notification settings - Fork 5.8k
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
8297389: resexhausted003 fails with assert(!thread->owns_locks()) failed: must release all locks when leaving VM #11316
Conversation
…iled: must release all locks when leaving VM
/label hotspot |
👋 Welcome back thartmann! A progress list of the required criteria for merging this PR into |
@TobiHartmann |
Webrevs
|
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.
If MethodData::allocate
cannot be called whilst holding a lock then perhaps we can assert that in there?
I think there is a broader problem here that metaspace allocation can occur in numerous places and any failure could post the resource-exhausted event and potentially lead to problems like this.
This fix side-steps one problematic call-site, but going lock-free has its own concerns.
src/hotspot/share/oops/method.cpp
Outdated
// The store into method must be released. On platforms without | ||
// total store order (TSO) the reference may become visible before | ||
// the initialization of data otherwise. | ||
OrderAccess::release(); |
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.
A release here is not necessary as Atomic::replace_if_null
will by default have memory_order_conservative
which maintains the full bi-directional fence of the internal cmpxchg
.
return; // return the exception (which is cleared) | ||
} | ||
ClassLoaderData* loader_data = method->method_holder()->class_loader_data(); | ||
MethodData* method_data = MethodData::allocate(loader_data, method, THREAD); |
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 downside of lock-free here is that we have to pre-allocate and then later free. How expensive is that? How likely are we to get multiple threads attempting this at the same time? We might trigger a resource-exhausted event unnecessarily due to the temporary use of metaspace.
Thanks for the review, David! I added an assert to Regarding the overhead of going lock-free: I temporarily added code that counts the number of times that multiple threads attempt initialization and asserts if it's more that 50x. This triggers in 25 out of 203.772 runs (tests from tier1 to tier3). The average size of these allocations is around 88 words (704 bytes). I therefore think it's fine to avoid a lock in this case. Also, we already use a lock-free mechanism for What do you think? |
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.
Thanks for taking care of the issue. The fix looks ok to me. Seems like you've removed all uses of MethodData_lock
so you could remove the declaration and definition too.
Thanks, Richard.
@TobiHartmann This change now passes all automated pre-integration checks. ℹ️ This project also has non-automated pre-integration requirements. Please see the file CONTRIBUTING.md for details. After integration, the commit message for the final commit will be:
You can use pull request commands such as /summary, /contributor and /issue to adjust it as needed. At the time when this comment was updated there had been 151 new commits pushed to the
As there are no conflicts, your changes will automatically be rebased on top of these commits when integrating. If you prefer to avoid this automatic rebasing, please check the documentation for the /integrate command for further details. ➡️ To integrate this PR with the above commit message to the |
Thanks for the review, Richard. Good catch, I removed the |
I'm not sure if it's guaranteed that replay runs single-threaded. I haven't looked into the details, but I think ReplayInline can run in any compiler thread after startup, and then of course there is JDK-8254110. |
But as long as the overhead is low and interference unlikely, then we can see how this works out in practice. Thanks. |
But ReplayInline does not load ciMethodData, i.e., does not call The only way this code can get executed is through Of course, if we are ever going to implement JDK-8254110, we need to revisit that code, but in that case the assert that I added will trigger. What do you think?
It uses the exact same mechanism that I now added to jdk/src/hotspot/share/oops/method.cpp Lines 651 to 654 in f4b5065
And I verified that multiple threads attempt to initialize the counters by adding verification code to: jdk/src/hotspot/share/oops/method.cpp Lines 644 to 646 in f4b5065
|
Sorry I somehow missed the |
OK, please add a TODO in JDK-8254110 explaining this so it doesn't get lost. |
Thanks, done. |
@dholmes-ora, @dean-long are you okay with the latest version? |
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.
Changes seem okay but I'm not that familiar with the actual code here.
Thanks.
Thanks, David! |
Thanks, Dean! |
/integrate |
Going to push as commit 9f24a6f.
Your commit was automatically rebased without conflicts. |
@TobiHartmann Pushed as commit 9f24a6f. 💡 You may see a message that your pull request was closed with unmerged commits. This can be safely ignored. |
Method::build_profiling_method_data
acquires theMethodData_lock
when initializingMethod::_method_data
to prevent multiple allocations by different threads. The problem is that when metaspace allocation fails andJvmtiExport::should_post_resource_exhausted()
is set, we assert during theThreadToNativeFromVM
transition in JVMTI code.Since concurrent initialization is a rare event, I suggest to get rid of the lock and perform the initialization with a
cmpxchg
, similar to how method counters are initialized:jdk/src/hotspot/share/oops/method.cpp
Lines 644 to 646 in f4b5065
Since current code in
Method::set_method_data
uses aAtomic::release_store
, I added aOrderAccess::release()
.Thanks,
Tobias
Progress
Issue
Reviewers
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk pull/11316/head:pull/11316
$ git checkout pull/11316
Update a local copy of the PR:
$ git checkout pull/11316
$ git pull https://git.openjdk.org/jdk pull/11316/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 11316
View PR using the GUI difftool:
$ git pr show -t 11316
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/11316.diff