]> source.dussan.org Git - vaadin-framework.git/commitdiff
Memory measurement test for V7&V8 Grids, 1 item and 100 000 items.
authorDenis Anisimov <denis@vaadin.com>
Fri, 14 Oct 2016 08:36:18 +0000 (11:36 +0300)
committerDenis Anisimov <denis@vaadin.com>
Fri, 14 Oct 2016 14:26:01 +0000 (14:26 +0000)
Change-Id: I66b358ff40703f2713272323ba1c5ae8778c8413

pom.xml
uitest/pom.xml
uitest/src/main/java/com/vaadin/testcategory/MeasurementTest.java [new file with mode: 0644]
uitest/src/main/java/com/vaadin/tests/performance/AbstractBeansMemoryTest.java
uitest/src/main/java/com/vaadin/tests/performance/CompatibilityGridMemory.java
uitest/src/main/java/com/vaadin/tests/performance/GridMemory.java
uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java [new file with mode: 0644]

diff --git a/pom.xml b/pom.xml
index 8e978a7e68d805396aa8a9a3d4153036e5363b01..e82cbac4a45db45f19679be2abc49364ef5ec524 100644 (file)
--- a/pom.xml
+++ b/pom.xml
                 </plugins>
             </build>
         </profile>
+        <profile>
+            <id>measurements</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <properties>
+                <skipTests>true</skipTests>
+            </properties>
+        </profile>
     </profiles>
 
 </project>
index 6055d84d97895747883044bbb3ac7d8519bcaa45..4b183e578b3dff08f8862c26de5cdccdb59d7d77 100644 (file)
                 <skip.uitest.deployment>false</skip.uitest.deployment>
             </properties>
         </profile>
+        <profile>
+            <id>default</id>
+            <activation>
+                <activeByDefault>true</activeByDefault>
+            </activation>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-surefire-plugin</artifactId>
+                        <configuration>
+                            <excludedGroups>com.vaadin.testcategory.MeasurementTest</excludedGroups>
+                        </configuration>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
+        <profile>
+            <id>measurements</id>
+            <activation>
+                <activeByDefault>false</activeByDefault>
+            </activation>
+            <properties>
+                <skipTests>false</skipTests>
+            </properties>
+            <build>
+                <plugins>
+                    <plugin>
+                        <artifactId>maven-failsafe-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>integration-test</goal>
+                                    <goal>verify</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                        <configuration>
+                            <groups>com.vaadin.testcategory.MeasurementTest</groups>
+                            <systemPropertyVariables>
+                                <phantomjs.binary.path>${phantomjs.binary}</phantomjs.binary.path>
+                            </systemPropertyVariables>
+                        </configuration>
+                    </plugin>
+                    <plugin>
+                        <groupId>org.eclipse.jetty</groupId>
+                        <artifactId>jetty-maven-plugin</artifactId>
+                        <configuration>
+                            <httpConnector>
+                                <port>8888</port>
+                            </httpConnector>
+                            <scanIntervalSeconds>-1</scanIntervalSeconds>
+                            <stopPort>8081</stopPort>
+                            <stopWait>5</stopWait>
+                            <stopKey>foo</stopKey>
+                        </configuration>
+                        <executions>
+                            <!-- start and stop jetty (running our app) when 
+                                running integration tests -->
+                            <execution>
+                                <id>start-jetty</id>
+                                <phase>pre-integration-test</phase>
+                                <goals>
+                                    <goal>start</goal>
+                                </goals>
+                            </execution>
+                            <execution>
+                                <id>stop-jetty</id>
+                                <phase>post-integration-test</phase>
+                                <goals>
+                                    <goal>stop</goal>
+                                </goals>
+                            </execution>
+                        </executions>
+                    </plugin>
+                    <plugin>
+                        <groupId>com.github.klieber</groupId>
+                        <artifactId>phantomjs-maven-plugin</artifactId>
+                        <executions>
+                            <execution>
+                                <goals>
+                                    <goal>install</goal>
+                                </goals>
+                                <configuration>
+                                    <version>${phantomjs.version}</version>
+                                </configuration>
+                            </execution>
+                        </executions>
+                    </plugin>
+                </plugins>
+            </build>
+        </profile>
     </profiles>
 
 </project>
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 (file)
index 0000000..7986867
--- /dev/null
@@ -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.
+ * <p>
+ * The purpose of the test to make some measurement (memory, time, etc.).
+ * 
+ * 
+ * @author Vaadin Ltd
+ *
+ */
+public interface MeasurementTest {
+
+}
index 62b42f56f8c250747459373a78617bc9e6759409..526b758e22682bfde7b6426f5f31efbae16d2aa7 100644 (file)
@@ -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<T extends AbstractComponent>
-        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<T extends AbstractComponent>
 
     protected abstract void setBackendContainer(T component, List<Person> 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<T extends AbstractComponent>
         } 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<T extends AbstractComponent>
     }
 
     private void createContainerSizeMenu(MenuItem menu, T component) {
-        List<MenuItem> items = IntStream.of(1, 100000, 500000, 1000000)
+        List<MenuItem> 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,
index f2dcdd6851dd0b8d6c0130ec323b981e5e490c32..291da9065d96b90b089d483e9b8bb65de6307df9 100644 (file)
@@ -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<Grid> {
 
+    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<String> {
 
index 10f5be93ec880848a9c0a80300b20956b17b848a..079bfb555d51806af1add56e38e10d3e9987f9ec 100644 (file)
@@ -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<Grid<Person>> {
 
+    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<Person> createComponent() {
         Grid<Person> 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 (file)
index 0000000..b5ba723
--- /dev/null
@@ -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=&#39;&lt;valueTypeKey&gt;&#39;
+        // value=&#39;&lt;value&gt;&#39;]
+        System.out.println("##teamcity[buildStatisticValue key='" + key
+                + "' value='" + value + "']");
+
+    }
+}