|
1 /* |
|
2 * Copyright (c) 2013, 2018, Oracle and/or its affiliates. All rights reserved. |
|
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
|
4 * |
|
5 * This code is free software; you can redistribute it and/or modify it |
|
6 * under the terms of the GNU General Public License version 2 only, as |
|
7 * published by the Free Software Foundation. Oracle designates this |
|
8 * particular file as subject to the "Classpath" exception as provided |
|
9 * by Oracle in the LICENSE file that accompanied this code. |
|
10 * |
|
11 * This code is distributed in the hope that it will be useful, but WITHOUT |
|
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
|
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
|
14 * version 2 for more details (a copy is included in the LICENSE file that |
|
15 * accompanied this code). |
|
16 * |
|
17 * You should have received a copy of the GNU General Public License version |
|
18 * 2 along with this work; if not, write to the Free Software Foundation, |
|
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
|
20 * |
|
21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
|
22 * or visit www.oracle.com if you need additional information or have any |
|
23 * questions. |
|
24 */ |
|
25 |
|
26 package jdk.jfr.event.gc.heapsummary; |
|
27 |
|
28 import java.time.Duration; |
|
29 import java.util.List; |
|
30 |
|
31 import jdk.jfr.Recording; |
|
32 import jdk.jfr.consumer.RecordedEvent; |
|
33 import jdk.test.lib.Asserts; |
|
34 import jdk.test.lib.jfr.EventNames; |
|
35 import jdk.test.lib.jfr.Events; |
|
36 import jdk.test.lib.jfr.GCHelper; |
|
37 |
|
38 public class HeapSummaryEventAllGcs { |
|
39 |
|
40 public static void test(String expectedYoungCollector, String expectedOldCollector) throws Exception { |
|
41 Recording recording = new Recording(); |
|
42 recording.enable(EventNames.GCConfiguration); |
|
43 recording.enable(EventNames.GCHeapSummary); |
|
44 recording.enable(EventNames.PSHeapSummary); |
|
45 recording.enable(EventNames.MetaspaceSummary).withThreshold(Duration.ofMillis(0)); |
|
46 |
|
47 recording.start(); |
|
48 // To eliminate the risk of being in the middle of a GC when the recording starts/stops, |
|
49 // we run 5 System.gc() and ignores the first and last GC. |
|
50 GCHelper.callSystemGc(5, true); |
|
51 recording.stop(); |
|
52 |
|
53 if (!checkCollectors(recording, expectedYoungCollector, expectedOldCollector)) { |
|
54 return; |
|
55 } |
|
56 List<RecordedEvent> events = GCHelper.removeFirstAndLastGC(Events.fromRecording(recording)); |
|
57 for (RecordedEvent event : events) { |
|
58 System.out.println("Event:" + event); |
|
59 } |
|
60 |
|
61 Asserts.assertFalse(events.isEmpty(), "Expected at least one event."); |
|
62 Asserts.assertEquals(events.size() % 2, 0, "Events should come in pairs"); |
|
63 |
|
64 int lastHeapGcId = -1; |
|
65 int lastPSGcId = -1; |
|
66 int lastMetaspaceGcId = -1; |
|
67 |
|
68 for (RecordedEvent event : events) { |
|
69 final String eventName = event.getEventType().getName(); |
|
70 switch (eventName) { |
|
71 case EventNames.GCHeapSummary: |
|
72 lastHeapGcId = checkGcId(event, lastHeapGcId); |
|
73 checkHeapEventContent(event); |
|
74 break; |
|
75 case EventNames.PSHeapSummary: |
|
76 lastPSGcId = checkGcId(event, lastPSGcId); |
|
77 checkPSEventContent(event); |
|
78 break; |
|
79 case EventNames.MetaspaceSummary: |
|
80 lastMetaspaceGcId = checkGcId(event, lastMetaspaceGcId); |
|
81 checkMetaspaceEventContent(event); |
|
82 break; |
|
83 default: |
|
84 System.out.println("Failed event: " + event); |
|
85 Asserts.fail("Unknown event type: " + eventName); |
|
86 } |
|
87 } |
|
88 |
|
89 // Sanity check. Not complete. |
|
90 Asserts.assertEquals(lastHeapGcId, lastMetaspaceGcId, "Should have gotten perm gen events for all GCs"); |
|
91 } |
|
92 |
|
93 private static void checkMetaspaceEventContent(RecordedEvent event) { |
|
94 long totalUsed = Events.assertField(event, "metaspace.used").atLeast(0L).getValue(); |
|
95 long totalCommitted = Events.assertField(event, "metaspace.committed").atLeast(totalUsed).getValue(); |
|
96 long totalReserved = Events.assertField(event, "metaspace.reserved").atLeast(totalCommitted).getValue(); |
|
97 |
|
98 long dataUsed = Events.assertField(event, "dataSpace.used").atLeast(0L).getValue(); |
|
99 long dataCommitted = Events.assertField(event, "dataSpace.committed").atLeast(dataUsed).getValue(); |
|
100 long dataReserved = Events.assertField(event, "dataSpace.reserved").atLeast(dataCommitted).getValue(); |
|
101 |
|
102 long classUsed = Events.assertField(event, "classSpace.used").atLeast(0L).getValue(); |
|
103 long classCommitted = Events.assertField(event, "classSpace.committed").atLeast(classUsed).getValue(); |
|
104 long classReserved = Events.assertField(event, "classSpace.reserved").atLeast(classCommitted).getValue(); |
|
105 |
|
106 Asserts.assertEquals(dataCommitted + classCommitted, totalCommitted, "Wrong committed memory"); |
|
107 Asserts.assertEquals(dataUsed + classUsed, totalUsed, "Wrong used memory"); |
|
108 Asserts.assertEquals(dataReserved + classReserved, totalReserved, "Wrong reserved memory"); |
|
109 } |
|
110 |
|
111 private static int checkGcId(RecordedEvent event, int currGcId) { |
|
112 int gcId = Events.assertField(event, "gcId").getValue(); |
|
113 String when = Events.assertField(event, "when").notEmpty().getValue(); |
|
114 if ("Before GC".equals(when)) { |
|
115 Asserts.assertGreaterThan(gcId, currGcId, "gcId should be increasing"); |
|
116 } else { |
|
117 Asserts.assertEquals(gcId, currGcId, "After should have same gcId as last Before event"); |
|
118 } |
|
119 return gcId; |
|
120 } |
|
121 |
|
122 private static void checkHeapEventContent(RecordedEvent event) { |
|
123 checkVirtualSpace(event, "heapSpace"); |
|
124 long heapUsed = Events.assertField(event, "heapUsed").atLeast(0L).getValue(); |
|
125 long start = Events.assertField(event, "heapSpace.start").atLeast(0L).getValue(); |
|
126 long committedEnd = Events.assertField(event, "heapSpace.committedEnd").above(start).getValue(); |
|
127 Asserts.assertLessThanOrEqual(heapUsed, committedEnd- start, "used can not exceed size"); |
|
128 } |
|
129 |
|
130 private static void checkPSEventContent(RecordedEvent event) { |
|
131 checkVirtualSpace(event, "oldSpace"); |
|
132 checkVirtualSpace(event, "youngSpace"); |
|
133 checkSpace(event, "oldObjectSpace"); |
|
134 checkSpace(event, "edenSpace"); |
|
135 checkSpace(event, "fromSpace"); |
|
136 checkSpace(event, "toSpace"); |
|
137 |
|
138 checkPSYoungSizes(event); |
|
139 checkPSYoungStartEnd(event); |
|
140 } |
|
141 |
|
142 private static void checkPSYoungSizes(RecordedEvent event) { |
|
143 long youngSize = (long)Events.assertField(event, "youngSpace.committedEnd").getValue() - |
|
144 (long)Events.assertField(event, "youngSpace.start").getValue(); |
|
145 long edenSize = (long)Events.assertField(event, "edenSpace.end").getValue() - |
|
146 (long)Events.assertField(event, "edenSpace.start").getValue(); |
|
147 long fromSize = (long)Events.assertField(event, "fromSpace.end").getValue() - |
|
148 (long)Events.assertField(event, "fromSpace.start").getValue(); |
|
149 long toSize = (long)Events.assertField(event, "toSpace.end").getValue() - |
|
150 (long)Events.assertField(event, "toSpace.start").getValue(); |
|
151 Asserts.assertGreaterThanOrEqual(youngSize, edenSize + fromSize + toSize, "Young sizes don't match"); |
|
152 } |
|
153 |
|
154 private static void checkPSYoungStartEnd(RecordedEvent event) { |
|
155 long oldEnd = Events.assertField(event, "oldSpace.reservedEnd").getValue(); |
|
156 long youngStart = Events.assertField(event, "youngSpace.start").getValue(); |
|
157 long youngEnd = Events.assertField(event, "youngSpace.committedEnd").getValue(); |
|
158 long edenStart = Events.assertField(event, "edenSpace.start").getValue(); |
|
159 long edenEnd = Events.assertField(event, "edenSpace.end").getValue(); |
|
160 long fromStart = Events.assertField(event, "fromSpace.start").getValue(); |
|
161 long fromEnd = Events.assertField(event, "fromSpace.end").getValue(); |
|
162 long toStart = Events.assertField(event, "toSpace.start").getValue(); |
|
163 long toEnd = Events.assertField(event, "toSpace.end").getValue(); |
|
164 Asserts.assertEquals(oldEnd, youngStart, "Young should start where old ends"); |
|
165 Asserts.assertEquals(youngStart, edenStart, "Eden should be placed first in young"); |
|
166 if (fromStart < toStart) { |
|
167 // [eden][from][to] |
|
168 Asserts.assertGreaterThanOrEqual(fromStart, edenEnd, "From should start after eden"); |
|
169 Asserts.assertLessThanOrEqual(fromEnd, toStart, "To should start after From"); |
|
170 Asserts.assertLessThanOrEqual(toEnd, youngEnd, "To should start after From"); |
|
171 } else { |
|
172 // [eden][to][from] |
|
173 Asserts.assertGreaterThanOrEqual(toStart, edenEnd, "From should start after eden"); |
|
174 Asserts.assertLessThanOrEqual(toEnd, fromStart, "To should start after From"); |
|
175 Asserts.assertLessThanOrEqual(fromEnd, youngEnd, "To should start after From"); |
|
176 } |
|
177 } |
|
178 |
|
179 private static void checkVirtualSpace(RecordedEvent event, String structName) { |
|
180 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); |
|
181 long committedEnd = Events.assertField(event, structName + ".committedEnd").above(start).getValue(); |
|
182 Events.assertField(event, structName + ".reservedEnd").atLeast(committedEnd); |
|
183 long committedSize = Events.assertField(event, structName + ".committedSize").atLeast(0L).getValue(); |
|
184 Events.assertField(event, structName + ".reservedSize").atLeast(committedSize); |
|
185 } |
|
186 |
|
187 private static void checkSpace(RecordedEvent event, String structName) { |
|
188 long start = Events.assertField(event, structName + ".start").atLeast(0L).getValue(); |
|
189 long end = Events.assertField(event, structName + ".end").above(start).getValue(); |
|
190 long used = Events.assertField(event, structName + ".used").atLeast(0L).getValue(); |
|
191 long size = Events.assertField(event, structName + ".size").atLeast(used).getValue(); |
|
192 Asserts.assertEquals(size, end - start, "Size mismatch"); |
|
193 } |
|
194 |
|
195 private static boolean checkCollectors(Recording recording, String expectedYoung, String expectedOld) throws Exception { |
|
196 for (RecordedEvent event : Events.fromRecording(recording)) { |
|
197 if (Events.isEventType(event, EventNames.GCConfiguration)) { |
|
198 final String young = Events.assertField(event, "youngCollector").notEmpty().getValue(); |
|
199 final String old = Events.assertField(event, "oldCollector").notEmpty().getValue(); |
|
200 if (young.equals(expectedYoung) && old.equals(expectedOld)) { |
|
201 return true; |
|
202 } |
|
203 // TODO: We treat wrong collector types as an error. Old test only warned. Not sure what is correct. |
|
204 Asserts.fail(String.format("Wrong collector types: got('%s','%s'), expected('%s','%s')", |
|
205 young, old, expectedYoung, expectedOld)); |
|
206 } |
|
207 } |
|
208 Asserts.fail("Missing event type " + EventNames.GCConfiguration); |
|
209 return false; |
|
210 } |
|
211 } |