8377996: [REDO] NMT: Consolidate [Virtual/Committed/Reserved]Regions into one structure

Reviewed-by: phubner, jsjolen
This commit is contained in:
Afshin Zafari 2026-02-24 09:15:23 +00:00
parent 35ed56afc7
commit bc9c6c6af9
12 changed files with 239 additions and 293 deletions

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -168,12 +168,13 @@ int compare_allocation_site(const VirtualMemoryAllocationSite& s1,
}
bool MemBaseline::aggregate_virtual_memory_allocation_sites() {
SortedLinkedList<VirtualMemoryAllocationSite, compare_allocation_site> allocation_sites;
VirtualMemoryAllocationSite* site;
bool failed_oom = false;
_vma_allocations->visit_reserved_regions([&](ReservedMemoryRegion& rgn) {
VirtualMemoryAllocationSite tmp(*rgn.call_stack(), rgn.mem_tag());
_vma_allocations->visit_reserved_regions([&](VirtualMemoryRegion& rgn) {
VirtualMemoryAllocationSite tmp(*rgn.reserved_call_stack(), rgn.mem_tag());
site = allocation_sites.find(tmp);
if (site == nullptr) {
LinkedListNode<VirtualMemoryAllocationSite>* node =

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2023, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2026, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2023, 2024, Red Hat, Inc. and/or its affiliates.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
@ -149,7 +149,7 @@ public:
}
}
bool do_allocation_site(const ReservedMemoryRegion* rgn) override {
bool do_allocation_site(const VirtualMemoryRegion* rgn) override {
// Cancel iteration if we run out of memory (add returns false);
return add(rgn->base(), rgn->end(), rgn->mem_tag());
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -395,14 +395,14 @@ int MemDetailReporter::report_virtual_memory_allocation_sites() {
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) {
_baseline.virtual_memory_allocations()->visit_reserved_regions([&](VirtualMemoryRegion& rgn) {
report_virtual_memory_region(&rgn);
return true;
});
}
void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion* reserved_rgn) {
assert(reserved_rgn != nullptr, "null pointer");
void MemDetailReporter::report_virtual_memory_region(const VirtualMemoryRegion* rgn) {
assert(rgn != nullptr, "null pointer");
// We don't bother about reporting peaks here.
// That is because peaks - in the context of virtual memory, peak of committed areas - make little sense
@ -414,16 +414,16 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion*
// usage *by callsite*.
// Don't report if size is too small.
if (amount_in_current_scale(reserved_rgn->size()) == 0) return;
if (amount_in_current_scale(rgn->size()) == 0) return;
outputStream* out = output();
const char* scale = current_scale();
const NativeCallStack* stack = reserved_rgn->call_stack();
bool all_committed = reserved_rgn->size() == _baseline.virtual_memory_allocations()->committed_size(*reserved_rgn);
const NativeCallStack* stack = rgn->reserved_call_stack();
bool all_committed = rgn->size() == _baseline.virtual_memory_allocations()->committed_size(*rgn);
const char* region_type = (all_committed ? "reserved and committed" : "reserved");
out->cr();
print_virtual_memory_region(region_type, reserved_rgn->base(), reserved_rgn->size());
out->print(" for %s", NMTUtil::tag_to_name(reserved_rgn->mem_tag()));
print_virtual_memory_region(region_type, rgn->base(), rgn->size());
out->print(" for %s", NMTUtil::tag_to_name(rgn->mem_tag()));
if (stack->is_empty()) {
out->cr();
} else {
@ -433,9 +433,9 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion*
if (all_committed) {
bool reserved_and_committed = false;
_baseline.virtual_memory_allocations()->visit_committed_regions(*reserved_rgn,
[&](CommittedMemoryRegion& committed_rgn) {
if (committed_rgn.equals(*reserved_rgn)) {
_baseline.virtual_memory_allocations()->visit_committed_regions(*rgn,
[&](VirtualMemoryRegion& committed_rgn) {
if (committed_rgn.equals(*rgn)) {
// One region spanning the entire reserved region, with the same stack trace.
// Don't print this regions because the "reserved and committed" line above
// already indicates that the region is committed.
@ -450,13 +450,13 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion*
}
}
auto print_committed_rgn = [&](const CommittedMemoryRegion& crgn) {
auto print_committed_rgn = [&](const VirtualMemoryRegion& rgn) {
// Don't report if size is too small
if (amount_in_current_scale(crgn.size()) == 0) return;
stack = crgn.call_stack();
if (amount_in_current_scale(rgn.size()) == 0) return;
stack = rgn.committed_call_stack();
out->cr();
INDENT_BY(8,
print_virtual_memory_region("committed", crgn.base(), crgn.size());
print_virtual_memory_region("committed", rgn.base(), rgn.size());
if (stack->is_empty()) {
out->cr();
} else {
@ -466,9 +466,9 @@ void MemDetailReporter::report_virtual_memory_region(const ReservedMemoryRegion*
)
};
_baseline.virtual_memory_allocations()->visit_committed_regions(*reserved_rgn,
[&](CommittedMemoryRegion& crgn) {
print_committed_rgn(crgn);
_baseline.virtual_memory_allocations()->visit_committed_regions(*rgn,
[&](VirtualMemoryRegion& committed_rgn) {
print_committed_rgn(committed_rgn);
return true;
});
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2012, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2012, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -178,7 +178,7 @@ class MemDetailReporter : public MemSummaryReporter {
int report_virtual_memory_allocation_sites();
// Report a virtual memory region
void report_virtual_memory_region(const ReservedMemoryRegion* rgn);
void report_virtual_memory_region(const VirtualMemoryRegion* rgn);
};
/*

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -58,9 +58,9 @@ void RegionsTree::print_on(outputStream* st) {
}
#endif
size_t RegionsTree::committed_size(const ReservedMemoryRegion& rgn) {
size_t RegionsTree::committed_size(const VirtualMemoryRegion& rgn) {
size_t result = 0;
visit_committed_regions(rgn, [&](CommittedMemoryRegion& crgn) {
visit_committed_regions(rgn, [&](VirtualMemoryRegion& crgn) {
result += crgn.size();
return true;
});

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,8 +29,7 @@
#include "nmt/vmatree.hpp"
class ReservedMemoryRegion;
class CommittedMemoryRegion;
class VirtualMemoryRegion;
// RegionsTree extends VMATree to add some more specific API and also defines a helper
// for processing the tree nodes in a shorter and more meaningful way.
class RegionsTree : public VMATree {
@ -46,7 +45,7 @@ class RegionsTree : public VMATree {
_with_storage(other._with_storage) {}
RegionsTree& operator=(const RegionsTree& other) = delete;
ReservedMemoryRegion find_reserved_region(address addr);
VirtualMemoryRegion find_reserved_region(address addr);
void commit_region(address addr, size_t size, const NativeCallStack& stack, SummaryDiff& diff);
void uncommit_region(address addr, size_t size, SummaryDiff& diff);
@ -71,6 +70,7 @@ class RegionsTree : public VMATree {
return position() - other.position();
}
inline NativeCallStackStorage::StackIndex out_stack_index() const { return _node->val().out.reserved_stack(); }
inline NativeCallStackStorage::StackIndex out_committed_stack_index() const { return _node->val().out.committed_stack(); }
inline MemTag in_tag() const { return _node->val().in.mem_tag(); }
inline MemTag out_tag() const { return _node->val().out.mem_tag(); }
inline void set_in_tag(MemTag tag) { _node->val().in.set_tag(tag); }
@ -81,7 +81,7 @@ class RegionsTree : public VMATree {
DEBUG_ONLY(void print_on(outputStream* st);)
template<typename F>
void visit_committed_regions(const ReservedMemoryRegion& rgn, F func);
void visit_committed_regions(const VirtualMemoryRegion& rgn, F func);
template<typename F>
void visit_reserved_regions(F func);
@ -90,7 +90,7 @@ class RegionsTree : public VMATree {
return RegionData(_ncs_storage.push(ncs), tag);
}
inline const NativeCallStack stack(NodeHelper& node) {
inline const NativeCallStack reserved_stack(NodeHelper& node) {
if (!_with_storage) {
return NativeCallStack::empty_stack();
}
@ -98,7 +98,15 @@ class RegionsTree : public VMATree {
return _ncs_storage.get(si);
}
size_t committed_size(const ReservedMemoryRegion& rgn);
inline const NativeCallStack committed_stack(NodeHelper& node) {
if (!_with_storage) {
return NativeCallStack::empty_stack();
}
NativeCallStackStorage::StackIndex si = node.out_committed_stack_index();
return _ncs_storage.get(si);
}
size_t committed_size(const VirtualMemoryRegion& rgn);
};
#endif // NMT_REGIONSTREE_HPP

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -29,7 +29,7 @@
#include "nmt/virtualMemoryTracker.hpp"
template<typename F>
void RegionsTree::visit_committed_regions(const ReservedMemoryRegion& rgn, F func) {
void RegionsTree::visit_committed_regions(const VirtualMemoryRegion& rgn, F func) {
position start = (position)rgn.base();
size_t end = reinterpret_cast<size_t>(rgn.end()) + 1;
size_t comm_size = 0;
@ -38,8 +38,12 @@ void RegionsTree::visit_committed_regions(const ReservedMemoryRegion& rgn, F fun
visit_range_in_order(start, end, [&](Node* node) {
NodeHelper curr(node);
if (prev.is_valid() && prev.is_committed_begin()) {
CommittedMemoryRegion cmr((address)prev.position(), curr.distance_from(prev), stack(prev));
if (!func(cmr)) {
VirtualMemoryRegion rgn((address)prev.position(),
curr.distance_from(prev),
reserved_stack(prev),
committed_stack(prev),
prev.out_tag());
if (!func(rgn)) {
return false;
}
}
@ -63,13 +67,13 @@ void RegionsTree::visit_reserved_regions(F func) {
}
prev = curr;
if (curr.is_released_begin() || begin_node.out_tag() != curr.out_tag()) {
auto st = stack(begin_node);
auto st = reserved_stack(begin_node);
if (rgn_size == 0) {
prev.clear_node();
return true;
}
ReservedMemoryRegion rmr((address)begin_node.position(), rgn_size, st, begin_node.out_tag());
if (!func(rmr)) {
VirtualMemoryRegion rgn((address)begin_node.position(), rgn_size, st, begin_node.out_tag());
if (!func(rgn)) {
return false;
}
rgn_size = 0;

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -193,14 +193,14 @@ bool VirtualMemoryTracker::Instance::print_containing_region(const void* p, outp
}
bool VirtualMemoryTracker::print_containing_region(const void* p, outputStream* st) {
ReservedMemoryRegion rmr = tree()->find_reserved_region((address)p);
if (!rmr.contain_address((address)p)) {
VirtualMemoryRegion rgn = tree()->find_reserved_region((address)p);
if (!rgn.is_valid() || !rgn.contain_address((address)p)) {
return false;
}
st->print_cr(PTR_FORMAT " in mmap'd memory region [" PTR_FORMAT " - " PTR_FORMAT "], tag %s",
p2i(p), p2i(rmr.base()), p2i(rmr.end()), NMTUtil::tag_to_enum_name(rmr.mem_tag()));
p2i(p), p2i(rgn.base()), p2i(rgn.end()), NMTUtil::tag_to_enum_name(rgn.mem_tag()));
if (MemTracker::tracking_level() == NMT_detail) {
rmr.call_stack()->print_on(st);
rgn.reserved_call_stack()->print_on(st);
}
st->cr();
return true;
@ -213,7 +213,7 @@ bool VirtualMemoryTracker::Instance::walk_virtual_memory(VirtualMemoryWalker* wa
bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) {
bool ret = true;
tree()->visit_reserved_regions([&](ReservedMemoryRegion& rgn) {
tree()->visit_reserved_regions([&](VirtualMemoryRegion& rgn) {
if (!walker->do_allocation_site(&rgn)) {
ret = false;
return false;
@ -223,29 +223,29 @@ bool VirtualMemoryTracker::walk_virtual_memory(VirtualMemoryWalker* walker) {
return ret;
}
size_t VirtualMemoryTracker::committed_size(const ReservedMemoryRegion* rmr) {
size_t VirtualMemoryTracker::committed_size(const VirtualMemoryRegion* rgn) {
size_t result = 0;
tree()->visit_committed_regions(*rmr, [&](CommittedMemoryRegion& crgn) {
tree()->visit_committed_regions(*rgn, [&](VirtualMemoryRegion& crgn) {
result += crgn.size();
return true;
});
return result;
}
size_t VirtualMemoryTracker::Instance::committed_size(const ReservedMemoryRegion* rmr) {
size_t VirtualMemoryTracker::Instance::committed_size(const VirtualMemoryRegion* rgn) {
assert(_tracker != nullptr, "Sanity check");
return _tracker->committed_size(rmr);
return _tracker->committed_size(rgn);
}
address VirtualMemoryTracker::Instance::thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr) {
address VirtualMemoryTracker::Instance::thread_stack_uncommitted_bottom(const VirtualMemoryRegion* rgn) {
assert(_tracker != nullptr, "Sanity check");
return _tracker->thread_stack_uncommitted_bottom(rmr);
return _tracker->thread_stack_uncommitted_bottom(rgn);
}
address VirtualMemoryTracker::thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr) {
address bottom = rmr->base();
address top = rmr->end();
tree()->visit_committed_regions(*rmr, [&](CommittedMemoryRegion& crgn) {
address VirtualMemoryTracker::thread_stack_uncommitted_bottom(const VirtualMemoryRegion* rgn) {
address bottom = rgn->base();
address top = rgn->end();
tree()->visit_committed_regions(*rgn, [&](VirtualMemoryRegion& crgn) {
address committed_top = crgn.base() + crgn.size();
if (committed_top < top) {
// committed stack guard pages, skip them
@ -299,7 +299,7 @@ class SnapshotThreadStackWalker : public VirtualMemoryWalker {
public:
SnapshotThreadStackWalker() {}
bool do_allocation_site(const ReservedMemoryRegion* rgn) {
bool do_allocation_site(const VirtualMemoryRegion* rgn) {
if (MemTracker::NmtVirtualMemoryLocker::is_safe_to_use()) {
assert_lock_strong(NmtVirtualMemory_lock);
}
@ -340,19 +340,19 @@ void VirtualMemoryTracker::Instance::snapshot_thread_stacks() {
walk_virtual_memory(&walker);
}
ReservedMemoryRegion RegionsTree::find_reserved_region(address addr) {
ReservedMemoryRegion rmr;
auto contain_region = [&](ReservedMemoryRegion& region_in_tree) {
VirtualMemoryRegion RegionsTree::find_reserved_region(address addr) {
VirtualMemoryRegion rgn;
auto contain_region = [&](VirtualMemoryRegion& region_in_tree) {
if (region_in_tree.contain_address(addr)) {
rmr = region_in_tree;
rgn = region_in_tree;
return false;
}
return true;
};
visit_reserved_regions(contain_region);
return rmr;
return rgn;
}
bool CommittedMemoryRegion::equals(const ReservedMemoryRegion& rmr) const {
return size() == rmr.size() && call_stack()->equals(*(rmr.call_stack()));
bool VirtualMemoryRegion::equals_including_stacks(const VirtualMemoryRegion& rgn) const {
return size() == rgn.size() && committed_call_stack()->equals(*(rgn.reserved_call_stack()));
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2013, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -194,15 +194,38 @@ class VirtualMemorySummary : AllStatic {
*/
class VirtualMemoryRegion {
private:
address _base_address;
size_t _size;
address _base_address;
size_t _size;
MemTag _mem_tag;
NativeCallStack _reserved_stack;
NativeCallStack _committed_stack;
public:
VirtualMemoryRegion() :
_base_address(nullptr), _size(0), _mem_tag(mtNone),
_reserved_stack(NativeCallStack::empty_stack()) ,
_committed_stack(NativeCallStack::empty_stack()) {}
VirtualMemoryRegion(address addr, size_t size) :
_base_address(addr), _size(size) {
_base_address(addr), _size(size), _mem_tag(mtNone),
_reserved_stack(NativeCallStack::empty_stack()) ,
_committed_stack(NativeCallStack::empty_stack()) {
assert(addr != nullptr, "Invalid address");
assert(size > 0, "Invalid size");
}
}
VirtualMemoryRegion(address addr, size_t size, const NativeCallStack& reserved_stack, const NativeCallStack& committed_stack, MemTag mem_tag = mtNone) :
_base_address(addr), _size(size), _mem_tag(mem_tag),
_reserved_stack(reserved_stack),
_committed_stack(committed_stack) {
assert(addr != nullptr, "Invalid address");
assert(size > 0, "Invalid size");
}
VirtualMemoryRegion(address addr, size_t size, const NativeCallStack& stack, MemTag mem_tag = mtNone)
: _base_address(addr), _size(size), _mem_tag(mem_tag),
_reserved_stack(stack),
_committed_stack(NativeCallStack::empty_stack()) {}
inline address base() const { return _base_address; }
inline address end() const { return base() + size(); }
@ -211,48 +234,18 @@ class VirtualMemoryRegion {
inline bool is_empty() const { return size() == 0; }
inline bool contain_address(address addr) const {
assert(is_valid(), "sanity");
return (addr >= base() && addr < end());
}
inline bool contain_region(address addr, size_t size) const {
return contain_address(addr) && contain_address(addr + size - 1);
}
inline bool same_region(address addr, size_t sz) const {
return (addr == base() && sz == size());
}
private:
inline bool overlap_region(address addr, size_t sz) const {
assert(sz > 0, "Invalid size");
assert(size() > 0, "Invalid size");
assert(is_valid(), "sanity");
return MAX2(addr, base()) < MIN2(addr + sz, end());
}
inline bool adjacent_to(address addr, size_t sz) const {
return (addr == end() || (addr + sz) == base());
}
void exclude_region(address addr, size_t sz) {
assert(contain_region(addr, sz), "Not containment");
assert(addr == base() || addr + sz == end(), "Can not exclude from middle");
size_t new_size = size() - sz;
if (addr == base()) {
set_base(addr + sz);
}
set_size(new_size);
}
void expand_region(address addr, size_t sz) {
assert(adjacent_to(addr, sz), "Not adjacent regions");
if (base() == addr + sz) {
set_base(addr);
}
set_size(size() + sz);
}
// Returns 0 if regions overlap; 1 if this region follows rgn;
// -1 if this region precedes rgn.
inline int compare(const VirtualMemoryRegion& rgn) const {
@ -266,86 +259,27 @@ class VirtualMemoryRegion {
}
}
public:
// Returns true if regions overlap, false otherwise.
inline bool equals(const VirtualMemoryRegion& rgn) const {
return compare(rgn) == 0;
}
protected:
void set_base(address base) {
assert(base != nullptr, "Sanity check");
_base_address = base;
}
bool equals_including_stacks(const VirtualMemoryRegion& other) const;
inline const NativeCallStack* committed_call_stack() const { return &_committed_stack; }
void set_size(size_t size) {
assert(size > 0, "Sanity check");
_size = size;
}
};
bool is_valid() const { return base() != nullptr && size() != 0;}
inline const NativeCallStack* reserved_call_stack() const { return &_reserved_stack; }
class CommittedMemoryRegion : public VirtualMemoryRegion {
private:
NativeCallStack _stack;
public:
CommittedMemoryRegion()
: VirtualMemoryRegion((address)1, 1), _stack(NativeCallStack::empty_stack()) { }
CommittedMemoryRegion(address addr, size_t size, const NativeCallStack& stack)
: VirtualMemoryRegion(addr, size), _stack(stack) { }
inline void set_call_stack(const NativeCallStack& stack) { _stack = stack; }
inline const NativeCallStack* call_stack() const { return &_stack; }
bool equals(const ReservedMemoryRegion& other) const;
};
class ReservedMemoryRegion : public VirtualMemoryRegion {
private:
NativeCallStack _stack;
MemTag _mem_tag;
public:
bool is_valid() { return base() != (address)1 && size() != 1;}
ReservedMemoryRegion()
: VirtualMemoryRegion((address)1, 1), _stack(NativeCallStack::empty_stack()), _mem_tag(mtNone) { }
ReservedMemoryRegion(address base, size_t size, const NativeCallStack& stack,
MemTag mem_tag = mtNone)
: VirtualMemoryRegion(base, size), _stack(stack), _mem_tag(mem_tag) { }
ReservedMemoryRegion(address base, size_t size)
: VirtualMemoryRegion(base, size), _stack(NativeCallStack::empty_stack()), _mem_tag(mtNone) { }
// Copy constructor
ReservedMemoryRegion(const ReservedMemoryRegion& rr)
: VirtualMemoryRegion(rr.base(), rr.size()) {
*this = rr;
}
inline void set_call_stack(const NativeCallStack& stack) { _stack = stack; }
inline const NativeCallStack* call_stack() const { return &_stack; }
inline MemTag mem_tag() const { return _mem_tag; }
ReservedMemoryRegion& operator= (const ReservedMemoryRegion& other) {
set_base(other.base());
set_size(other.size());
_stack = *other.call_stack();
_mem_tag = other.mem_tag();
return *this;
}
inline MemTag mem_tag() const { return _mem_tag; }
const char* tag_name() const { return NMTUtil::tag_to_name(_mem_tag); }
};
class VirtualMemoryWalker : public StackObj {
public:
virtual bool do_allocation_site(const ReservedMemoryRegion* rgn) { return false; }
virtual bool do_allocation_site(const VirtualMemoryRegion* rgn) { return false; }
};
@ -376,8 +310,8 @@ class VirtualMemoryTracker {
// Snapshot current thread stacks
void snapshot_thread_stacks();
void apply_summary_diff(VMATree::SummaryDiff diff);
size_t committed_size(const ReservedMemoryRegion* rmr);
address thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr);
size_t committed_size(const VirtualMemoryRegion* rgn);
address thread_stack_uncommitted_bottom(const VirtualMemoryRegion* rgn);
RegionsTree* tree() { return &_tree; }
@ -401,9 +335,9 @@ class VirtualMemoryTracker {
static bool print_containing_region(const void* p, outputStream* st);
static void snapshot_thread_stacks();
static void apply_summary_diff(VMATree::SummaryDiff diff);
static size_t committed_size(const ReservedMemoryRegion* rmr);
static size_t committed_size(const VirtualMemoryRegion* rgn);
// uncommitted thread stack bottom, above guard pages if there is any.
static address thread_stack_uncommitted_bottom(const ReservedMemoryRegion* rmr);
static address thread_stack_uncommitted_bottom(const VirtualMemoryRegion* rgn);
static RegionsTree* tree() { return _tracker->tree(); }
};

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2025, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -104,15 +104,15 @@ TEST_VM_F(NMTRegionsTreeTest, FindReservedRegion) {
rt.reserve_mapping(1200, 50, rd, not_used);
rt.reserve_mapping(1300, 50, rd, not_used);
rt.reserve_mapping(1400, 50, rd, not_used);
ReservedMemoryRegion rmr;
rmr = rt.find_reserved_region((address)1205);
EXPECT_EQ(rmr.base(), (address)1200);
rmr = rt.find_reserved_region((address)1305);
EXPECT_EQ(rmr.base(), (address)1300);
rmr = rt.find_reserved_region((address)1405);
EXPECT_EQ(rmr.base(), (address)1400);
rmr = rt.find_reserved_region((address)1005);
EXPECT_EQ(rmr.base(), (address)1000);
VirtualMemoryRegion rgn;
rgn = rt.find_reserved_region((address)1205);
EXPECT_EQ(rgn.base(), (address)1200);
rgn = rt.find_reserved_region((address)1305);
EXPECT_EQ(rgn.base(), (address)1300);
rgn = rt.find_reserved_region((address)1405);
EXPECT_EQ(rgn.base(), (address)1400);
rgn = rt.find_reserved_region((address)1005);
EXPECT_EQ(rgn.base(), (address)1000);
}
TEST_VM_F(NMTRegionsTreeTest, VisitReservedRegions) {
@ -124,7 +124,7 @@ TEST_VM_F(NMTRegionsTreeTest, VisitReservedRegions) {
rt.reserve_mapping(1300, 50, rd, not_used);
rt.reserve_mapping(1400, 50, rd, not_used);
rt.visit_reserved_regions([&](const ReservedMemoryRegion& rgn) {
rt.visit_reserved_regions([&](const VirtualMemoryRegion& rgn) {
EXPECT_EQ(((size_t)rgn.base()) % 100, 0UL);
EXPECT_EQ(rgn.size(), 50UL);
return true;
@ -144,9 +144,9 @@ TEST_VM_F(NMTRegionsTreeTest, VisitCommittedRegions) {
rt.commit_region((address)1020, 5UL, ncs, not_used);
rt.commit_region((address)1030, 5UL, ncs, not_used);
rt.commit_region((address)1040, 5UL, ncs, not_used);
ReservedMemoryRegion rmr((address)1000, 50);
VirtualMemoryRegion rgn((address)1000, 50);
size_t count = 0;
rt.visit_committed_regions(rmr, [&](CommittedMemoryRegion& crgn) {
rt.visit_committed_regions(rgn, [&](VirtualMemoryRegion& crgn) {
count++;
EXPECT_EQ((((size_t)crgn.base()) % 100) / 10, count);
EXPECT_EQ(crgn.size(), 5UL);

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -45,15 +45,14 @@ public:
VirtualMemoryTracker::Instance::snapshot_thread_stacks();
}
ReservedMemoryRegion rmr_found;
VirtualMemoryRegion rgn_found;
{
MemTracker::NmtVirtualMemoryLocker vml;
rmr_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region(stack_end);
rgn_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region(stack_end);
}
ASSERT_TRUE(rmr_found.is_valid());
ASSERT_EQ(rmr_found.base(), stack_end);
ASSERT_TRUE(rgn_found.is_valid());
ASSERT_EQ(rgn_found.base(), stack_end);
int i = 0;
address i_addr = (address)&i;
@ -64,12 +63,12 @@ public:
bool found_stack_top = false;
{
MemTracker::NmtVirtualMemoryLocker vml;
VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr_found, [&](const CommittedMemoryRegion& cmr) {
if (cmr.base() + cmr.size() == stack_top) {
EXPECT_TRUE(cmr.size() <= stack_size);
VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rgn_found, [&](const VirtualMemoryRegion& rgn) {
if (rgn.base() + rgn.size() == stack_top) {
EXPECT_TRUE(rgn.size() <= stack_size);
found_stack_top = true;
}
if (i_addr < stack_top && i_addr >= cmr.base()) {
if (i_addr < stack_top && i_addr >= rgn.base()) {
found_i_addr = true;
}
i++;
@ -115,25 +114,25 @@ public:
}
// trigger the test
ReservedMemoryRegion rmr_found;
VirtualMemoryRegion rgn_found;
{
MemTracker::NmtVirtualMemoryLocker nvml;
VirtualMemoryTracker::Instance::snapshot_thread_stacks();
rmr_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region((address)base);
rgn_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region((address)base);
}
ASSERT_TRUE(rmr_found.is_valid());
ASSERT_EQ(rmr_found.base(), (address)base);
ASSERT_TRUE(rgn_found.is_valid());
ASSERT_EQ(rgn_found.base(), (address)base);
bool precise_tracking_supported = false;
{
MemTracker::NmtVirtualMemoryLocker nvml;
VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rmr_found, [&](const CommittedMemoryRegion& cmr){
if (cmr.size() == size) {
VirtualMemoryTracker::Instance::tree()->visit_committed_regions(rgn_found, [&](const VirtualMemoryRegion& rgn){
if (rgn.size() == size) {
return false;
} else {
precise_tracking_supported = true;
check_covered_pages(cmr.base(), cmr.size(), (address)base, touch_pages, page_num);
check_covered_pages(rgn.base(), rgn.size(), (address)base, touch_pages, page_num);
}
return true;
});
@ -151,9 +150,9 @@ public:
{
MemTracker::NmtVirtualMemoryLocker nvml;
VirtualMemoryTracker::Instance::remove_released_region((address)base, size);
rmr_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region((address)base);
rgn_found = VirtualMemoryTracker::Instance::tree()->find_reserved_region((address)base);
}
ASSERT_TRUE(!rmr_found.is_valid());
ASSERT_TRUE(!rgn_found.is_valid());
}
static void test_committed_region() {

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2018, 2026, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -50,41 +50,41 @@ namespace {
};
}
#define check(vmt, rmr, regions) check_inner((vmt), (rmr), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__)
#define check(vmt, rgn, regions) check_inner((vmt), (rgn), (regions), ARRAY_SIZE(regions), __FILE__, __LINE__)
#define check_empty(vmt, rmr) \
#define check_empty(vmt, rgn) \
do { \
check_inner((vmt), (rmr), nullptr, 0, __FILE__, __LINE__); \
check_inner((vmt), (rgn), nullptr, 0, __FILE__, __LINE__); \
} while (false)
static void diagnostic_print(VirtualMemoryTracker& vmt, const ReservedMemoryRegion& rmr) {
LOG("In reserved region " PTR_FORMAT ", size %X:", p2i(rmr.base()), rmr.size());
vmt.tree()->visit_committed_regions(rmr, [&](CommittedMemoryRegion& region) {
LOG(" committed region: " PTR_FORMAT ", size %X", p2i(region.base()), region.size());
static void diagnostic_print(VirtualMemoryTracker& vmt, const VirtualMemoryRegion& rgn) {
LOG("In reserved region " PTR_FORMAT ", size %X:", p2i(rgn.base()), rgn.size());
vmt.tree()->visit_committed_regions(rgn, [&](VirtualMemoryRegion& crgn) {
LOG(" committed region: " PTR_FORMAT ", size %X", p2i(crgn.base()), crgn.size());
return true;
});
}
static void check_inner(VirtualMemoryTracker& vmt, const ReservedMemoryRegion& rmr, R* regions, size_t regions_size, const char* file, int line) {
static void check_inner(VirtualMemoryTracker& vmt, const VirtualMemoryRegion& rgn, R* regions, size_t regions_size, const char* file, int line) {
size_t i = 0;
size_t size = 0;
// Helpful log
diagnostic_print(vmt, rmr);
diagnostic_print(vmt, rgn);
#define WHERE " from " << file << ":" << line
vmt.tree()->visit_committed_regions(rmr, [&](CommittedMemoryRegion& region) {
vmt.tree()->visit_committed_regions(rgn, [&](VirtualMemoryRegion& crgn) {
EXPECT_LT(i, regions_size) << WHERE;
EXPECT_EQ(region.base(), regions[i]._addr) << WHERE;
EXPECT_EQ(region.size(), regions[i]._size) << WHERE;
size += region.size();
EXPECT_EQ(crgn.base(), regions[i]._addr) << WHERE;
EXPECT_EQ(crgn.size(), regions[i]._size) << WHERE;
size += crgn.size();
i++;
return true;
});
EXPECT_EQ(i, regions_size) << WHERE;
EXPECT_EQ(size, vmt.committed_size(&rmr)) << WHERE;
EXPECT_EQ(size, vmt.committed_size(&rgn)) << WHERE;
}
class VirtualMemoryTrackerTest {
@ -104,11 +104,11 @@ public:
NativeCallStack stack(&frame1, 1);
NativeCallStack stack2(&frame2, 1);
// Fetch the added RMR for the space
ReservedMemoryRegion rmr = rtree->find_reserved_region(addr);
// Fetch the added region for the space
VirtualMemoryRegion rgn = rtree->find_reserved_region(addr);
ASSERT_EQ(rmr.size(), size);
ASSERT_EQ(rmr.base(), addr);
ASSERT_EQ(rgn.size(), size);
ASSERT_EQ(rgn.base(), addr);
// Commit Size Granularity
const size_t cs = 0x1000;
@ -118,24 +118,24 @@ public:
{ // Commit one region
rtree->commit_region(addr + cs, cs, stack, diff);
R r[] = { {addr + cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent - lower address
rtree->commit_region(addr, cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent - higher address
rtree->commit_region(addr + 2 * cs, cs, stack, diff);
R r[] = { {addr, 3 * cs} };
check(vmt,rmr, r);
check(vmt, rgn, r);
}
// Cleanup
rtree->uncommit_region(addr, 3 * cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 0u);
ASSERT_EQ(vmt.committed_size(&rgn), 0u);
// Commit adjacent regions with different stacks
@ -143,14 +143,14 @@ public:
{ // Commit one region
rtree->commit_region(addr + cs, cs, stack, diff);
R r[] = { {addr + cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent - lower address
rtree->commit_region(addr, cs, stack2, diff);
R r[] = { {addr, cs},
{addr + cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent - higher address
@ -158,12 +158,12 @@ public:
R r[] = { {addr, cs},
{addr + cs, cs},
{addr + 2 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// Cleanup
rtree->uncommit_region(addr, 3 * cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 0u);
ASSERT_EQ(vmt.committed_size(&rgn), 0u);
}
static void test_add_committed_region_adjacent_overlapping() {
@ -180,11 +180,11 @@ public:
NativeCallStack stack(&frame1, 1);
NativeCallStack stack2(&frame2, 1);
// Fetch the added RMR for the space
ReservedMemoryRegion rmr = rtree->find_reserved_region(addr);
// Fetch the added region for the space
VirtualMemoryRegion rgn = rtree->find_reserved_region(addr);
ASSERT_EQ(rmr.size(), size);
ASSERT_EQ(rmr.base(), addr);
ASSERT_EQ(rgn.size(), size);
ASSERT_EQ(rgn.base(), addr);
// Commit Size Granularity
const size_t cs = 0x1000;
@ -196,28 +196,28 @@ public:
rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff);
R r[] = { {addr, 2 * cs},
{addr + 3 * cs, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent and overlapping
rtree->commit_region(addr + 2 * cs, 2 * cs, stack, diff);
R r[] = { {addr, 5 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// revert to two non-adjacent regions
rtree->uncommit_region(addr + 2 * cs, cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs);
ASSERT_EQ(vmt.committed_size(&rgn), 4 * cs);
{ // Commit overlapping and adjacent
rtree->commit_region(addr + cs, 2 * cs, stack, diff);
R r[] = { {addr, 5 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// Cleanup
rtree->uncommit_region(addr, 5 * cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 0u);
ASSERT_EQ(vmt.committed_size(&rgn), 0u);
// Commit adjacent and overlapping regions with different stacks
@ -227,7 +227,7 @@ public:
rtree->commit_region(addr + 3 * cs, 2 * cs, stack, diff);
R r[] = { {addr, 2 * cs},
{addr + 3 * cs, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit adjacent and overlapping
@ -235,20 +235,20 @@ public:
R r[] = { {addr, 2 * cs},
{addr + 2 * cs, 2 * cs},
{addr + 4 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// revert to two non-adjacent regions
rtree->commit_region(addr, 5 * cs, stack, diff);
rtree->uncommit_region(addr + 2 * cs, cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 4 * cs);
ASSERT_EQ(vmt.committed_size(&rgn), 4 * cs);
{ // Commit overlapping and adjacent
rtree->commit_region(addr + cs, 2 * cs, stack2, diff);
R r[] = { {addr, cs},
{addr + cs, 2 * cs},
{addr + 3 * cs, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
rtree->tree().remove_all();
@ -269,12 +269,12 @@ public:
NativeCallStack stack(&frame1, 1);
NativeCallStack stack2(&frame2, 1);
// Fetch the added RMR for the space
ReservedMemoryRegion rmr = rtree->find_reserved_region(addr);
// Fetch the added region for the space
VirtualMemoryRegion rgn = rtree->find_reserved_region(addr);
ASSERT_EQ(rmr.size(), size);
ASSERT_EQ(rmr.base(), addr);
ASSERT_EQ(rgn.size(), size);
ASSERT_EQ(rgn.base(), addr);
// Commit Size Granularity
const size_t cs = 0x1000;
@ -284,54 +284,54 @@ public:
{ // Commit one region
rtree->commit_region(addr, cs, stack, diff);
R r[] = { {addr, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit the same region
rtree->commit_region(addr, cs, stack, diff);
R r[] = { {addr, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit a succeeding region
rtree->commit_region(addr + cs, cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit over two regions
rtree->commit_region(addr, 2 * cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{// Commit first part of a region
rtree->commit_region(addr, cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit second part of a region
rtree->commit_region(addr + cs, cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit a third part
rtree->commit_region(addr + 2 * cs, cs, stack, diff);
R r[] = { {addr, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit in the middle of a region
rtree->commit_region(addr + 1 * cs, cs, stack, diff);
R r[] = { {addr, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// Cleanup
rtree->uncommit_region(addr, 3 * cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 0u);
ASSERT_EQ(vmt.committed_size(&rgn), 0u);
// With preceding region
@ -342,71 +342,71 @@ public:
{
R r[] = { {addr, cs},
{addr + 2 * cs, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
rtree->commit_region(addr + 3 * cs, cs, stack, diff);
{
R r[] = { {addr, cs},
{addr + 2 * cs, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
rtree->commit_region(addr + 4 * cs, cs, stack, diff);
{
R r[] = { {addr, cs},
{addr + 2 * cs, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// Cleanup
rtree->uncommit_region(addr, 5 * cs, diff);
ASSERT_EQ(vmt.committed_size(&rmr), 0u);
ASSERT_EQ(vmt.committed_size(&rgn), 0u);
// With different stacks
{ // Commit one region
rtree->commit_region(addr, cs, stack, diff);
R r[] = { {addr, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit the same region
rtree->commit_region(addr, cs, stack2, diff);
R r[] = { {addr, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit a succeeding region
rtree->commit_region(addr + cs, cs, stack, diff);
R r[] = { {addr, cs},
{addr + cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit over two regions
rtree->commit_region(addr, 2 * cs, stack, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{// Commit first part of a region
rtree->commit_region(addr, cs, stack2, diff);
R r[] = { {addr, cs},
{addr + cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit second part of a region
rtree->commit_region(addr + cs, cs, stack2, diff);
R r[] = { {addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit a third part
rtree->commit_region(addr + 2 * cs, cs, stack2, diff);
R r[] = { {addr, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
{ // Commit in the middle of a region
@ -414,7 +414,7 @@ public:
R r[] = { {addr, cs},
{addr + cs, cs},
{addr + 2 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
rtree->tree().remove_all();
@ -445,11 +445,11 @@ public:
NativeCallStack stack(&frame1, 1);
NativeCallStack stack2(&frame2, 1);
// Fetch the added RMR for the space
ReservedMemoryRegion rmr = rtree->find_reserved_region(addr);
// Fetch the added region for the space
VirtualMemoryRegion rgn = rtree->find_reserved_region(addr);
ASSERT_EQ(rmr.size(), size);
ASSERT_EQ(rmr.base(), addr);
ASSERT_EQ(rgn.size(), size);
ASSERT_EQ(rgn.base(), addr);
// Commit Size Granularity
const size_t cs = 0x1000;
@ -457,11 +457,11 @@ public:
{ // Commit regions
rtree->commit_region(addr, 3 * cs, stack, diff);
R r[] = { {addr, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
// Remove only existing
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{
@ -473,7 +473,7 @@ public:
rtree->uncommit_region(addr, cs, diff);
R r[] = { {addr + 2 * cs, cs},
{addr + 4 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// add back
@ -483,7 +483,7 @@ public:
rtree->uncommit_region(addr + 2 * cs, cs, diff);
R r[] = { {addr + 0 * cs, cs},
{addr + 4 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
// add back
@ -493,17 +493,17 @@ public:
rtree->uncommit_region(addr + 4 * cs, cs, diff);
R r[] = { {addr + 0 * cs, cs},
{addr + 2 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
}
rtree->uncommit_region(addr, 5 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove larger region
rtree->commit_region(addr + 1 * cs, cs, stack, diff);
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove smaller region - in the middle
@ -511,50 +511,50 @@ public:
rtree->uncommit_region(addr + 1 * cs, cs, diff);
R r[] = { { addr + 0 * cs, cs},
{ addr + 2 * cs, cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove smaller region - at the beginning
rtree->commit_region(addr, 3 * cs, stack, diff);
rtree->uncommit_region(addr + 0 * cs, cs, diff);
R r[] = { { addr + 1 * cs, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove smaller region - at the end
rtree->commit_region(addr, 3 * cs, stack, diff);
rtree->uncommit_region(addr + 2 * cs, cs, diff);
R r[] = { { addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove smaller, overlapping region - at the beginning
rtree->commit_region(addr + 1 * cs, 4 * cs, stack, diff);
rtree->uncommit_region(addr, 2 * cs, diff);
R r[] = { { addr + 2 * cs, 3 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
rtree->uncommit_region(addr + 1 * cs, 4 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
{ // Remove smaller, overlapping region - at the end
rtree->commit_region(addr, 3 * cs, stack, diff);
rtree->uncommit_region(addr + 2 * cs, 2 * cs, diff);
R r[] = { { addr, 2 * cs} };
check(vmt, rmr, r);
check(vmt, rgn, r);
rtree->uncommit_region(addr, 3 * cs, diff);
check_empty(vmt, rmr);
check_empty(vmt, rgn);
}
rtree->tree().remove_all();