Skip to content

Commit c725078

Browse files
committed
7231: JMC createReport for JMC8 Automated Analysis fails to evaluate several rules
Reviewed-by: hirt, hdafgard
1 parent 90197d6 commit c725078

File tree

6 files changed

+124
-10
lines changed

6 files changed

+124
-10
lines changed

core/org.openjdk.jmc.flightrecorder.rules/src/main/java/org/openjdk/jmc/flightrecorder/rules/messages/internal/Messages.java

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
*
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -43,10 +43,12 @@ public class Messages {
4343
public static final String ItemTreeToolkit_BREAKDOWN_HEADER_LAYERS = "ItemTreeToolkit_BREAKDOWN_HEADER_LAYERS"; //$NON-NLS-1$
4444
public static final String ItemTreeToolkit_BREAKDOWN_HEADER_MAX_DURATION_EVENT_CHAIN = "ItemTreeToolkit_BREAKDOWN_HEADER_MAX_DURATION_EVENT_CHAIN"; //$NON-NLS-1$
4545
public static final String ItemTreeToolkit_BREAKDOWN_LAYER_CAPTION = "ItemTreeToolkit_BREAKDOWN_LAYER_CAPTION"; //$NON-NLS-1$
46-
public static final String Result_SHORT_RECORDING = "Result_SHORT_RECORDING";; //$NON-NLS-1$
46+
public static final String Result_SHORT_RECORDING = "Result_SHORT_RECORDING"; //$NON-NLS-1$
4747
public static final String RulesToolkit_ATTRIBUTE_NOT_FOUND = "RulesToolkit_ATTRIBUTE_NOT_FOUND"; //$NON-NLS-1$
4848
public static final String RulesToolkit_ATTRIBUTE_NOT_FOUND_LONG = "RulesToolkit_ATTRIBUTE_NOT_FOUND_LONG"; //$NON-NLS-1$
49+
public static final String RulesToolkit_EVALUATION_ERROR_DESCRIPTION = "RulesToolkit_EVALUATION_ERROR_DESCRIPTION"; //$NON-NLS-1$
4950
public static final String RulesToolkit_EVERY_CHUNK = "RulesToolkit_EVERY_CHUNK"; //$NON-NLS-1$
51+
public static final String RulesToolkit_RULE_IGNORED = "RulesToolkit_RULE_IGNORED"; //$NON-NLS-1$
5052
public static final String RulesToolkit_RULE_RECOMMENDS_EVENTS = "RulesToolkit_RULE_RECOMMENDS_EVENTS"; //$NON-NLS-1$
5153
public static final String RulesToolkit_RULE_REQUIRES_EVENTS = "RulesToolkit_RULE_REQUIRES_EVENTS"; //$NON-NLS-1$
5254
public static final String RulesToolkit_RULE_REQUIRES_EVENTS_LONG = "RulesToolkit_RULE_REQUIRES_EVENTS_LONG"; //$NON-NLS-1$
@@ -57,6 +59,7 @@ public class Messages {
5759
public static final String RulesToolkit_RULE_REQUIRES_SOME_EVENTS = "RulesToolkit_RULE_REQUIRES_SOME_EVENTS"; //$NON-NLS-1$
5860
public static final String RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE = "RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE"; //$NON-NLS-1$
5961
public static final String RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE_LONG = "RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE_LONG"; //$NON-NLS-1$
62+
public static final String RulesToolkit_RULE_RESULT_RETRIEVAL_ERROR = "RulesToolkit_RULE_RESULT_RETRIEVAL_ERROR"; //$NON-NLS-1$
6063
public static final String RulesToolkit_TOO_FEW_EVENTS = "RulesToolkit_TOO_FEW_EVENTS"; //$NON-NLS-1$
6164
public static final String Severity_INFORMATION = "Severity_INFORMATION"; //$NON-NLS-1$
6265
public static final String Severity_NOT_APPLICABLE = "Severity_NOT_APPLICABLE"; //$NON-NLS-1$

core/org.openjdk.jmc.flightrecorder.rules/src/main/java/org/openjdk/jmc/flightrecorder/rules/util/RulesToolkit.java

Lines changed: 89 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, 2020, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
*
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -47,11 +47,14 @@
4747
import java.util.Map.Entry;
4848
import java.util.Queue;
4949
import java.util.Set;
50+
import java.util.concurrent.CompletableFuture;
5051
import java.util.concurrent.ConcurrentLinkedQueue;
5152
import java.util.concurrent.ExecutionException;
5253
import java.util.concurrent.Future;
5354
import java.util.concurrent.RunnableFuture;
5455
import java.util.function.Predicate;
56+
import java.util.logging.Level;
57+
import java.util.logging.Logger;
5558
import java.util.regex.Matcher;
5659
import java.util.regex.Pattern;
5760

@@ -80,6 +83,7 @@
8083
import org.openjdk.jmc.common.unit.UnitLookup;
8184
import org.openjdk.jmc.common.util.IPreferenceValueProvider;
8285
import org.openjdk.jmc.common.util.LabeledIdentifier;
86+
import org.openjdk.jmc.common.util.Pair;
8387
import org.openjdk.jmc.common.util.PredicateToolkit;
8488
import org.openjdk.jmc.common.util.StringToolkit;
8589
import org.openjdk.jmc.common.version.JavaVersion;
@@ -88,10 +92,12 @@
8892
import org.openjdk.jmc.flightrecorder.jdk.JdkAttributes;
8993
import org.openjdk.jmc.flightrecorder.jdk.JdkFilters;
9094
import org.openjdk.jmc.flightrecorder.jdk.JdkTypeIDs;
95+
import org.openjdk.jmc.flightrecorder.rules.DependsOn;
9196
import org.openjdk.jmc.flightrecorder.rules.IResult;
9297
import org.openjdk.jmc.flightrecorder.rules.IResultValueProvider;
9398
import org.openjdk.jmc.flightrecorder.rules.IRule;
9499
import org.openjdk.jmc.flightrecorder.rules.ResultBuilder;
100+
import org.openjdk.jmc.flightrecorder.rules.ResultProvider;
95101
import org.openjdk.jmc.flightrecorder.rules.RuleRegistry;
96102
import org.openjdk.jmc.flightrecorder.rules.Severity;
97103
import org.openjdk.jmc.flightrecorder.rules.messages.internal.Messages;
@@ -1208,12 +1214,59 @@ public static Map<IRule, Future<IResult>> evaluateParallel(
12081214
if (nThreads < 1) {
12091215
nThreads = Runtime.getRuntime().availableProcessors();
12101216
}
1217+
ResultProvider resultProvider = new ResultProvider();
12111218
Map<IRule, Future<IResult>> resultFutures = new HashMap<>();
12121219
Queue<RunnableFuture<IResult>> futureQueue = new ConcurrentLinkedQueue<>();
1220+
// Map using the rule name as a key, and a Pair containing the rule (left) and it's dependency (right)
1221+
Map<String, Pair<IRule, IRule>> rulesWithDependencies = new HashMap<>();
1222+
Map<IRule, IResult> computedResults = new HashMap<>();
12131223
for (IRule rule : rules) {
1214-
RunnableFuture<IResult> resultFuture = rule.createEvaluation(items, preferences, null);
1215-
resultFutures.put(rule, resultFuture);
1216-
futureQueue.add(resultFuture);
1224+
if (matchesEventAvailabilityMap(items, rule.getRequiredEvents())) {
1225+
if (hasDependency(rule)) {
1226+
IRule depRule = rules.stream().filter(r -> r.getId().equals(getRuleDependencyName(rule)))
1227+
.findFirst().orElse(null);
1228+
rulesWithDependencies.put(rule.getId(), new Pair<>(rule, depRule));
1229+
} else {
1230+
RunnableFuture<IResult> resultFuture = rule.createEvaluation(items, preferences, resultProvider);
1231+
resultFutures.put(rule, resultFuture);
1232+
futureQueue.add(resultFuture);
1233+
}
1234+
} else {
1235+
resultFutures.put(rule, CompletableFuture.completedFuture(getNotApplicableResult(rule, preferences,
1236+
Messages.getString(Messages.RulesToolkit_RULE_IGNORED))));
1237+
}
1238+
}
1239+
for (String ruleName : rulesWithDependencies.keySet()) {
1240+
IRule rule = rulesWithDependencies.get(ruleName).left;
1241+
IRule depRule = rulesWithDependencies.get(ruleName).right;
1242+
Future<IResult> depResultFuture = resultFutures.get(depRule);
1243+
if (depResultFuture == null) {
1244+
resultFutures.put(rule, CompletableFuture.completedFuture(getNotApplicableResult(rule, preferences,
1245+
Messages.getString(Messages.RulesToolkit_EVALUATION_ERROR_DESCRIPTION))));
1246+
} else {
1247+
IResult depResult = null;
1248+
if (!depResultFuture.isDone()) {
1249+
((Runnable) depResultFuture).run();
1250+
try {
1251+
depResult = depResultFuture.get();
1252+
resultProvider.addResults(depResult);
1253+
computedResults.put(depRule, depResult);
1254+
} catch (InterruptedException | ExecutionException e) {
1255+
Logger.getLogger(RulesToolkit.class.getName()).log(Level.WARNING, MessageFormat
1256+
.format(Messages.getString(Messages.RulesToolkit_RULE_RESULT_RETRIEVAL_ERROR), e));
1257+
}
1258+
} else {
1259+
depResult = computedResults.get(depRule);
1260+
}
1261+
if (depResult != null && shouldEvaluate(rule, depResult)) {
1262+
RunnableFuture<IResult> resultFuture = rule.createEvaluation(items, preferences, resultProvider);
1263+
resultFutures.put(rule, resultFuture);
1264+
futureQueue.add(resultFuture);
1265+
} else {
1266+
resultFutures.put(rule, CompletableFuture.completedFuture(getNotApplicableResult(rule, preferences,
1267+
Messages.getString(Messages.RulesToolkit_RULE_IGNORED))));
1268+
}
1269+
}
12171270
}
12181271
for (int i = 0; i < nThreads; i++) {
12191272
RuleEvaluator re = new RuleEvaluator(futureQueue);
@@ -1223,6 +1276,38 @@ public static Map<IRule, Future<IResult>> evaluateParallel(
12231276
return resultFutures;
12241277
}
12251278

1279+
private static boolean hasDependency(IRule rule) {
1280+
DependsOn dependency = rule.getClass().getAnnotation(DependsOn.class);
1281+
return dependency != null;
1282+
}
1283+
1284+
private static String getRuleDependencyName(IRule rule) {
1285+
DependsOn dependency = rule.getClass().getAnnotation(DependsOn.class);
1286+
Class<? extends IRule> dependencyType = dependency.value();
1287+
return dependencyType.getSimpleName();
1288+
}
1289+
1290+
/**
1291+
* Checks to see if a rule should be evaluated based on the severity value of its dependency's
1292+
* result severity value.
1293+
*
1294+
* @param rule
1295+
* rule to check severity value against its dependency's severity
1296+
* @param depResult
1297+
* result from the rule's dependency
1298+
* @return true if the dependency rule result satisfies the severity requirement for the passed
1299+
* rule
1300+
*/
1301+
private static boolean shouldEvaluate(IRule rule, IResult depResult) {
1302+
DependsOn dependency = rule.getClass().getAnnotation(DependsOn.class);
1303+
if (dependency != null) {
1304+
if (depResult.getSeverity().compareTo(dependency.severity()) < 0) {
1305+
return false;
1306+
}
1307+
}
1308+
return true;
1309+
}
1310+
12261311
private static class RuleEvaluator implements Runnable {
12271312
private Queue<RunnableFuture<IResult>> futureQueue;
12281313

core/org.openjdk.jmc.flightrecorder.rules/src/main/resources/org/openjdk/jmc/flightrecorder/rules/messages/internal/messages.properties

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
#
2-
# Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
# Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
#
44
# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
#
@@ -34,7 +34,9 @@
3434
RulesToolkit_ATTRIBUTE_NOT_FOUND=Could not get the attribute with id ''{0}'' from the event type with id ''{1}''. This recording is likely from an unsupported version.
3535
# {0} is an event type id, {1} is an attribute id
3636
RulesToolkit_ATTRIBUTE_NOT_FOUND_LONG=Could not get the attribute with id ''{0}'' from the event type with id ''{1}''. This recording is likely from an unsupported version.<p>If you are using an older Java version, then you can consider upgrading.
37+
RulesToolkit_EVALUATION_ERROR_DESCRIPTION=Could not evaluate this rule
3738
RulesToolkit_EVERY_CHUNK=Every Chunk
39+
RulesToolkit_RULE_IGNORED=Ignored
3840
# {0} is a rule name, {1} is one or more event type ids
3941
RulesToolkit_RULE_REQUIRES_UNAVAILABLE_EVENT_TYPE=The {0} rule requires the following event types: {1}.
4042
# {0} is a rule name, {1} is one or more event type ids
@@ -55,6 +57,7 @@ RulesToolkit_RULE_REQUIRES_EVENT_TYPE_LONG=The {0} rule requires that the follow
5557
RulesToolkit_RULE_REQUIRES_SOME_EVENTS=The {0} rule requires events to be available from at least one of the following event types: {1}.
5658
# {0} is one or more event type names
5759
RulesToolkit_RULE_RECOMMENDS_EVENTS=To improve rule accuracy and/or get more details for further investigation, it is recommended to enable the following event types: {0}.
60+
RulesToolkit_RULE_RESULT_RETRIEVAL_ERROR=Unexpected problem retrieving rule result.
5861
RulesToolkit_TOO_FEW_EVENTS=Too few events to calculate the result.
5962

6063
Result_SHORT_RECORDING=This recording is only {0} long, consider creating a recording longer than {1} for improved rule accuracy.

core/tests/org.openjdk.jmc.flightrecorder.rules.test/META-INF/MANIFEST.MF

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,6 @@ Bundle-ActivationPolicy: lazy
99
Require-Bundle: org.junit,
1010
org.openjdk.jmc.common.test,
1111
org.openjdk.jmc.flightrecorder,
12-
org.openjdk.jmc.flightrecorder.rules
12+
org.openjdk.jmc.flightrecorder.test,
13+
org.openjdk.jmc.flightrecorder.rules,
1314
Automatic-Module-Name: org.openjdk.jmc.flightrecorder.rules.test

core/tests/org.openjdk.jmc.flightrecorder.rules.test/pom.xml

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<?xml version="1.0" encoding="UTF-8"?>
22
<!--
3-
Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
44
55
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
66
@@ -67,6 +67,11 @@
6767
<artifactId>flightrecorder</artifactId>
6868
<version>${project.version}</version>
6969
</dependency>
70+
<dependency>
71+
<groupId>org.openjdk.jmc</groupId>
72+
<artifactId>flightrecorder.test</artifactId>
73+
<version>${project.version}</version>
74+
</dependency>
7075
<dependency>
7176
<groupId>org.openjdk.jmc</groupId>
7277
<artifactId>flightrecorder.rules</artifactId>

core/tests/org.openjdk.jmc.flightrecorder.rules.test/src/test/java/org/openjdk/jmc/flightrecorder/rules/RulesToolkitTest.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 2018, 2021, Oracle and/or its affiliates. All rights reserved.
33
*
44
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
55
*
@@ -35,11 +35,17 @@
3535
import static org.junit.Assert.assertEquals;
3636
import static org.junit.Assert.assertFalse;
3737
import static org.junit.Assert.assertTrue;
38+
import static org.junit.Assert.fail;
39+
40+
import java.io.IOException;
3841

3942
import org.junit.Test;
4043

4144
import org.openjdk.jmc.common.version.JavaVersion;
45+
import org.openjdk.jmc.flightrecorder.CouldNotLoadRecordingException;
46+
import org.openjdk.jmc.flightrecorder.rules.report.html.JfrHtmlRulesReport;
4247
import org.openjdk.jmc.flightrecorder.rules.util.RulesToolkit;
48+
import org.openjdk.jmc.flightrecorder.test.util.RecordingToolkit;
4349

4450
@SuppressWarnings("nls")
4551
public class RulesToolkitTest {
@@ -80,4 +86,15 @@ public void testGetJavaVersion() {
8086
JavaVersion javaVersion = RulesToolkit.getJavaVersion(JAVA_8_40);
8187
assertFalse(javaVersion.isEarlyAccess());
8288
}
89+
90+
@Test
91+
public void testJfrHtmlRulesReportGeneration() {
92+
String report = "";
93+
try {
94+
report = JfrHtmlRulesReport.createReport(RecordingToolkit.getNamedRecording("8u60.jfr"));
95+
} catch (IOException | CouldNotLoadRecordingException e) {
96+
fail();
97+
}
98+
assert (!report.isEmpty());
99+
}
83100
}

0 commit comments

Comments
 (0)