Skip to content

Commit fa4c075

Browse files
committed
Using heap dump analyser on Windows.
1 parent ce16e57 commit fa4c075

File tree

4 files changed

+47
-71
lines changed

4 files changed

+47
-71
lines changed

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/GCUtils.java

Lines changed: 39 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@
4343
import java.io.BufferedInputStream;
4444
import java.io.BufferedOutputStream;
4545
import java.io.IOException;
46+
import java.io.PrintStream;
4647
import java.lang.management.ManagementFactory;
4748
import java.lang.ref.Reference;
4849
import java.lang.ref.WeakReference;
@@ -97,7 +98,7 @@ public final class GCUtils {
9798
*/
9899
private static final String SAVE_HEAP_DUMP_TO = System.getProperty(GCUtils.class.getSimpleName() + ".saveHeapDumpTo");
99100

100-
private static final ReachabilityAnalyser<?> analyser = selectAnalyser();
101+
private static final ReachabilityAnalyser<?> analyser = new HeapDumpAnalyser();
101102

102103
private GCUtils() {
103104
throw new IllegalStateException("No instance allowed.");
@@ -115,6 +116,10 @@ private GCUtils() {
115116
* @param objectFactory producer of collectible object per an iteration
116117
*/
117118
public static void assertObjectsCollectible(Function<Integer, Object> objectFactory) {
119+
if (!isSupported()) {
120+
emitHeapDumpNotSupportedWarning("assertObjectsCollectible");
121+
return;
122+
}
118123
List<Reference<Object>> collectibleObjects = new ArrayList<>();
119124
for (int i = 0; i < GC_TEST_ITERATIONS; i++) {
120125
collectibleObjects.add(new WeakReference<>(objectFactory.apply(i)));
@@ -138,6 +143,10 @@ public static void assertObjectsCollectible(Function<Integer, Object> objectFact
138143
* @see #assertGc(Collection)
139144
*/
140145
public static void assertGc(String message, Reference<?> ref) {
146+
if (!isSupported()) {
147+
emitHeapDumpNotSupportedWarning("assertGc");
148+
return;
149+
}
141150
Result result = analyser.allCollected(Collections.singleton(ref), true, true, PRESERVE_HEAP_DUMP_ON_FAILURE);
142151
if (!result.isCollected()) {
143152
Assert.fail(formatShortestGCRootPath(message, result));
@@ -154,6 +163,10 @@ public static void assertGc(String message, Reference<?> ref) {
154163
* @param refs references their referents are to be released
155164
*/
156165
public static void assertGc(String message, Collection<? extends Reference<?>> refs) {
166+
if (!isSupported()) {
167+
emitHeapDumpNotSupportedWarning("assertGc");
168+
return;
169+
}
157170
Result result = analyser.allCollected(refs, true, true, PRESERVE_HEAP_DUMP_ON_FAILURE);
158171
if (!result.isCollected()) {
159172
Assert.fail(formatShortestGCRootPath(message, result));
@@ -170,6 +183,10 @@ public static void assertGc(String message, Collection<? extends Reference<?>> r
170183
* {@link AssertionError} thrown when the referent is not freed by the GC
171184
*/
172185
public static void assertGc(Collection<? extends Pair<String, Reference<?>>> refsWithMessages) {
186+
if (!isSupported()) {
187+
emitHeapDumpNotSupportedWarning("assertGc");
188+
return;
189+
}
173190
Map<Reference<?>, String> refsMap = new IdentityHashMap<>();
174191
for (Pair<String, Reference<?>> pair : refsWithMessages) {
175192
refsMap.putIfAbsent(pair.getRight(), pair.getLeft());
@@ -188,6 +205,10 @@ public static void assertGc(Collection<? extends Pair<String, Reference<?>>> ref
188205
* @param ref the reference
189206
*/
190207
public static void assertNotGc(final String message, final Reference<?> ref) {
208+
if (!isSupported()) {
209+
emitHeapDumpNotSupportedWarning("assertNotGc");
210+
return;
211+
}
191212
if (analyser.allCollected(Collections.singleton(ref), false, false, false).isCollected()) {
192213
Assert.fail(message);
193214
}
@@ -243,14 +264,14 @@ public static void generateGcPressure(double heapLoadFactor) {
243264
}
244265
}
245266

246-
private static ReachabilityAnalyser<?> selectAnalyser() {
247-
if (OSUtils.isWindows()) {
248-
// On Windows there are problems with the Heap release, which prevents the headump file
249-
// from being deleted.
250-
return new GCAnalyser();
251-
} else {
252-
return new HeapDumpAnalyser();
253-
}
267+
public static boolean isSupported() {
268+
return !ImageInfo.inImageRuntimeCode() || !OSUtils.isWindows();
269+
}
270+
271+
private static void emitHeapDumpNotSupportedWarning(String method) {
272+
PrintStream err = System.err;
273+
err.printf("[GCUtils] Ignoring GCUtils.%s: heap dump not supported in native-image on %s.%n",
274+
method, OSUtils.getCurrent());
254275
}
255276

256277
private static String formatShortestGCRootPath(String message, Result result) {
@@ -344,17 +365,6 @@ private Result() {
344365
this.heapDumpFile = null;
345366
}
346367

347-
Result(Reference<?> reference) {
348-
this.collected = false;
349-
this.reference = reference;
350-
this.gcRootKind = null;
351-
this.instanceId = -1;
352-
this.shortestGCRootPath = null;
353-
this.gcRootThreadId = -1;
354-
this.gcRootStackTrace = null;
355-
this.heapDumpFile = null;
356-
}
357-
358368
Result(Reference<?> reference, long instanceId, String gcRootKind, Iterable<? extends InstanceReference> shortestGCRootPath,
359369
long gcRootThreadId, Iterable<? extends StackTraceElement> gcRootStackTrace, Path heapDumpFile) {
360370
this.collected = false;
@@ -674,60 +684,18 @@ private static HotSpotDiagnosticMXBean getHotSpotDiagnosticMBean() throws IOExce
674684
}
675685

676686
private static void delete(Path file) throws IOException {
677-
if (Files.isDirectory(file, LinkOption.NOFOLLOW_LINKS)) {
678-
try (DirectoryStream<Path> content = Files.newDirectoryStream(file)) {
679-
for (Path child : content) {
680-
delete(child);
681-
}
682-
}
683-
}
684-
Files.delete(file);
685-
}
686-
}
687-
688-
private static final class GCAnalyser extends ReachabilityAnalyser<Void> {
689-
690-
@Override
691-
Result analyse(Collection<? extends Reference<?>> references, boolean performAllocations, boolean collectGCRootPath,
692-
boolean preserveHeapDumpIfNonCollectable, Function<Void, Result> testCollected) {
693-
int blockSize = 100_000;
694-
final List<byte[]> blocks = new ArrayList<>();
695-
Result result = null;
696-
for (int i = 0; i < 50; i++) {
697-
result = testCollected.apply(null);
698-
if (result.isCollected()) {
699-
return result;
700-
}
701-
try {
702-
System.gc();
703-
} catch (OutOfMemoryError oom) {
704-
}
705-
try {
706-
System.runFinalization();
707-
} catch (OutOfMemoryError oom) {
708-
}
709-
if (performAllocations) {
710-
try {
711-
blocks.add(new byte[blockSize]);
712-
blockSize = (int) (blockSize * 1.3);
713-
} catch (OutOfMemoryError oom) {
714-
blockSize >>>= 1;
715-
}
716-
}
717-
if (i % 10 == 0) {
718-
try {
719-
Thread.sleep(500);
720-
} catch (InterruptedException ie) {
721-
break;
687+
// On Windows there are problems with the Heap release, which prevents the headump file
688+
// from being deleted.
689+
if (OSUtils.getCurrent() != OSUtils.OS.Windows) {
690+
if (Files.isDirectory(file, LinkOption.NOFOLLOW_LINKS)) {
691+
try (DirectoryStream<Path> content = Files.newDirectoryStream(file)) {
692+
for (Path child : content) {
693+
delete(child);
694+
}
722695
}
723696
}
697+
Files.delete(file);
724698
}
725-
return result;
726-
}
727-
728-
@Override
729-
Result isCollected(Reference<?> reference, Void context) {
730-
return reference.get() == null ? Result.COLLECTED : new Result(reference);
731699
}
732700
}
733701
}

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/LoggingTest.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,7 @@ public void testInterpreterOnlyWarning() {
13891389

13901390
@Test
13911391
public void testGR49739() {
1392+
Assume.assumeTrue(GCUtils.isSupported());
13921393
AtomicReference<TruffleLogger> loggerHolder = new AtomicReference<>();
13931394
AbstractLoggingLanguage.action = (ctx, defaultLoggers) -> {
13941395
loggerHolder.set(ctx.env.getLogger("after.close"));

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/polyglot/PolyglotGCTest.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@
5656
import com.oracle.truffle.api.nodes.Node;
5757
import com.oracle.truffle.api.nodes.RootNode;
5858
import com.oracle.truffle.api.test.GCUtils;
59+
import com.oracle.truffle.api.test.OSUtils;
5960
import com.oracle.truffle.api.test.ReflectionUtils;
6061
import com.oracle.truffle.api.test.SubprocessTestUtils;
6162
import com.oracle.truffle.api.test.common.AbstractExecutableTestLanguage;
@@ -77,6 +78,7 @@
7778
import org.graalvm.polyglot.management.ExecutionListener;
7879
import org.junit.AfterClass;
7980
import org.junit.Assert;
81+
import org.junit.Assume;
8082
import org.junit.Before;
8183
import org.junit.BeforeClass;
8284
import org.junit.Test;
@@ -156,6 +158,7 @@ public static void tearDownClass() {
156158

157159
@Before
158160
public void setUp() {
161+
Assume.assumeTrue(GCUtils.isSupported());
159162
testLogHandler = new TestLogHandler();
160163
languageInnerContextDisposed.set(false);
161164
}
@@ -680,6 +683,7 @@ protected Object execute(RootNode node, Env env, Object[] contextArguments, Obje
680683

681684
@Test
682685
public void testInnerContextSPI() throws Exception {
686+
Assume.assumeTrue(TruffleTestAssumptions.isWeakEncapsulation() || !OSUtils.isWindows());
683687
runInSubprocess(() -> {
684688
Context context = newContextBuilder().build();
685689
AbstractExecutableTestLanguage.execute(context, UnreachableInnerContextGcLanguage2.class);

truffle/src/com.oracle.truffle.api.test/src/com/oracle/truffle/api/test/source/SourceCacheTest.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@
6666
import org.graalvm.polyglot.Source;
6767
import org.graalvm.polyglot.io.ByteSequence;
6868
import org.junit.Assert;
69+
import org.junit.Assume;
6970
import org.junit.Test;
7071

7172
import com.oracle.truffle.api.CallTarget;
@@ -154,6 +155,7 @@ public void testTraceSourceCacheFailure() throws Throwable {
154155
@Test
155156
public void testTraceSourceCacheEviction() throws IOException, InterruptedException {
156157
TruffleTestAssumptions.assumeWeakEncapsulation(); // Can't control GC in the isolate.
158+
Assume.assumeTrue(GCUtils.isSupported());
157159
Runnable runnable = () -> {
158160
try (ByteArrayOutputStream out = new ByteArrayOutputStream(); Context context = Context.newBuilder().option("engine.TraceSourceCache", "true").out(out).err(out).build()) {
159161
Source auxiliarySource = Source.newBuilder(SourceCacheTestLanguage.ID, "x", "AuxiliarySource").build();
@@ -321,6 +323,7 @@ protected CallTarget parse(ParsingRequest request) throws Exception {
321323
@Test
322324
public void testSourceCachesCleared() throws IOException, InterruptedException {
323325
TruffleTestAssumptions.assumeWeakEncapsulation(); // Can't control GC in the isolate.
326+
Assume.assumeTrue(GCUtils.isSupported());
324327
Runnable runnable = () -> {
325328
List<String> logs = new ArrayList<>();
326329
String[] expectedSequence = new String[]{"miss1", "miss2", "evict2", "miss1", "evict1", "evict1"};

0 commit comments

Comments
 (0)