-
Notifications
You must be signed in to change notification settings - Fork 6.2k
8366363: MemBaseline accesses VMT without using lock #27003
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
base: master
Are you sure you want to change the base?
Conversation
80e5eef
to
bfa2d72
Compare
👋 Welcome back jsjolen! A progress list of the required criteria for merging this PR into |
❗ This change is not yet ready to be integrated. |
@jdksjolen The following label will be automatically applied to this pull request:
When this pull request is ready to be reviewed, an "RFR" email will be sent to the corresponding mailing list. If you would like to change these labels, use the /label pull request command. |
bfa2d72
to
206b36d
Compare
/label hotspot-runtime |
@jdksjolen |
Webrevs
|
@@ -451,6 +451,13 @@ class RBTree : public AbstractRBTree<K, RBNode<K, V>, COMPARATOR> { | |||
|
|||
public: | |||
RBTree() : BaseType(), _allocator() {} | |||
RBTree(const RBTree& other) : BaseType(), _allocator() { |
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.
@caspernorrbin , I added this. Does it look 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.
Looks correct to me, as long as the value type can also be properly copy-constructible. Maybe we can add in an assert to avoid potential future misuse? :-)
Something like:
assert(std::is_copy_constructible<V>(), "Value type must be copy-constructible");
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.
Yeah, we can do that! I'll put it in a static_assert even.
800eca2
to
c5454db
Compare
@jdksjolen Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information. |
Oops, I accidentally committed to my current branch, I meant to commit to a new one. I'm going to rewrite history a bit, sorry bot. |
c5454db
to
a125e58
Compare
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.
Thank you @jdksjolen for taking this issue.
I have only one concern when we copy a RBTree to a new one. We do a visit_in_order
on the source tree and upsert
the key-value to the destination tree. We do a sorted access on both trees. We can avoid one, by a new function like: visit_all()
for the source tree, or for the destination tree use the hint_node
somehow (that I don't know how, ping @caspernorrbin) in RBTree::upsert(K, V, Node* hint_node)
I don't think we would see much improvement iterating differently on the source tree. However, for the destination tree we traverse down the tree for each upsert, which could have quite an impact on large trees. To achieve this we could change the return type of RBTree(const RBTree& other) : BaseType(), _allocator() {
static_assert(std::is_copy_constructible<K>::value, "Key type must be copy-constructible when copying a RBTree");
static_assert(std::is_copy_constructible<V>::value, "Value type must be copy-constructible when copying a RBTree");
RBNode<K, V>* prev_node = nullptr;
other.visit_in_order([&](RBNode<K, V>* node) {
RBNode<K, V>* new_node = this->upsert(node->key(), node->val(), prev_node);
prev_node = new_node;
return true;
});
} |
I think we need to switch out the iterator for that to make sense, specifically it needs to be DFS. Anyway, let's do that. |
When we do a |
@jdksjolen Please do not rebase or force-push to an active PR as it invalidates existing review comments. Note for future reference, the bots always squash all changes into a single commit automatically as part of the integration. See OpenJDK Developers’ Guide for more information. |
Sorry about the ridiculous amount of commits. For each one I thought "this is the last one". I've created a temp branch that I'll push to so you don't have to see this WIP. |
enum Dir { Left, Right }; | ||
struct node_pair { const RBNode<K, V>* current; RBNode<K, V>* other_parent; Dir d; }; | ||
struct stack { | ||
node_pair s[64]; |
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.
Could you clarify the choice of 64 as an upper bound? It's not immediately obvious to me if we guarantee (or if we don't care about) the maximum visitation size in the code below.
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 an arbitrary depth (it's used in other parts of the RBTree code as well). The maximum length of the stack represents the maximum depth of the tree that we support. A perfectly balanced binary tree of depth 64 has 2**64 - 1 nodes, so in practice this will never be reached.
/contributo add @caspernorrbin |
/contributor add @caspernorrbin |
@jdksjolen this pull request can not be integrated into git checkout cleanup-membaseline
git fetch https://git.openjdk.org/jdk.git master
git merge FETCH_HEAD
# resolve conflicts and follow the instructions given by git merge
git commit -m "Merge master"
git push |
@jdksjolen Unknown command |
@jdksjolen |
while ((rgn = itr.next()) != nullptr) { | ||
VirtualMemoryAllocationSite tmp(*rgn->call_stack(), rgn->mem_tag()); | ||
bool failed_oom = false; | ||
_vma_allocs_replacement->visit_reserved_regions([&](ReservedMemoryRegion& rgn) { |
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 _vma_allocs_replacement
is used only locally here. Instead of creating a copy of the VMATree, we can do our loop here within a lock. Can't we?
Then we save one tree traverse.
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 used here:
void MemDetailReporter::report_virtual_memory_map() {
// Virtual memory map always in base address order
output()->print_cr("Virtual memory map:");
_baseline.virtual_memory_allocations()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) {
report_virtual_memory_region(&rgn);
return true;
});
}
Hi,
The
MemBaseline
used to access the VMT instance directly without a lock. We fix that, and we switch from using aLinkedList
to a copiedRegionsTree
instead.Progress
Issue
Contributors
<cnorrbin@openjdk.org>
Reviewing
Using
git
Checkout this PR locally:
$ git fetch https://git.openjdk.org/jdk.git pull/27003/head:pull/27003
$ git checkout pull/27003
Update a local copy of the PR:
$ git checkout pull/27003
$ git pull https://git.openjdk.org/jdk.git pull/27003/head
Using Skara CLI tools
Checkout this PR locally:
$ git pr checkout 27003
View PR using the GUI difftool:
$ git pr show -t 27003
Using diff file
Download this PR as a diff file:
https://git.openjdk.org/jdk/pull/27003.diff
Using Webrev
Link to Webrev Comment