Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,189 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* The contents of this file are subject to the terms of either the Universal Permissive License
* v 1.0 as shown at https://oss.oracle.com/licenses/upl
*
* or the following license:
*
* Redistribution and use in source and binary forms, with or without modification, are permitted
* provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this list of conditions
* and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice, this list of
* conditions and the following disclaimer in the documentation and/or other materials provided with
* the distribution.
*
* 3. Neither the name of the copyright holder nor the names of its contributors may be used to
* endorse or promote products derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
* FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
* CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY
* WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package org.openjdk.jmc.flightrecorder.rules.jdk.memory;

import static org.openjdk.jmc.common.unit.UnitLookup.NUMBER;
import static org.openjdk.jmc.common.unit.UnitLookup.NUMBER_UNITY;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;
import java.util.concurrent.RunnableFuture;

import org.openjdk.jmc.common.item.IItemCollection;
import org.openjdk.jmc.common.unit.IQuantity;
import org.openjdk.jmc.common.unit.UnitLookup;
import org.openjdk.jmc.common.util.IPreferenceValueProvider;
import org.openjdk.jmc.common.util.TypedPreference;
import org.openjdk.jmc.flightrecorder.jdk.JdkAggregators;
import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
import org.openjdk.jmc.flightrecorder.rules.IResult;
import org.openjdk.jmc.flightrecorder.rules.IResultValueProvider;
import org.openjdk.jmc.flightrecorder.rules.IRule;
import org.openjdk.jmc.flightrecorder.rules.ResultBuilder;
import org.openjdk.jmc.flightrecorder.rules.Severity;
import org.openjdk.jmc.flightrecorder.rules.TypedResult;
import org.openjdk.jmc.flightrecorder.rules.jdk.messages.internal.Messages;
import org.openjdk.jmc.flightrecorder.rules.util.JfrRuleTopics;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit.EventAvailability;
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit.RequiredEventsBuilder;

public class ZGCAllocationStallRule implements IRule {

private static final String ZGC_RESULT_ID = "ZGCAllocationStallRule"; //$NON-NLS-1$

private static final Map<String, EventAvailability> REQUIRED_EVENTS = RequiredEventsBuilder.create()
.addEventType(JdkTypeIDs.ZGC_ALLOCATION_STALL, EventAvailability.AVAILABLE).build();

public static final TypedResult<IQuantity> ZGC_ALLOCATION_STALL_EVENTS = new TypedResult<>(
"zgcAllocationStallCount", //$NON-NLS-1$
JdkAggregators.ZGC_ALLOCATION_STALL_COUNT, UnitLookup.NUMBER, IQuantity.class);

public static final TypedResult<IQuantity> ZGC_ALLOCATION_STALL_LONGEST_DURATION = new TypedResult<>(
"zgcAllocationStallLongestDuration", //$NON-NLS-1$
JdkAggregators.ZGC_ALLOCATION_STALL_COUNT, UnitLookup.TIMESPAN, IQuantity.class);

public static final TypedResult<IQuantity> ZGC_ALLOCATION_STALL_TOTAL_DURATION = new TypedResult<>(
"zgcAllocationStallTotalDuration", //$NON-NLS-1$
JdkAggregators.ZGC_ALLOCATION_STALL_COUNT, UnitLookup.TIMESPAN, IQuantity.class);

public static final TypedResult<IQuantity> ZGC_ALLOCATION_STALL_PER_MINUTE = new TypedResult<>(
"zgcAllocationStallPerMinute", //$NON-NLS-1$
Messages.getString(Messages.ZGCAllocationStallRule_RATE),
Messages.getString(Messages.ZGCAllocationStallRule_RATE_LONG), UnitLookup.NUMBER, IQuantity.class);
public static final TypedPreference<IQuantity> ALLOCATION_STALL_INFO_LIMIT = new TypedPreference<>(
"allocation.stall.rate.info.limit", //$NON-NLS-1$
Messages.getString(Messages.ZGCAllocationStallRule_CONFIG_INFO_LIMIT),
Messages.getString(Messages.ZGCAllocationStallRule_CONFIG_INFO_LIMIT_LONG), NUMBER,
NUMBER_UNITY.quantity(10));

public static final TypedPreference<IQuantity> ALLOCATION_STALL_WARNING_LIMIT = new TypedPreference<>(
"allocation.stall.rate.warning.limit", //$NON-NLS-1$
Messages.getString(Messages.ZGCAllocationStallRule_CONFIG_WARN_LIMIT),
Messages.getString(Messages.ZGCAllocationStallRule_CONFIG_WARN_LIMIT_LONG), NUMBER,
NUMBER_UNITY.quantity(100));

private static final List<TypedPreference<?>> CONFIG_ATTRIBUTES = Arrays
.<TypedPreference<?>> asList(ALLOCATION_STALL_INFO_LIMIT, ALLOCATION_STALL_WARNING_LIMIT);

private static final Collection<TypedResult<?>> RESULT_ATTRIBUTES = Arrays.<TypedResult<?>> asList(
TypedResult.SCORE, ZGC_ALLOCATION_STALL_EVENTS, ZGC_ALLOCATION_STALL_LONGEST_DURATION,
ZGC_ALLOCATION_STALL_TOTAL_DURATION, ZGC_ALLOCATION_STALL_PER_MINUTE);

@Override
public String getId() {
return ZGC_RESULT_ID;
}

@Override
public String getTopic() {
return JfrRuleTopics.GARBAGE_COLLECTION;
}

@Override
public String getName() {
return Messages.getString(Messages.ZGCAllocationStall_RULE_NAME);
}

@Override
public Map<String, EventAvailability> getRequiredEvents() {
return REQUIRED_EVENTS;
}

private IResult getResult(
IItemCollection items, IPreferenceValueProvider valueProvider, IResultValueProvider resultProvider) {
long infoLimit = valueProvider.getPreferenceValue(ALLOCATION_STALL_INFO_LIMIT).clampedLongValueIn(NUMBER_UNITY);
long warningLimit = valueProvider.getPreferenceValue(ALLOCATION_STALL_WARNING_LIMIT)
.clampedLongValueIn(NUMBER_UNITY);

IQuantity zgcAllocationStallCount = items.getAggregate(JdkAggregators.ZGC_ALLOCATION_STALL_COUNT);
IQuantity zgcAllocationStallTotalDuration = items.getAggregate(JdkAggregators.TOTAL_ZGC_ALLOCATION_STALL);
IQuantity zgcAllocationStallLongestDuration = items.getAggregate(JdkAggregators.LONGEST_ZGC_ALLOCATION_STALL);
if (zgcAllocationStallCount != null && zgcAllocationStallCount.doubleValue() > 0) {

//Calculate time after JVM Start
IQuantity timeAfterJVMStart = RulesToolkit.getEarliestStartTime(items)
.subtract(items.getAggregate(JdkAggregators.JVM_START_TIME));

//Calculate Stall Per minute
IQuantity stallPerMinute = UnitLookup.NUMBER_UNITY
.quantity(zgcAllocationStallTotalDuration.doubleValueIn(UnitLookup.MINUTE)
/ timeAfterJVMStart.doubleValueIn(UnitLookup.MINUTE));

double score = RulesToolkit.mapExp100(stallPerMinute.clampedLongValueIn(UnitLookup.NUMBER_UNITY), infoLimit,
warningLimit);

return ResultBuilder.createFor(ZGCAllocationStallRule.this, valueProvider).setSeverity(Severity.get(score))
.setSummary(Messages.getString(Messages.ZGCAllocationStall_TEXT_INFO)
.concat(Messages.getString(Messages.ZGCAllocationStall_TEXT_WARN)))
.addResult(TypedResult.SCORE, UnitLookup.NUMBER_UNITY.quantity(score))
.addResult(ZGC_ALLOCATION_STALL_EVENTS, zgcAllocationStallCount)
.addResult(ZGC_ALLOCATION_STALL_TOTAL_DURATION, zgcAllocationStallTotalDuration)
.addResult(ZGC_ALLOCATION_STALL_LONGEST_DURATION, zgcAllocationStallLongestDuration)
.addResult(ZGC_ALLOCATION_STALL_PER_MINUTE, stallPerMinute).build();

}
return ResultBuilder.createFor(ZGCAllocationStallRule.this, valueProvider).setSeverity(Severity.OK)
.setSummary(Messages.getString(Messages.ZGCAllocationStall_TEXT_INFO)
.concat(Messages.getString(Messages.ZGCAllocationStall_TEXT_OK)))
.build();
}

@Override
public RunnableFuture<IResult> createEvaluation(
final IItemCollection items, final IPreferenceValueProvider preferenceValueProvider,
final IResultValueProvider dependencyResults) {
FutureTask<IResult> evaluationTask = new FutureTask<>(new Callable<IResult>() {
@Override
public IResult call() throws Exception {
return getResult(items, preferenceValueProvider, dependencyResults);
}
});
return evaluationTask;
}

@Override
public Collection<TypedPreference<?>> getConfigurationAttributes() {
return CONFIG_ATTRIBUTES;
}

@Override
public Collection<TypedResult<?>> getResults() {
return RESULT_ATTRIBUTES;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,13 @@ public class Messages {
public static final String GcFreedRatioRule_RESULT_OK = "GcFreedRatioRule_RESULT_OK"; //$NON-NLS-1$
public static final String GcFreedRatioRule_RESULT_SHORT_DESCRIPTION = "GcFreedRatioRule_RESULT_SHORT_DESCRIPTION"; //$NON-NLS-1$
public static final String GarbageCollectionInfo_RULE_NAME = "GarbageCollectionInfo_RULE_NAME"; //$NON-NLS-1$
public static final String ZGCAllocationStall_RULE_NAME = "ZGCAllocationStall_RULE_NAME"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_CONFIG_INFO_LIMIT = "ZGCAllocationStallRule_CONFIG_INFO_LIMIT"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_CONFIG_INFO_LIMIT_LONG = "ZGCAllocationStallRule_CONFIG_INFO_LIMIT_LONG"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_RATE = "ZGCAllocationStallRule_RATE"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_RATE_LONG = "ZGCAllocationStallRule_RATE_LONG"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_CONFIG_WARN_LIMIT = "ZGCAllocationStallRule_CONFIG_WARN_LIMIT"; //$NON-NLS-1$
public static final String ZGCAllocationStallRule_CONFIG_WARN_LIMIT_LONG = "ZGCAllocationStallRule_CONFIG_WARN_LIMIT_LONG"; //$NON-NLS-1$
public static final String GcFreedRatioRule_RULE_NAME = "GcFreedRatioRule_RULE_NAME"; //$NON-NLS-1$
public static final String GcFreedRatioRule_WINDOW_SIZE = "GcFreedRatioRule_WINDOW_SIZE"; //$NON-NLS-1$
public static final String GcFreedRatioRule_WINDOW_SIZE_DESC = "GcFreedRatioRule_WINDOW_SIZE_DESC"; //$NON-NLS-1$
Expand Down Expand Up @@ -476,7 +483,7 @@ public class Messages {
public static final String ManyRunningProcessesRule_TEXT_RECOMMENDATION = "ManyRunningProcessesRule_TEXT_RECOMMENDATION"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_RULE_NAME = "MetaspaceOomRuleFactory_RULE_NAME"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_OK = "MetaspaceOomRuleFactory_TEXT_OK"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_CAUSE = "MetaspaceOomRuleFactory_TEXT_CAUSE"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_CAUSE = "MetaspaceOomRuleFactory_TEXT_CAUSE"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_SET_ACTION = "MetaspaceOomRuleFactory_TEXT_SET_ACTION"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_INCREASE_ACTION = "MetaspaceOomRuleFactory_TEXT_INCREASE_ACTION"; //$NON-NLS-1$
public static final String MetaspaceOomRuleFactory_TEXT_WARN = "MetaspaceOomRuleFactory_TEXT_WARN"; //$NON-NLS-1$
Expand All @@ -503,6 +510,9 @@ public class Messages {
public static final String MultipleAgentsRule_NATIVE_WARNING_LIMIT_LONG = "MultipleAgentsRule_NATIVE_WARNING_LIMIT_LONG"; //$NON-NLS-1$;
public static final String NumberOfGcThreadsRuleFactory_TEXT_INFO = "NumberOfGcThreadsRuleFactory_TEXT_INFO"; //$NON-NLS-1$
public static final String NumberOfGcThreadsRuleFactory_TEXT_INFO_LONG = "NumberOfGcThreadsRuleFactory_TEXT_INFO_LONG"; //$NON-NLS-1$
public static final String ZGCAllocationStall_TEXT_INFO = "ZGCAllocationStall_TEXT_INFO"; //$NON-NLS-1$
public static final String ZGCAllocationStall_TEXT_WARN = "ZGCAllocationStall_TEXT_WARN"; //$NON-NLS-1$
public static final String ZGCAllocationStall_TEXT_OK = "ZGCAllocationStall_TEXT_OK"; //$NON-NLS-1$
public static final String ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE = "ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE"; //$NON-NLS-1$
public static final String ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE_DESC = "ObjectStatisticsDataProvider_AGGR_LIVE_SIZE_INCREASE_DESC"; //$NON-NLS-1$
public static final String ObjectStatisticsDataProvider_AGGR_LIVE_INSTANCES_INCREASE = "ObjectStatisticsDataProvider_AGGR_LIVE_INSTANCES_INCREASE"; //$NON-NLS-1$
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
#
# Copyright (c) 2018, 2024, Oracle and/or its affiliates. All rights reserved.
# Copyright (c) 2018, 2025, Oracle and/or its affiliates. All rights reserved.
#
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
#
Expand Down Expand Up @@ -86,6 +86,7 @@ org.openjdk.jmc.flightrecorder.rules.jdk.memory.AutoBoxingRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.CompressedOopsRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.FullGcRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.GarbageCollectionInfoRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.ZGCAllocationStallRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.GcLockerRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.GcStallRule
org.openjdk.jmc.flightrecorder.rules.jdk.memory.GcFreedRatioRule
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -751,3 +751,13 @@ VMOperationRuleFactory_TEXT_WARN_COMBINED_DURATION=There are long lasting blocki
# {longestOperationDuration} is a time period, {longestOperation} is a JVM operation type, {longestOperationCaller} is a thread name, {longestOperationStartTime} is a time stamp
VMOperationRuleFactory_TEXT_WARN_LONG=There are long lasting blocking VM operations in this recording. The longest was of type {longestOperation} and lasted for {longestOperationDuration}. It was initiated from thread {longestOperationCaller} and happened at {longestOperationStartTime}. VM operations are JVM internal operations. Some VM operations are executed synchronously (i.e. will block the calling thread), and some need to be executed at so called safe points. Safe point polling is a cooperative suspension mechanism that halts byte code execution in the JVM. A VM operation occurring at a safe point will effectively be "stopping the world", meaning that no Java code will be executing in any thread while executing VM operations at that safe point. Long lasting VM operations executing at safe points can decrease the responsiveness of an application. If you do find such VM operations, then the type of operation and its caller thread provide vital information to understand why the VM operation happened. To find more details, check if there is an event in the caller thread intersecting this event time wise. Looking at the stack trace for such an event can help determining what caused it. See [Runtime Overview](http://openjdk.java.net/groups/hotspot/docs/RuntimeOverview.html) for further information.
VMOperationRuleFactory_TEXT_WARN_LONG_COMBINED_DURATION=There are long lasting blocking VM operations in this recording. The longest was created from multiple close consecutive operations that were of type {longestOperation} and lasted for {longestOperationDuration} in total. They were initiated from thread {longestOperationCaller} and started at {longestOperationStartTime}. VM operations are JVM internal operations. Some VM operations are executed synchronously (i.e. will block the calling thread), and some need to be executed at so called safe points. Safe point polling is a cooperative suspension mechanism that halts byte code execution in the JVM. A VM operation occurring at a safe point will effectively be "stopping the world", meaning that no Java code will be executing in any thread while executing VM operations at that safe point. Long lasting VM operations executing at safe points can decrease the responsiveness of an application. If you do find such VM operations, then the type of operation and its caller thread provide vital information to understand why the VM operation happened. To find more details, check if there is an event in the caller thread intersecting this event time wise. Looking at the stack trace for such an event can help determining what caused it. See [Runtime Overview](http://openjdk.java.net/groups/hotspot/docs/RuntimeOverview.html) for further information.
ZGCAllocationStall_RULE_NAME=ZGC Allocation Stall Rate
ZGCAllocationStall_TEXT_INFO=In ZGC, a type of concurrent Garbage Collection (GC) algorithm, GC threads run concurrently with application threads, resulting in minimal stop-the-world pauses. However application threads can overrun the GC threads, allocating objects faster than GC threads can reclaim memory. in such cases, the JVM temporarily stops allocating application threads. This is called "Allocation Stall".\n Allocation Stalls occurs due to the following reasons:\n 1. High Object Allocation Rate: if your application creates objects at a very high rate, it can overwhelm the GC's ability to reclaim memory quickly enough, leading to stalls\n 2. Java Heap size is not sufficient: Having more free room in the heap can give more time for GC threads to perform their GC cycle and reclaim memory to satisfy new allocations happening concurrently.\n 3. Insufficient resources available for the GC threads: number of GC threads or the CPU allocated for them is not enough to finish the GC cycle and reclaim the memory compared to allocations done by application threads.\n
ZGCAllocationStall_TEXT_WARN=\n{zgcAllocationStallCount} Allocation Stall events observed. Total time spent in waiting for memory to become available is {zgcAllocationStallTotalDuration} and the maximum duration is {zgcAllocationStallLongestDuration}. Stall time rate per minute is {zgcAllocationStallPerMinute}.
ZGCAllocationStall_TEXT_OK=There are no occurrence of Allocation Stall Events.
ZGCAllocationStallRule_CONFIG_INFO_LIMIT=ZGC Allocation Stall Rate info limit
ZGCAllocationStallRule_CONFIG_INFO_LIMIT_LONG=The ZGC allocation stall time per minute needed to trigger an info notice
ZGCAllocationStallRule_CONFIG_WARN_LIMIT=ZGC Allocation Stall Rate warning limit
ZGCAllocationStallRule_CONFIG_WARN_LIMIT_LONG=The ZGC allocation stall time per minute needed to trigger a warning
ZGCAllocationStallRule_RATE=Allocation Stall time per minute
ZGCAllocationStallRule_RATE_LONG=Average ZGC allocation stalls per minute over the recording period
Loading