RFR: JDK-8293313: NMT: Rework MallocLimit [v4]

Thomas Stuefe stuefe at openjdk.org
Fri Jan 27 06:29:20 UTC 2023


On Wed, 25 Jan 2023 17:41:41 GMT, Gerard Ziemski <gziemski at openjdk.org> wrote:

>>> 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?

Yes, you are right, its better. Can remove vmError.hpp dependency from the header too.

-------------

PR: https://git.openjdk.org/jdk/pull/11371


More information about the hotspot-dev mailing list