* Update MemoryIT to report median render and request time * Add TreeGrid and TreeTable performance test UIs Addresses the collapsed cases for #8849, #8850tags/8.1.0.alpha2
@@ -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(); | |||
} | |||
} |
@@ -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(); | |||
} | |||
} |
@@ -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() { |