From: Denis Anisimov Date: Fri, 14 Oct 2016 08:36:18 +0000 (+0300) Subject: Memory measurement test for V7&V8 Grids, 1 item and 100 000 items. X-Git-Tag: 8.0.0.alpha5~14 X-Git-Url: https://source.dussan.org/?a=commitdiff_plain;h=3b454d94ae64f743d05cd7e94d00b354ff9d14eb;p=vaadin-framework.git Memory measurement test for V7&V8 Grids, 1 item and 100 000 items. Change-Id: I66b358ff40703f2713272323ba1c5ae8778c8413 --- diff --git a/pom.xml b/pom.xml index 8e978a7e68..e82cbac4a4 100644 --- a/pom.xml +++ b/pom.xml @@ -680,6 +680,15 @@ + + measurements + + false + + + true + + diff --git a/uitest/pom.xml b/uitest/pom.xml index 6055d84d97..4b183e578b 100644 --- a/uitest/pom.xml +++ b/uitest/pom.xml @@ -330,6 +330,97 @@ false + + default + + true + + + + + maven-surefire-plugin + + com.vaadin.testcategory.MeasurementTest + + + + + + + measurements + + false + + + false + + + + + maven-failsafe-plugin + + + + integration-test + verify + + + + + com.vaadin.testcategory.MeasurementTest + + ${phantomjs.binary} + + + + + org.eclipse.jetty + jetty-maven-plugin + + + 8888 + + -1 + 8081 + 5 + foo + + + + + start-jetty + pre-integration-test + + start + + + + stop-jetty + post-integration-test + + stop + + + + + + com.github.klieber + phantomjs-maven-plugin + + + + install + + + ${phantomjs.version} + + + + + + + diff --git a/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java b/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java new file mode 100644 index 0000000000..798686776f --- /dev/null +++ b/uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java @@ -0,0 +1,30 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.testcategory; + +/** + * Test that is not supposed to be run on validation and run without other + * verification tests. + *

+ * The purpose of the test to make some measurement (memory, time, etc.). + * + * + * @author Vaadin Ltd + * + */ +public interface MeasurementTest { + +} diff --git a/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java b/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java index 62b42f56f8..526b758e22 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java @@ -15,6 +15,7 @@ */ package com.vaadin.tests.performance; +import java.lang.reflect.Field; import java.math.BigDecimal; import java.util.Collections; import java.util.Date; @@ -24,34 +25,65 @@ import java.util.stream.Collectors; import java.util.stream.IntStream; import com.vaadin.server.VaadinRequest; -import com.vaadin.tests.components.AbstractTestUI; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Country; import com.vaadin.tests.data.bean.Person; import com.vaadin.tests.data.bean.Sex; import com.vaadin.ui.AbstractComponent; +import com.vaadin.ui.Button; import com.vaadin.ui.Component; +import com.vaadin.ui.HasComponents; +import com.vaadin.ui.Label; import com.vaadin.ui.MenuBar; import com.vaadin.ui.MenuBar.MenuItem; +import com.vaadin.ui.UI; +import com.vaadin.ui.VerticalLayout; + +import jdk.nashorn.internal.ir.debug.ObjectSizeCalculator; /** * @author Vaadin Ltd * */ public abstract class AbstractBeansMemoryTest - extends AbstractTestUI { + extends UI { private int dataSize; private boolean isInMemory; private boolean isDataOnly; + private Label logLabel; + private Label memoryLabel; + @Override - protected void setup(VaadinRequest request) { + protected void init(VaadinRequest request) { + String items = request.getParameter("items"); + int itemsCount = 1; + if (items != null) { + itemsCount = Integer.parseInt(items); + } + + VerticalLayout layout = new VerticalLayout(); + setContent(layout); + layout.addComponent(new Label(getClass().getSimpleName())); + + memoryLabel = new Label(); + memoryLabel.setId("memory"); + layout.addComponent(memoryLabel); + + logLabel = new Label(); + logLabel.setId("log"); + layout.addComponent(logLabel); + T component = createComponent(); - setData(null, 1000000, component, true); - addComponent(createMenu(component)); + setData(null, itemsCount, component, true); + layout.addComponent(createMenu(component)); - addComponent(component); + layout.addComponent(component); + + Button close = new Button("Close UI", event -> close()); + close.setId("close"); + layout.addComponent(close); } protected abstract T createComponent(); @@ -92,12 +124,19 @@ public abstract class AbstractBeansMemoryTest protected abstract void setBackendContainer(T component, List data); + @Override + public VerticalLayout getContent() { + return (VerticalLayout) super.getContent(); + } + + @SuppressWarnings("restriction") private void setData(MenuItem item, int size, T component, boolean memoryContainer) { if (item != null) { MenuItem parent = item.getParent(); parent.getChildren().stream().filter(itm -> !itm.equals(item)) .forEach(itm -> itm.setChecked(false)); + logLabel.setValue(item.getText()); } dataSize = size; isInMemory = memoryContainer; @@ -113,6 +152,24 @@ public abstract class AbstractBeansMemoryTest } else { setBackendContainer(component, persons); } + + HasComponents container = component.getParent(); + setParent(component, null); + memoryLabel.setValue( + String.valueOf(ObjectSizeCalculator.getObjectSize(component))); + + setParent(component, container); + } + + private void setParent(Component component, Component parent) { + try { + Field field = AbstractComponent.class.getDeclaredField("parent"); + field.setAccessible(true); + field.set(component, parent); + } catch (NoSuchFieldException | SecurityException + | IllegalArgumentException | IllegalAccessException e) { + throw new RuntimeException(e); + } } private Component createMenu(T component) { @@ -141,10 +198,12 @@ public abstract class AbstractBeansMemoryTest } private void createContainerSizeMenu(MenuItem menu, T component) { - List items = IntStream.of(1, 100000, 500000, 1000000) + List items = IntStream.of(1, 10000, 100000, 500000, 1000000) .mapToObj(size -> addContainerSizeMenu(size, menu, component)) .collect(Collectors.toList()); - items.get(items.size() - 1).setChecked(true); + if (dataSize == 1) { + items.get(0).setChecked(true); + } } private MenuItem addContainerSizeMenu(int size, MenuItem menu, diff --git a/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java index f2dcdd6851..291da9065d 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java @@ -19,6 +19,10 @@ import java.util.List; import java.util.Optional; import java.util.function.Function; +import javax.servlet.annotation.WebServlet; + +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.VaadinServlet; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Person; import com.vaadin.v7.data.Item; @@ -33,6 +37,17 @@ import com.vaadin.v7.ui.Grid; */ public class CompatibilityGridMemory extends AbstractBeansMemoryTest { + public static final String PATH = "/grid-compatibility-memory/"; + + /** + * The main servlet for the application. + */ + @WebServlet(urlPatterns = PATH + + "*", name = "CompatibilityGridServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = CompatibilityGridMemory.class, productionMode = false, widgetset = "com.vaadin.v7.Vaadin7WidgetSet") + public static class Servlet extends VaadinServlet { + } + private static class ColumnGenerator extends PropertyValueGenerator { diff --git a/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java index 10f5be93ec..079bfb555d 100644 --- a/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java +++ b/uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java @@ -18,6 +18,10 @@ package com.vaadin.tests.performance; import java.util.List; import java.util.Optional; +import javax.servlet.annotation.WebServlet; + +import com.vaadin.annotations.VaadinServletConfiguration; +import com.vaadin.server.VaadinServlet; import com.vaadin.tests.data.bean.Address; import com.vaadin.tests.data.bean.Person; import com.vaadin.ui.Grid; @@ -28,6 +32,17 @@ import com.vaadin.ui.Grid; */ public class GridMemory extends AbstractBeansMemoryTest> { + public static final String PATH = "/grid-memory/"; + + /** + * The main servlet for the application. + */ + @WebServlet(urlPatterns = PATH + + "*", name = "GridServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = GridMemory.class, productionMode = false) + public static class Servlet extends VaadinServlet { + } + @Override protected Grid createComponent() { Grid grid = new Grid<>(); diff --git a/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java new file mode 100644 index 0000000000..b5ba723c7d --- /dev/null +++ b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java @@ -0,0 +1,98 @@ +/* + * Copyright 2000-2016 Vaadin Ltd. + * + * Licensed under the Apache License, Version 2.0 (the "License"); you may not + * use this file except in compliance with the License. You may obtain a copy of + * the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ +package com.vaadin.tests.performance; + +import org.apache.commons.lang3.StringUtils; +import org.junit.Assert; +import org.junit.Test; +import org.junit.experimental.categories.Category; + +import com.vaadin.testbench.By; +import com.vaadin.testcategory.MeasurementTest; +import com.vaadin.tests.tb3.SingleBrowserTest; + +@Category(MeasurementTest.class) +public class MemoryIT extends SingleBrowserTest { + + @Test + public void measureMemory() { + printTeamcityStats("grid-v8-one-item-size", + getGridSize(GridMemory.PATH, 1)); + printTeamcityStats("grid-v7-one-item-size", + getGridSize(CompatibilityGridMemory.PATH, 1)); + + printTeamcityStats("grid-v8-100thousand-items-size", + getGridSize(GridMemory.PATH, 100000)); + printTeamcityStats("grid-v7-100thousand-items-size", + getGridSize(CompatibilityGridMemory.PATH, 100000)); + } + + @Override + protected void closeApplication() { + } + + @Override + protected String getScreenshotDirectory() { + return "."; + } + + private long getGridSize(String path, int itemsCount) { + // Repeat until we get consecutive results within 0.1% of each other + double lastResult = 0; + int stableNumber = 0; + for (int i = 0; i < 500; i++) { + openUI(path, itemsCount); + long currentResult = Long + .parseLong(findElement(By.id("memory")).getText()); + close(); + + if (approx(lastResult, currentResult, 0.001)) { + stableNumber++; + } + lastResult = currentResult; + if (stableNumber == 5) { + return currentResult; + } + } + + Assert.fail("Memory size does not stabilize"); + return -1; + } + + private boolean approx(double num1, double num2, double epsilon) { + double delta = Math.abs(num1 - num2); + double deltaLimit = num2 * epsilon; + return delta < deltaLimit; + } + + private void openUI(String path, int itemsNumber) { + getDriver().get(StringUtils.strip(getBaseURL(), "/") + path + "?items=" + + itemsNumber); + Assert.assertTrue(isElementPresent(By.className("v-grid"))); + } + + private void close() { + findElement(By.id("close")).click(); + } + + private void printTeamcityStats(String key, long value) { + // ##teamcity[buildStatisticValue key='<valueTypeKey>' + // value='<value>'] + System.out.println("##teamcity[buildStatisticValue key='" + key + + "' value='" + value + "']"); + + } +}