diff --git a/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/OpenMultipleEditorTest.java b/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/OpenMultipleEditorTest.java index bccbb9356f2..d87177e98d1 100644 --- a/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/OpenMultipleEditorTest.java +++ b/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/OpenMultipleEditorTest.java @@ -17,12 +17,17 @@ import static org.eclipse.ui.tests.harness.util.UITestUtil.openTestWindow; import static org.eclipse.ui.tests.harness.util.UITestUtil.processEvents; import static org.eclipse.ui.tests.performance.UIPerformanceTestRule.getTestProject; +import static org.eclipse.ui.tests.performance.UIPerformanceTestUtil.reportTimings; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; import org.eclipse.core.resources.IFile; -import org.eclipse.test.performance.PerformanceTestCaseJunit4; +import org.eclipse.ui.IEditorPart; import org.eclipse.ui.IEditorReference; import org.eclipse.ui.IWorkbenchPage; import org.eclipse.ui.IWorkbenchWindow; @@ -36,10 +41,30 @@ import org.junit.runners.Parameterized.Parameters; /** + * Measures opening many editors and closing them again. Reports the cost of the + * first and the last editors separately, so that a cost that grows with the + * number of open editors is visible. + * * @since 3.1 */ @RunWith(Parameterized.class) -public class OpenMultipleEditorTest extends PerformanceTestCaseJunit4 { +public class OpenMultipleEditorTest { + + /** + * Stays below the REUSE_EDITORS threshold, which defaults to 99. Above it the + * workbench recycles the oldest editor, so further opens would measure reuse + * rather than opening. + */ + private static final int EDITOR_COUNT = 90; + + /** + * Enough editors to get the editor implementation loaded and compiled. Below + * roughly this many, the reported times are dominated by JIT warm-up. + */ + private static final int WARMUP_EDITORS = 20; + + /** How many editors at each end of the run are reported on their own. */ + private static final int SEGMENT = 10; @ClassRule public static final UIPerformanceTestRule uiPerformanceTestRule = new UIPerformanceTestRule(); @@ -50,7 +75,7 @@ public class OpenMultipleEditorTest extends PerformanceTestCaseJunit4 { private final String extension; private final boolean closeAll; - @Parameters(name = "{index}: closeAll: {0} - closeEach: {1}") + @Parameters(name = "{index}: {0} - closeAll: {1}") public static Collection data() { return Arrays.asList(new Object[][] { { "perf_basic", true }, { "perf_outline", true }, { "perf_text", true }, { "perf_basic", false }, { "perf_outline", false }, { "perf_text", false } }); @@ -64,27 +89,71 @@ public OpenMultipleEditorTest(String extension, boolean closeAll) { @Test public void test() throws Throwable { IWorkbenchWindow window = openTestWindow(UIPerformanceTestRule.PERSPECTIVE1); - IWorkbenchPage activePage = window.getActivePage(); + IWorkbenchPage page = window.getActivePage(); - startMeasuring(); + // Class loading and JIT warm-up would otherwise end up in the reported times. + openEditors(page, WARMUP_EDITORS, null); + page.closeAllEditors(false); + processEvents(); + EditorTestHelper.calmDown(500, 30000, 500); + + List openTimes = new ArrayList<>(); + openEditors(page, EDITOR_COUNT, openTimes); + assertEquals("Not all editors stayed open. The workbench recycles the oldest editor once REUSE_EDITORS" + + " (default 99) are open, so EDITOR_COUNT has to stay below that threshold.", EDITOR_COUNT, + page.getEditorReferences().length); + + String label = extension + (closeAll ? ", closeAll" : ", closeEach"); + reportTimings("openMultiple[" + label + "] open", openTimes); + reportTimings("openMultiple[" + label + "] open, first " + SEGMENT, openTimes.subList(0, SEGMENT)); + reportTimings("openMultiple[" + label + "] open, last " + SEGMENT, + openTimes.subList(EDITOR_COUNT - SEGMENT, EDITOR_COUNT)); - for (int i = 0; i < 100; i++) { - IFile file = getTestProject().getFile(i + "." + extension); - IDE.openEditor(activePage, file, true); - processEvents(); - } if (closeAll) { - activePage.closeAllEditors(false); + long before = System.nanoTime(); + page.closeAllEditors(false); + processEvents(); + reportTimings("openMultiple[" + label + "] closeAllEditors", List.of(System.nanoTime() - before)); + } else { + List closeTimes = closeEditorsIndividually(page); + reportTimings("openMultiple[" + label + "] close", closeTimes); + reportTimings("openMultiple[" + label + "] close, first " + SEGMENT, closeTimes.subList(0, SEGMENT)); + reportTimings("openMultiple[" + label + "] close, last " + SEGMENT, + closeTimes.subList(EDITOR_COUNT - SEGMENT, EDITOR_COUNT)); } - else { - IEditorReference[] parts = activePage.getEditorReferences(); - for (IEditorReference part : parts) { - activePage.closeEditor(part.getEditor(false), false); + assertEquals("Not all editors were closed", 0, page.getEditorReferences().length); + } + + /** + * Opens {@code count} editors, recording each open when the given list is not + * {@code null}. + */ + private void openEditors(IWorkbenchPage page, int count, List openTimes) throws Exception { + for (int i = 0; i < count; i++) { + IFile file = getTestProject().getFile(i + "." + extension); + long before = System.nanoTime(); + IEditorPart part = IDE.openEditor(page, file, true); + processEvents(); + long after = System.nanoTime(); + assertNotNull("No editor opened for " + file.getName(), part); + + if (openTimes != null) { + openTimes.add(after - before); } } - stopMeasuring(); - commitMeasurements(); - assertPerformance(); } + private static List closeEditorsIndividually(IWorkbenchPage page) { + List closeTimes = new ArrayList<>(); + for (IEditorReference reference : page.getEditorReferences()) { + IEditorPart part = reference.getEditor(false); + assertNotNull("Editor was never created: " + reference.getId(), part); + + long before = System.nanoTime(); + page.closeEditor(part, false); + processEvents(); + closeTimes.add(System.nanoTime() - before); + } + return closeTimes; + } } diff --git a/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/PerspectiveSwitchTest.java b/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/PerspectiveSwitchTest.java index c82149dd4f1..7bd3f6a7bb8 100644 --- a/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/PerspectiveSwitchTest.java +++ b/tests/org.eclipse.ui.tests.performance/src/org/eclipse/ui/tests/performance/PerspectiveSwitchTest.java @@ -17,15 +17,19 @@ import static org.eclipse.ui.tests.harness.util.UITestUtil.processEvents; import static org.eclipse.ui.tests.performance.UIPerformanceTestRule.getTestProject; import static org.eclipse.ui.tests.performance.UIPerformanceTestUtil.exercise; +import static org.eclipse.ui.tests.performance.UIPerformanceTestUtil.reportTimings; +import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; +import static org.junit.Assume.assumeTrue; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; +import java.util.List; import org.eclipse.core.resources.IFile; import org.eclipse.core.runtime.CoreException; -import org.eclipse.test.performance.PerformanceTestCaseJunit4; import org.eclipse.ui.IPerspectiveDescriptor; import org.eclipse.ui.IPerspectiveRegistry; import org.eclipse.ui.IWorkbenchPage; @@ -42,10 +46,23 @@ import org.junit.runners.Parameterized.Parameters; /** - * Test perspective switching. + * Measures switching back and forth between two perspectives, and reports each + * switch direction separately. */ @RunWith(Parameterized.class) -public class PerspectiveSwitchTest extends PerformanceTestCaseJunit4 { +public class PerspectiveSwitchTest { + + /** + * Enough switches to get the participating parts loaded and compiled. Below + * roughly this many, the reported times are dominated by JIT warm-up. + */ + private static final int WARMUP_PAIRS = 5; + + private static final int MIN_PAIRS = 5; + + private static final int MAX_PAIRS = 50; + + private static final int MAX_MEASURE_TIME_MS = 12000; @ClassRule public static final UIPerformanceTestRule uiPerformanceTestRule = new UIPerformanceTestRule(); @@ -80,9 +97,6 @@ public PerspectiveSwitchTest(String id1, String id2, String activeEditor) { this.activeEditor = activeEditor; } - /** - * Test perspective switching performance. - */ @Test public void test() throws CoreException, WorkbenchException { // Get the two perspectives to switch between. @@ -90,18 +104,11 @@ public void test() throws CoreException, WorkbenchException { final IPerspectiveDescriptor perspective1 = registry.findPerspectiveWithId(id1); final IPerspectiveDescriptor perspective2 = registry.findPerspectiveWithId(id2); - // Don't fail if we reference an unknown perspective ID. This can be - // a normal occurrance since the test suites reference JDT perspectives, which - // might not exist. Just skip the test. - if (perspective1 == null) { - System.out.println("Unknown perspective ID: " + id1); - return; - } - - if (perspective2 == null) { - System.out.println("Unknown perspective ID: " + id2); - return; - } + // The parameters reference JDT perspectives, which are not part of every target + // platform. Skip visibly rather than reporting a pass for something that was + // never measured. + assumeTrue("Perspective not available: " + id1, perspective1 != null); + assumeTrue("Perspective not available: " + id2, perspective2 != null); // Open the two perspectives and the file, in a new window. // Do this outside the loop so as not to include @@ -111,25 +118,43 @@ public void test() throws CoreException, WorkbenchException { assertNotNull(page); page.setPerspective(perspective2); - // IFile aFile = getProject().getFile("1." + - // EditorPerformanceSuite.EDITOR_FILE_EXTENSIONS[0]); IFile aFile = getTestProject().getFile(activeEditor); - assertTrue(aFile.exists()); + assertTrue("Missing test file " + activeEditor + ", the fixture does not create it", aFile.exists()); IDE.openEditor(page, aFile, true); + // Class loading and JIT warm-up would otherwise end up in the reported times. + for (int i = 0; i < WARMUP_PAIRS; i++) { + switchTo(page, perspective1, null); + switchTo(page, perspective2, null); + } + EditorTestHelper.calmDown(500, 30000, 500); + + List toFirst = new ArrayList<>(); + List toSecond = new ArrayList<>(); + exercise(() -> { - processEvents(); - - startMeasuring(); - page.setPerspective(perspective1); - processEvents(); - page.setPerspective(perspective2); - processEvents(); - stopMeasuring(); - }); - - commitMeasurements(); - assertPerformance(); + switchTo(page, perspective1, toFirst); + switchTo(page, perspective2, toSecond); + }, MIN_PAIRS, MAX_PAIRS, MAX_MEASURE_TIME_MS); + + reportTimings("PerspectiveSwitch to [" + id1 + "]", toFirst); + reportTimings("PerspectiveSwitch to [" + id2 + "]", toSecond); + } + + /** + * Switches to the given perspective, recording the time when the given list is + * not {@code null}. + */ + private static void switchTo(IWorkbenchPage page, IPerspectiveDescriptor perspective, List times) { + long before = System.nanoTime(); + page.setPerspective(perspective); + processEvents(); + long after = System.nanoTime(); + assertEquals("Wrong perspective active", perspective, page.getPerspective()); + + if (times != null) { + times.add(after - before); + } } }