Skip to content

Commit 1e086b1

Browse files
committed
8340103: Add internal set_flag function to VMATree
Reviewed-by: stuefe, azafari, gziemski
1 parent db535c8 commit 1e086b1

File tree

4 files changed

+366
-14
lines changed

4 files changed

+366
-14
lines changed

src/hotspot/share/nmt/nmtTreap.hpp

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,10 @@ class Treap {
234234
this->remove_all();
235235
}
236236

237+
int size() {
238+
return _node_count;
239+
}
240+
237241
void upsert(const K& k, const V& v) {
238242
TreapNode* found = find(_root, k);
239243
if (found != nullptr) {
@@ -304,6 +308,38 @@ class Treap {
304308
return candidate;
305309
}
306310

311+
TreapNode* closest_gt(const K& key) {
312+
TreapNode* candidate = nullptr;
313+
TreapNode* pos = _root;
314+
while (pos != nullptr) {
315+
int cmp_r = COMPARATOR::cmp(pos->key(), key);
316+
if (cmp_r > 0) {
317+
// Found a match, try to find a better one.
318+
candidate = pos;
319+
pos = pos->_left;
320+
} else if (cmp_r <= 0) {
321+
pos = pos->_right;
322+
}
323+
}
324+
return candidate;
325+
}
326+
327+
struct Range {
328+
TreapNode* start;
329+
TreapNode* end;
330+
Range(TreapNode* start, TreapNode* end)
331+
: start(start), end(end) {}
332+
};
333+
334+
// Return the range [start, end)
335+
// where start->key() <= addr < end->key().
336+
// Failure to find the range leads to start and/or end being null.
337+
Range find_enclosing_range(K addr) {
338+
TreapNode* start = closest_leq(addr);
339+
TreapNode* end = closest_gt(addr);
340+
return Range(start, end);
341+
}
342+
307343
// Visit all TreapNodes in ascending key order.
308344
template<typename F>
309345
void visit_in_order(F f) const {

src/hotspot/share/nmt/vmatree.cpp

Lines changed: 101 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
#include "precompiled.hpp"
2727
#include "logging/log.hpp"
2828
#include "nmt/vmatree.hpp"
29+
#include "utilities/globalDefinitions.hpp"
2930
#include "utilities/growableArray.hpp"
3031

3132
const VMATree::RegionData VMATree::empty_regiondata{NativeCallStackStorage::StackIndex{}, mtNone};
@@ -82,12 +83,12 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType
8283

8384
// Unless we know better, let B's outgoing state be the outgoing state of the node at or preceding A.
8485
// Consider the case where the found node is the start of a region enclosing [A,B)
85-
stB.out = leqA_n->val().out;
86+
stB.out = out_state(leqA_n);
8687

8788
// Direct address match.
8889
if (leqA_n->key() == A) {
8990
// Take over in state from old address.
90-
stA.in = leqA_n->val().in;
91+
stA.in = in_state(leqA_n);
9192

9293
// We may now be able to merge two regions:
9394
// If the node's old state matches the new, it becomes a noop. That happens, for example,
@@ -113,7 +114,7 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType
113114
// We add a new node, but only if there would be a state change. If there would not be a
114115
// state change, we just omit the node.
115116
// That happens, for example, when reserving within an already reserved region with identical metadata.
116-
stA.in = leqA_n->val().out; // .. and the region's prior state is the incoming state
117+
stA.in = out_state(leqA_n); // .. and the region's prior state is the incoming state
117118
if (stA.is_noop()) {
118119
// Nothing to do.
119120
} else {
@@ -134,7 +135,7 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType
134135
// outgoing state.
135136
_tree.visit_range_in_order(A + 1, B + 1, [&](TreapNode* head) {
136137
int cmp_B = PositionComparator::cmp(head->key(), B);
137-
stB.out = head->val().out;
138+
stB.out = out_state(head);
138139
if (cmp_B < 0) {
139140
// Record all nodes preceding B.
140141
to_be_deleted_inbetween_a_b.push({head->key(), head->val()});
@@ -215,3 +216,99 @@ VMATree::SummaryDiff VMATree::register_mapping(position A, position B, StateType
215216
}
216217
return diff;
217218
}
219+
220+
#ifdef ASSERT
221+
void VMATree::print_on(outputStream* out) {
222+
visit_in_order([&](TreapNode* current) {
223+
out->print(SIZE_FORMAT " (%s) - %s - ", current->key(), NMTUtil::tag_to_name(out_state(current).mem_tag()),
224+
statetype_to_string(out_state(current).type()));
225+
});
226+
out->cr();
227+
}
228+
#endif
229+
230+
VMATree::SummaryDiff VMATree::set_tag(const position start, const size size, const MemTag tag) {
231+
auto pos = [](TreapNode* n) { return n->key(); };
232+
position from = start;
233+
position end = from+size;
234+
size_t remsize = size;
235+
VMATreap::Range range(nullptr, nullptr);
236+
237+
// Find the next range to adjust and set range, remsize and from
238+
// appropriately. If it returns false, there is no valid next range.
239+
auto find_next_range = [&]() -> bool {
240+
range = _tree.find_enclosing_range(from);
241+
if ((range.start == nullptr && range.end == nullptr) ||
242+
(range.start != nullptr && range.end == nullptr)) {
243+
// There is no range containing the starting address
244+
assert(range.start->val().out.type() == StateType::Released, "must be");
245+
return false;
246+
} else if (range.start == nullptr && range.end != nullptr) {
247+
position found_end = pos(range.end);
248+
if (found_end >= end) {
249+
// The found address is outside of our range, we can end now.
250+
return false;
251+
}
252+
// There is at least one range [found_end, ?) which starts within [start, end)
253+
// Use this as the range instead.
254+
range = _tree.find_enclosing_range(found_end);
255+
remsize = end - found_end;
256+
from = found_end;
257+
}
258+
return true;
259+
};
260+
261+
bool success = find_next_range();
262+
if (!success) return SummaryDiff();
263+
assert(range.start != nullptr && range.end != nullptr, "must be");
264+
265+
end = MIN2(from + remsize, pos(range.end));
266+
IntervalState& out = out_state(range.start);
267+
StateType type = out.type();
268+
269+
SummaryDiff diff;
270+
// Ignore any released ranges, these must be mtNone and have no stack
271+
if (type != StateType::Released) {
272+
RegionData new_data = RegionData(out.stack(), tag);
273+
SummaryDiff result = register_mapping(from, end, type, new_data);
274+
diff.add(result);
275+
}
276+
277+
remsize = remsize - (end - from);
278+
from = end;
279+
280+
// If end < from + sz then there are multiple ranges for which to set the flag.
281+
while (end < from + remsize) {
282+
// Using register_mapping may invalidate the already found range, so we must
283+
// use find_next_range repeatedly
284+
bool success = find_next_range();
285+
if (!success) return diff;
286+
assert(range.start != nullptr && range.end != nullptr, "must be");
287+
288+
end = MIN2(from + remsize, pos(range.end));
289+
IntervalState& out = out_state(range.start);
290+
StateType type = out.type();
291+
292+
if (type != StateType::Released) {
293+
RegionData new_data = RegionData(out.stack(), tag);
294+
SummaryDiff result = register_mapping(from, end, type, new_data);
295+
diff.add(result);
296+
}
297+
remsize = remsize - (end - from);
298+
from = end;
299+
}
300+
301+
return diff;
302+
}
303+
304+
#ifdef ASSERT
305+
void VMATree::SummaryDiff::print_on(outputStream* out) {
306+
for (int i = 0; i < mt_number_of_tags; i++) {
307+
if (tag[i].reserve == 0 && tag[i].commit == 0) {
308+
continue;
309+
}
310+
out->print_cr("Tag %s R: " INT64_FORMAT " C: " INT64_FORMAT, NMTUtil::tag_to_enum_name((MemTag)i), tag[i].reserve,
311+
tag[i].commit);
312+
}
313+
}
314+
#endif

src/hotspot/share/nmt/vmatree.hpp

Lines changed: 46 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,11 @@
2626
#ifndef SHARE_NMT_VMATREE_HPP
2727
#define SHARE_NMT_VMATREE_HPP
2828

29+
#include "nmt/memTag.hpp"
2930
#include "nmt/nmtNativeCallStackStorage.hpp"
3031
#include "nmt/nmtTreap.hpp"
31-
#include "runtime/os.hpp"
3232
#include "utilities/globalDefinitions.hpp"
33+
#include "utilities/ostream.hpp"
3334
#include <cstdint>
3435

3536
// A VMATree stores a sequence of points on the natural number line.
@@ -42,6 +43,7 @@ class VMATree {
4243
// A position in memory.
4344
public:
4445
using position = size_t;
46+
using size = size_t;
4547

4648
class PositionComparator {
4749
public:
@@ -140,6 +142,14 @@ class VMATree {
140142
private:
141143
VMATreap _tree;
142144

145+
static IntervalState& in_state(TreapNode* node) {
146+
return node->val().in;
147+
}
148+
149+
static IntervalState& out_state(TreapNode* node) {
150+
return node->val().out;
151+
}
152+
143153
// AddressState saves the necessary information for performing online summary accounting.
144154
struct AddressState {
145155
position address;
@@ -162,40 +172,67 @@ class VMATree {
162172
delta reserve;
163173
delta commit;
164174
};
175+
165176
struct SummaryDiff {
166177
SingleDiff tag[mt_number_of_tags];
167178
SummaryDiff() {
168179
for (int i = 0; i < mt_number_of_tags; i++) {
169180
tag[i] = SingleDiff{0, 0};
170181
}
171182
}
183+
184+
void add(SummaryDiff& other) {
185+
for (int i = 0; i < mt_number_of_tags; i++) {
186+
tag[i].reserve += other.tag[i].reserve;
187+
tag[i].commit += other.tag[i].commit;
188+
}
189+
}
190+
191+
#ifdef ASSERT
192+
void print_on(outputStream* out);
193+
#endif
172194
};
173195

174196
private:
175197
SummaryDiff register_mapping(position A, position B, StateType state, const RegionData& metadata, bool use_tag_inplace = false);
176198

177199
public:
178-
SummaryDiff reserve_mapping(position from, position sz, const RegionData& metadata) {
179-
return register_mapping(from, from + sz, StateType::Reserved, metadata, false);
200+
SummaryDiff reserve_mapping(position from, size size, const RegionData& metadata) {
201+
return register_mapping(from, from + size, StateType::Reserved, metadata, false);
202+
}
203+
204+
SummaryDiff commit_mapping(position from, size size, const RegionData& metadata, bool use_tag_inplace = false) {
205+
return register_mapping(from, from + size, StateType::Committed, metadata, use_tag_inplace);
180206
}
181207

182-
SummaryDiff commit_mapping(position from, position sz, const RegionData& metadata, bool use_tag_inplace = false) {
183-
return register_mapping(from, from + sz, StateType::Committed, metadata, use_tag_inplace);
208+
// Given an interval and a tag, find all reserved and committed ranges at least
209+
// partially contained within that interval and set their tag to the one provided.
210+
// This may cause merging and splitting of ranges.
211+
// Released regions are ignored.
212+
SummaryDiff set_tag(position from, size size, MemTag tag);
213+
214+
SummaryDiff uncommit_mapping(position from, size size, const RegionData& metadata) {
215+
return register_mapping(from, from + size, StateType::Reserved, metadata, true);
184216
}
185217

186-
SummaryDiff uncommit_mapping(position from, position sz, const RegionData& metadata) {
187-
return register_mapping(from, from + sz, StateType::Reserved, metadata, true);
218+
SummaryDiff release_mapping(position from, size size) {
219+
return register_mapping(from, from + size, StateType::Released, VMATree::empty_regiondata);
188220
}
189221

190-
SummaryDiff release_mapping(position from, position sz) {
191-
return register_mapping(from, from + sz, StateType::Released, VMATree::empty_regiondata);
222+
VMATreap& tree() {
223+
return _tree;
192224
}
193225

194226
public:
195227
template<typename F>
196228
void visit_in_order(F f) const {
197229
_tree.visit_in_order(f);
198230
}
231+
232+
#ifdef ASSERT
233+
void print_on(outputStream* out);
234+
#endif
235+
199236
};
200237

201238
#endif

0 commit comments

Comments
 (0)