diff options
author | Aleksi Hietanen <aleksi@vaadin.com> | 2017-03-21 15:52:16 +0200 |
---|---|---|
committer | Henri Sara <henri.sara@gmail.com> | 2017-03-21 15:52:16 +0200 |
commit | 2dc8c1b5ad81c0dd800225b6185f47fe952251f7 (patch) | |
tree | 6e9bf954f010553ab0347e1667bf07f8a6e15ea2 | |
parent | 414d5b034080b35b94bb20fc66000390818ebc24 (diff) | |
download | vaadin-framework-2dc8c1b5ad81c0dd800225b6185f47fe952251f7.tar.gz vaadin-framework-2dc8c1b5ad81c0dd800225b6185f47fe952251f7.zip |
Measure TreeGrid performance (#8896)
* Update MemoryIT to report median render and request time
* Add TreeGrid and TreeTable performance test UIs
Addresses the collapsed cases for #8849, #8850
3 files changed, 198 insertions, 16 deletions
diff --git a/uitest/src/main/java/com/vaadin/tests/performance/TreeGridMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/TreeGridMemory.java new file mode 100644 index 0000000000..105a05fe49 --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/performance/TreeGridMemory.java @@ -0,0 +1,67 @@ +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.data.HierarchyData; +import com.vaadin.data.provider.InMemoryHierarchicalDataProvider; +import com.vaadin.server.VaadinServlet; +import com.vaadin.tests.data.bean.Address; +import com.vaadin.tests.data.bean.Person; +import com.vaadin.ui.TreeGrid; + +public class TreeGridMemory extends AbstractBeansMemoryTest<TreeGrid<Person>> { + + public static final String PATH = "/tree-grid-memory/"; + + @WebServlet(urlPatterns = PATH + + "*", name = "TreeGridServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = TreeGridMemory.class, productionMode = false) + public static class Servlet extends VaadinServlet { + } + + @Override + protected TreeGrid<Person> createComponent() { + TreeGrid<Person> treeGrid = new TreeGrid<>(); + treeGrid.addColumn(Person::getFirstName).setCaption("First Name"); + treeGrid.addColumn(Person::getLastName).setCaption("Last Name"); + treeGrid.addColumn(person -> Optional.ofNullable(person.getAddress()) + .map(Address::getStreetAddress).orElse(null)) + .setCaption("Street"); + treeGrid.addColumn(person -> Optional.ofNullable(person.getAddress()) + .map(Address::getPostalCode).map(Object::toString).orElse("")) + .setCaption("Zip"); + treeGrid.addColumn(person -> Optional.ofNullable(person.getAddress()) + .map(Address::getCity).orElse(null)).setCaption("City"); + return treeGrid; + } + + @Override + protected void setInMemoryContainer(TreeGrid<Person> treeGrid, + List<Person> data) { + HierarchyData<Person> hierarchyData = new HierarchyData<>(); + if (data.size() % 2 == 0) { + // treat list as if it were a balanced binary tree + hierarchyData.addItem(null, data.get(0)); + int n = 0; + while (2 * n + 2 < data.size()) { + hierarchyData.addItems(data.get(n), + data.subList(2 * n + 1, 2 * n + 3)); + n++; + } + } else { + hierarchyData.addItems(null, data); + } + treeGrid.setDataProvider( + new InMemoryHierarchicalDataProvider<>(hierarchyData)); + } + + @Override + protected void setBackendContainer(TreeGrid<Person> component, + List<Person> data) { + throw new UnsupportedOperationException(); + } +} diff --git a/uitest/src/main/java/com/vaadin/tests/performance/TreeTableMemory.java b/uitest/src/main/java/com/vaadin/tests/performance/TreeTableMemory.java new file mode 100644 index 0000000000..203c74fd4d --- /dev/null +++ b/uitest/src/main/java/com/vaadin/tests/performance/TreeTableMemory.java @@ -0,0 +1,83 @@ +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.v7.data.Item; +import com.vaadin.v7.data.util.HierarchicalContainer; +import com.vaadin.v7.ui.TreeTable; + +public class TreeTableMemory extends AbstractBeansMemoryTest<TreeTable> { + + public static final String PATH = "/tree-table-memory/"; + + @WebServlet(urlPatterns = PATH + + "*", name = "TreeTableServlet", asyncSupported = true) + @VaadinServletConfiguration(ui = TreeTableMemory.class, productionMode = false, widgetset = "com.vaadin.v7.Vaadin7WidgetSet") + public static class Servlet extends VaadinServlet { + } + + @Override + protected TreeTable createComponent() { + TreeTable treeTable = new TreeTable(); + return treeTable; + } + + @Override + protected void setInMemoryContainer(TreeTable treeTable, + List<Person> data) { + HierarchicalContainer container = new HierarchicalContainer(); + container.addContainerProperty("firstName", String.class, null); + container.addContainerProperty("lastName", String.class, null); + container.addContainerProperty("street", String.class, null); + container.addContainerProperty("zip", String.class, null); + container.addContainerProperty("city", String.class, null); + + if (data.size() % 2 == 0) { + createItem(0, container, data); + int n = 0; + while (2 * n + 2 < data.size()) { + for (int i : new Integer[] { 1, 2 }) { + createItem(2 * n + i, container, data); + container.setParent(2 * n + i, n); + } + n++; + } + } else { + for (int i = 0; i < data.size(); i++) { + createItem(i, container, data); + } + } + treeTable.setContainerDataSource(container); + } + + private void createItem(int index, HierarchicalContainer container, + List<Person> data) { + Item item = container.addItem(index); + item.getItemProperty("firstName") + .setValue(data.get(index).getFirstName()); + item.getItemProperty("lastName") + .setValue(data.get(index).getLastName()); + item.getItemProperty("street") + .setValue(Optional.ofNullable(data.get(index).getAddress()) + .map(Address::getStreetAddress).orElse(null)); + item.getItemProperty("zip") + .setValue(Optional.ofNullable(data.get(index).getAddress()) + .map(Address::getPostalCode).map(Object::toString) + .orElse("")); + item.getItemProperty("city") + .setValue(Optional.ofNullable(data.get(index).getAddress()) + .map(Address::getCity).orElse(null)); + } + + @Override + protected void setBackendContainer(TreeTable component, List<Person> data) { + throw new UnsupportedOperationException(); + } +} diff --git a/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java index 4ac3ae68ff..0f4249b6ea 100644 --- a/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java +++ b/uitest/src/test/java/com/vaadin/tests/performance/MemoryIT.java @@ -15,6 +15,9 @@ */ package com.vaadin.tests.performance; +import java.util.ArrayList; +import java.util.List; + import org.apache.commons.lang3.StringUtils; import org.junit.Assert; import org.junit.Test; @@ -27,29 +30,40 @@ import com.vaadin.tests.tb3.SingleBrowserTest; @Category(MeasurementTest.class) public class MemoryIT extends SingleBrowserTest { + private static final int MAX_ITERATIONS = 20; + @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)); + performTest(GridMemory.PATH, 1, "grid-v8-one-item-"); + performTest(CompatibilityGridMemory.PATH, 1, "grid-v7-one-item-"); + + performTest(GridMemory.PATH, 100000, "grid-v8-100thousand-items-"); + performTest(CompatibilityGridMemory.PATH, 100000, + "grid-v7-100thousand-items-"); + + performTest(TreeGridMemory.PATH, 1, "tree-grid-one-item-"); + performTest(TreeTableMemory.PATH, 1, "tree-table-one-item-"); + + performTest(TreeGridMemory.PATH, 100000, + "tree-grid-100thousand-items-"); + performTest(TreeTableMemory.PATH, 100000, + "tree-table-100thousand-items-"); } @Override protected void closeApplication() { } - private long getGridSize(String path, int itemsCount) { - // Repeat until we get consecutive results within 0.1% of each other + private void performTest(String path, int itemsCount, + String teamcityStatPrefix) { double lastResult = 0; int stableNumber = 0; - for (int i = 0; i < 500; i++) { + List<Long> renderingTimes = new ArrayList<>(); + List<Long> requestTimes = new ArrayList<>(); + for (int i = 0; i < MAX_ITERATIONS; i++) { openUI(path, itemsCount); + renderingTimes.add(testBench().totalTimeSpentRendering()); + requestTimes.add(testBench().totalTimeSpentServicingRequests()); long currentResult = Long .parseLong(findElement(By.id("memory")).getText()); close(); @@ -59,12 +73,29 @@ public class MemoryIT extends SingleBrowserTest { } lastResult = currentResult; if (stableNumber == 5) { - return currentResult; + System.out.println( + "Memory usage stabilized after " + i + " iterations"); + printTeamcityStats(teamcityStatPrefix + "size", currentResult); + printTeamcityStats(teamcityStatPrefix + "rendering-time", + median(renderingTimes)); + printTeamcityStats(teamcityStatPrefix + "request-time", + median(requestTimes)); + return; + } + if (i == MAX_ITERATIONS) { + Assert.fail("Memory size does not stabilize"); } } + } - Assert.fail("Memory size does not stabilize"); - return -1; + private long median(List<Long> values) { + values.sort(Long::compareTo); + int middle = values.size() / 2; + if (values.size() % 2 == 1) { + return values.get(middle); + } else { + return (values.get(middle - 1) + values.get(middle)) / 2; + } } private boolean approx(double num1, double num2, double epsilon) { @@ -76,7 +107,8 @@ public class MemoryIT extends SingleBrowserTest { private void openUI(String path, int itemsNumber) { getDriver().get(StringUtils.strip(getBaseURL(), "/") + path + "?items=" + itemsNumber); - Assert.assertTrue(isElementPresent(By.className("v-grid"))); + Assert.assertTrue(isElementPresent(By.className("v-grid")) + || isElementPresent(By.className("v-table"))); } private void close() { |