RFR: JDK-8293313: NMT: Rework MallocLimit [v4]
Gerard Ziemski
gziemski at openjdk.org
Wed Jan 25 17:44:47 UTC 2023
On Wed, 25 Jan 2023 06:51:04 GMT, Thomas Stuefe <stuefe at openjdk.org> wrote:
>> src/hotspot/share/services/mallocTracker.inline.hpp line 56:
>>
>>> 54: size_t so_far = as_snapshot()->total();
>>> 55: if ((so_far + s) > l->sz) { // hit the limit
>>> 56: if (!suppress_limit_handling()) {
>>
>> I would prefer to see `suppress_limit_handling()` checked inside `total_limit_reached()`, same for `category_limit_reached()`. This way we would force those APIs to always obey the suppression without having to bother to add `suppress_limit_handling()`, they could call `VMError::is_error_reported()` directly.
>
>> I would prefer to see `suppress_limit_handling()` checked inside `total_limit_reached()`, same for `category_limit_reached()`. This way we would force those APIs to always obey the suppression without having to bother to add `suppress_limit_handling()`, they could call `VMError::is_error_reported()` directly.
>
> Note that `total_limit_reached()` and `category_limit_reached()` are private APIs.
>
> If we move `suppress_limit_handling()` into `total_limit_reached()`, `total_limit_reached()` would need to report it back to `MallocMemorySummary::check_exceeds_limit` since its processed there too, it affects the return code. So `total_limit_reached()` cannot be void anymore, and gets somewhat more complex. I prefer it this way, tbh.
I'm not following.
If we get rid of `suppress_limit_handling()` SPI, and do:
bool MallocMemorySummary::total_limit_reached(size_t s, size_t so_far, const malloclimit* limit) {
if (VMError::is_error_reported()) {
return false;
}
#define FORMATTED \
"MallocLimit: reached global limit (triggering allocation size: " PROPERFMT ", allocated so far: " PROPERFMT ", limit: " PROPERFMT ") ", \
PROPERFMTARGS(s), PROPERFMTARGS(so_far), PROPERFMTARGS(limit->sz)
if (limit->mode == MallocLimitMode::trigger_fatal) {
fatal(FORMATTED);
} else {
log_warning(nmt)(FORMATTED);
}
#undef FORMATTED
return true;
}
bool MallocMemorySummary::category_limit_reached(MEMFLAGS f, size_t s, size_t so_far, const malloclimit* limit) {
if (VMError::is_error_reported()) {
return false;
}
#define FORMATTED \
"MallocLimit: reached category "%s" limit (triggering allocation size: " PROPERFMT ", allocated so far: " PROPERFMT ", limit: " PROPERFMT ") ", \
NMTUtil::flag_to_enum_name(f), PROPERFMTARGS(s), PROPERFMTARGS(so_far), PROPERFMTARGS(limit->sz)
if (limit->mode == MallocLimitMode::trigger_fatal) {
fatal(FORMATTED);
} else {
log_warning(nmt)(FORMATTED);
}
#undef FORMATTED
return true;
}
then we can simply have:
// Returns true if allocating s bytes on f would trigger either global or the category limit
inline bool MallocMemorySummary::check_exceeds_limit(size_t s, MEMFLAGS f) {
// Note: checks are ordered to have as little impact as possible on the standard code path,
// when MallocLimit is unset, resp. it is set but we have reached no limit yet.
// Somewhat expensive are:
// - as_snapshot()->total(), total malloc load (requires iteration over arena types)
// - VMError::is_error_reported() is a load from a volatile.
if (MallocLimitHandler::have_limit()) {
// Global Limit ?
const malloclimit* l = MallocLimitHandler::global_limit();
if (l->sz > 0) {
size_t so_far = as_snapshot()->total();
if ((so_far + s) > l->sz) { // hit the limit
if (total_limit_reached(s, so_far, l)) {
return true;
}
}
} else {
// Category Limit ?
l = MallocLimitHandler::category_limit(f);
if (l->sz > 0) {
const MallocMemory* mm = as_snapshot()->by_type(f);
size_t so_far = mm->malloc_size() + mm->arena_size();
if ((so_far + s) > l->sz) {
if (category_limit_reached(f, s, so_far, l)) {
return true;
}
}
}
}
}
return false;
}
Doesn't that work?
-------------
PR: https://git.openjdk.org/jdk/pull/11371
More information about the hotspot-dev
mailing list