From 55d06ea4c1942db597732cc438dc1b3d21ab8965 Mon Sep 17 00:00:00 2001 From: Andrey Loskutov Date: Mon, 21 Oct 2024 11:32:45 +0200 Subject: [PATCH] Add memory reporting for UI tests and exit for E4Testable on OOM Maybe this could help understanding OOM errors on jenkins. See https://github.com/eclipse-platform/eclipse.platform.ui/issues/2432 --- .../ui/internal/workbench/swt/E4Testable.java | 74 ++++++++++++++----- .../ui/tests/harness/util/UITestCase.java | 22 ++++++ 2 files changed, 78 insertions(+), 18 deletions(-) diff --git a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Testable.java b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Testable.java index 6a3c3c4b828..ceafe956ef2 100644 --- a/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Testable.java +++ b/bundles/org.eclipse.e4.ui.workbench.swt/src/org/eclipse/e4/ui/internal/workbench/swt/E4Testable.java @@ -13,6 +13,7 @@ *******************************************************************************/ package org.eclipse.e4.ui.internal.workbench.swt; +import java.util.Locale; import org.eclipse.core.runtime.Assert; import org.eclipse.core.runtime.OperationCanceledException; import org.eclipse.core.runtime.jobs.Job; @@ -115,24 +116,61 @@ public void testingStarting() { @Override public void runTest(Runnable testRunnable) { Assert.isNotNull(workbench); - display.syncExec( - () -> { - display.addListener(SWT.Dispose, - e -> { - // lambda block to allow breakpoint for debugging - displayCheck = new Exception("Display is disposed"); - }); - - // Run actual test - testRunnable.run(); - - while (display.readAndDispatch()) { - // process all pending tasks - } - - // Display should be still there - checkDisplay(); - }); + display.syncExec(new TestExecutionRunnable(testRunnable)); + } + + private final class TestExecutionRunnable implements Runnable { + private final Runnable testRunnable; + + private TestExecutionRunnable(Runnable testRunnable) { + this.testRunnable = testRunnable; + } + + @Override + public void run() { + display.addListener(SWT.Dispose, + e -> { + // lambda block to allow breakpoint for debugging + displayCheck = new Exception("Display is disposed"); + }); + + try { + // Run actual test + testRunnable.run(); + } catch (OutOfMemoryError e) { + try { + e.printStackTrace(System.out); + printMemoryUse(); + } finally { + System.out.println("Calling System.exit() after OutOfMemoryError"); + System.exit(1); + } + } + + while (display.readAndDispatch()) { + // process all pending tasks + } + + // Display should be still there + checkDisplay(); + } + } + + private static void printMemoryUse() { + System.gc(); + System.runFinalization(); + System.gc(); + System.runFinalization(); + long max = Runtime.getRuntime().maxMemory(); + long total = Runtime.getRuntime().totalMemory(); + long free = Runtime.getRuntime().freeMemory(); + long used = total - free; + System.out.print("\n########### Memory usage reported by JVM ########"); + System.out.printf(Locale.GERMAN, "%n%,16d bytes max heap", max); + System.out.printf(Locale.GERMAN, "%n%,16d bytes heap allocated", total); + System.out.printf(Locale.GERMAN, "%n%,16d bytes free heap", free); + System.out.printf(Locale.GERMAN, "%n%,16d bytes used heap", used); + System.out.println("\n#################################################\n"); } /** diff --git a/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/UITestCase.java b/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/UITestCase.java index 436b0f884bc..51b0e98728a 100644 --- a/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/UITestCase.java +++ b/tests/org.eclipse.ui.tests.harness/src/org/eclipse/ui/tests/harness/util/UITestCase.java @@ -21,6 +21,7 @@ import java.io.PrintStream; import java.util.ArrayList; import java.util.List; +import java.util.Locale; import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; @@ -212,6 +213,8 @@ protected void doSetUp() throws Exception { public final void tearDown() throws Exception { String name = runningTest != null ? runningTest : this.getName(); trace(TestRunLogUtil.formatTestFinishedMessage(name)); + printMemoryUse(); + prefMemento.resetPreferences(); doTearDown(); @@ -229,6 +232,25 @@ public final void tearDown() throws Exception { leakedModalShellTitles.size()); } + protected void printMemoryUse() { + System.gc(); + System.runFinalization(); + System.gc(); + System.runFinalization(); + long nax = Runtime.getRuntime().maxMemory(); + long total = Runtime.getRuntime().totalMemory(); + long free = Runtime.getRuntime().freeMemory(); + long used = total - free; + System.out.print("\n#################################################"); + System.out.print("\n" + getClass().getName()); + System.out.print("\n########### Memory usage reported by JVM ########"); + System.out.printf(Locale.GERMAN, "%n%,16d bytes max heap", nax); + System.out.printf(Locale.GERMAN, "%n%,16d bytes heap allocated", total); + System.out.printf(Locale.GERMAN, "%n%,16d bytes free heap", free); + System.out.printf(Locale.GERMAN, "%n%,16d bytes used heap", used); + System.out.println("\n#################################################\n"); + } + /** * Tears down the fixture, for example, close a network connection. * This method is called after a test is executed.