diff options
author | Ryan Campbell <ryanjcampbell@google.com> | 2017-07-17 17:23:11 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2017-07-17 17:23:11 +0000 |
commit | 2b532bee21a2b3318435ae55928a769e6f2a3df7 (patch) | |
tree | e76b48a424d523884921e273e2f1765c473495a5 | |
parent | ad3b6e33d9ca954c7d9c9029653325d01722409f (diff) | |
parent | 1c1fda4205799fd97452da3b0d9c0d3b21ec1fb0 (diff) | |
download | dashboard-2b532bee21a2b3318435ae55928a769e6f2a3df7.tar.gz |
Merge changes from topic 'profiling analysis'
* changes:
Create profiling tab/entry point.
Update test entities to indicate profiling data.
8 files changed, 202 insertions, 19 deletions
diff --git a/src/main/java/com/android/vts/entity/TestEntity.java b/src/main/java/com/android/vts/entity/TestEntity.java index bbba6c6..9a8d32a 100644 --- a/src/main/java/com/android/vts/entity/TestEntity.java +++ b/src/main/java/com/android/vts/entity/TestEntity.java @@ -17,6 +17,8 @@ package com.android.vts.entity; import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.Key; +import com.google.appengine.api.datastore.KeyFactory; import java.util.logging.Level; import java.util.logging.Logger; @@ -25,25 +27,61 @@ public class TestEntity implements DashboardEntity { protected static final Logger logger = Logger.getLogger(TestEntity.class.getName()); public static final String KIND = "Test"; + public static final String HAS_PROFILING_DATA = "hasProfilingData"; public final String testName; + public final Key key; + public boolean hasProfilingData; /** - * Create a TestEntity object with status metadata. + * Create a TestEntity object. * * @param testName The name of the test. + * @param hasProfilingData True if the test includes profiling data. */ - public TestEntity(String testName) { + public TestEntity(String testName, boolean hasProfilingData) { this.testName = testName; + this.key = KeyFactory.createKey(KIND, testName); + this.hasProfilingData = hasProfilingData; + } + + /** + * Create a TestEntity object. + * + * @param testName The name of the test. + */ + public TestEntity(String testName) { + this(testName, false); } @Override public Entity toEntity() { - Entity testEntity = new Entity(KIND, this.testName); + Entity testEntity = new Entity(this.key); + testEntity.setProperty(HAS_PROFILING_DATA, this.hasProfilingData); return testEntity; } /** + * Set to true if the test has profiling data. + * + * @param hasProfilingData The value to store. + */ + public void setHasProfilingData(boolean hasProfilingData) { + this.hasProfilingData = hasProfilingData; + } + + @Override + public boolean equals(Object obj) { + if (obj == null || !TestEntity.class.isAssignableFrom(obj.getClass())) { + return false; + } + TestEntity test2 = (TestEntity) obj; + return ( + this.testName.equals(test2.testName) && + this.hasProfilingData == test2.hasProfilingData); + } + + /** * Convert an Entity object to a TestEntity. * * @param e The entity to process. @@ -56,6 +94,10 @@ public class TestEntity implements DashboardEntity { return null; } String testName = e.getKey().getName(); - return new TestEntity(testName); + boolean hasProfilingData = false; + if (e.hasProperty(HAS_PROFILING_DATA)) { + hasProfilingData = (boolean) e.getProperty(HAS_PROFILING_DATA); + } + return new TestEntity(testName, hasProfilingData); } } diff --git a/src/main/java/com/android/vts/servlet/BaseServlet.java b/src/main/java/com/android/vts/servlet/BaseServlet.java index d24c111..7382846 100644 --- a/src/main/java/com/android/vts/servlet/BaseServlet.java +++ b/src/main/java/com/android/vts/servlet/BaseServlet.java @@ -44,13 +44,15 @@ public abstract class BaseServlet extends HttpServlet { TOT("ToT", "/"), RELEASE("Release", "/show_release"), COVERAGE_OVERVIEW("Coverage", "/show_coverage_overview"), + PROFILING_LIST("Profiling", "/show_profiling_list"), TABLE("", "/show_table"), TREE("", "/show_tree"), GRAPH("Profiling", "/show_graph"), COVERAGE("Coverage", "/show_coverage"), - PERFORMANCE("Performance Digest", "/show_performance_digest"), + PERFORMANCE_DIGEST("Performance Digest", "/show_performance_digest"), PLAN_RELEASE("", "/show_plan_release"), - PLAN_RUN("Plan Run", "/show_plan_run"); + PLAN_RUN("Plan Run", "/show_plan_run"), + PROFILING_OVERVIEW("", "/show_profiling_overview"); public final String defaultName; public final String defaultUrl; @@ -100,6 +102,7 @@ public abstract class BaseServlet extends HttpServlet { links.add(new Page(PageType.TOT)); links.add(new Page(PageType.RELEASE)); links.add(new Page(PageType.COVERAGE_OVERVIEW)); + links.add(new Page(PageType.PROFILING_LIST)); navbarLinks = links; } @@ -130,6 +133,9 @@ public abstract class BaseServlet extends HttpServlet { int activeIndex; switch (getNavParentType()) { + case PROFILING_LIST: + activeIndex = 3; + break; case COVERAGE_OVERVIEW: activeIndex = 2; break; diff --git a/src/main/java/com/android/vts/servlet/ShowPerformanceDigestServlet.java b/src/main/java/com/android/vts/servlet/ShowPerformanceDigestServlet.java index 51b0127..44afbfa 100644 --- a/src/main/java/com/android/vts/servlet/ShowPerformanceDigestServlet.java +++ b/src/main/java/com/android/vts/servlet/ShowPerformanceDigestServlet.java @@ -75,7 +75,7 @@ public class ShowPerformanceDigestServlet extends BaseServlet { List<Page> links = new ArrayList<>(); String testName = request.getParameter("testName"); links.add(new Page(PageType.TABLE, testName, "?testName=" + testName)); - links.add(new Page(PageType.PERFORMANCE, "?testName=" + testName)); + links.add(new Page(PageType.PERFORMANCE_DIGEST, "?testName=" + testName)); return links; } diff --git a/src/main/java/com/android/vts/servlet/ShowProfilingListServlet.java b/src/main/java/com/android/vts/servlet/ShowProfilingListServlet.java new file mode 100644 index 0000000..cbebd2c --- /dev/null +++ b/src/main/java/com/android/vts/servlet/ShowProfilingListServlet.java @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2017 The Android Open Source Project + * + * 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.android.vts.servlet; + +import com.android.vts.entity.TestEntity; +import com.google.appengine.api.datastore.DatastoreService; +import com.google.appengine.api.datastore.DatastoreServiceFactory; +import com.google.appengine.api.datastore.Entity; +import com.google.appengine.api.datastore.Query; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import javax.servlet.RequestDispatcher; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/** Servlet for handling requests to display profiling tests. */ +public class ShowProfilingListServlet extends BaseServlet { + private static final String PROFILING_LIST_JSP = "WEB-INF/jsp/show_profiling_list.jsp"; + + @Override + public PageType getNavParentType() { + return PageType.PROFILING_LIST; + } + + @Override + public List<Page> getBreadcrumbLinks(HttpServletRequest request) { + return null; + } + + @Override + public void doGetHandler(HttpServletRequest request, HttpServletResponse response) + throws IOException { + DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); + Query.Filter profilingFilter = new Query.FilterPredicate( + TestEntity.HAS_PROFILING_DATA, Query.FilterOperator.EQUAL, true); + Query query = new Query(TestEntity.KIND) + .setFilter(profilingFilter) + .setKeysOnly(); + Set<String> profilingTests = new HashSet<>(); + for (Entity test : datastore.prepare(query).asIterable()) { + profilingTests.add(test.getKey().getName()); + } + + List<String> tests = new ArrayList<>(profilingTests); + tests.sort(Comparator.naturalOrder()); + + response.setStatus(HttpServletResponse.SC_OK); + request.setAttribute("testNames", tests); + RequestDispatcher dispatcher = request.getRequestDispatcher(PROFILING_LIST_JSP); + try { + dispatcher.forward(request, response); + } catch (ServletException e) { + logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e); + } + } +} diff --git a/src/main/java/com/android/vts/servlet/ShowProfilingOverviewServlet.java b/src/main/java/com/android/vts/servlet/ShowProfilingOverviewServlet.java index bb1174e..be830e9 100644 --- a/src/main/java/com/android/vts/servlet/ShowProfilingOverviewServlet.java +++ b/src/main/java/com/android/vts/servlet/ShowProfilingOverviewServlet.java @@ -61,16 +61,14 @@ public class ShowProfilingOverviewServlet extends BaseServlet { @Override public PageType getNavParentType() { - return PageType.TOT; + return PageType.PROFILING_LIST; } @Override public List<Page> getBreadcrumbLinks(HttpServletRequest request) { List<Page> links = new ArrayList<>(); String testName = request.getParameter("testName"); - links.add(new Page(PageType.TABLE, testName, "?testName=" + testName)); - - links.add(new Page(PageType.GRAPH, "?testName=" + testName)); + links.add(new Page(PageType.PROFILING_OVERVIEW, testName, "?testName=" + testName)); return links; } diff --git a/src/main/java/com/android/vts/util/DatastoreHelper.java b/src/main/java/com/android/vts/util/DatastoreHelper.java index b738df7..e38555b 100644 --- a/src/main/java/com/android/vts/util/DatastoreHelper.java +++ b/src/main/java/com/android/vts/util/DatastoreHelper.java @@ -202,11 +202,11 @@ public class DatastoreHelper { String testBuildId = report.getBuildInfo().getId().toStringUtf8(); String hostName = report.getHostInfo().getHostname().toStringUtf8(); - Entity testEntity = new TestEntity(testName).toEntity(); + TestEntity testEntity = new TestEntity(testName); Key testRunKey = KeyFactory.createKey( - testEntity.getKey(), TestRunEntity.KIND, report.getStartTimestamp()); + testEntity.key, TestRunEntity.KIND, report.getStartTimestamp()); long passCount = 0; long failCount = 0; @@ -250,6 +250,7 @@ public class DatastoreHelper { logger.log(Level.WARNING, "Invalid profiling report in test run " + testRunKey); } puts.add(profilingEntity.toEntity()); + testEntity.setHasProfilingData(true); } int lastIndex = testCases.size() - 1; @@ -321,6 +322,7 @@ public class DatastoreHelper { logger.log(Level.WARNING, "Invalid profiling report in test run " + testRunKey); } puts.add(profilingEntity.toEntity()); + testEntity.setHasProfilingData(true); } List<String> logLinks = new ArrayList<>(); @@ -332,7 +334,7 @@ public class DatastoreHelper { TestRunEntity testRunEntity = new TestRunEntity( - testEntity.getKey(), + testEntity.key, testRunType, startTimestamp, endTimestamp, @@ -347,14 +349,19 @@ public class DatastoreHelper { puts.add(testRunEntity.toEntity()); int retries = 0; + Entity test = testEntity.toEntity(); while (true) { Transaction txn = datastore.beginTransaction(); try { // Check if test already exists in the database try { - datastore.get(testEntity.getKey()); + Entity oldTest = datastore.get(testEntity.key); + TestEntity oldTestEntity = TestEntity.fromEntity(oldTest); + if (oldTestEntity == null || !oldTestEntity.equals(testEntity)) { + puts.add(test); + } } catch (EntityNotFoundException e) { - puts.add(testEntity); + puts.add(test); } datastore.put(puts); txn.commit(); @@ -370,12 +377,12 @@ public class DatastoreHelper { } catch (ConcurrentModificationException | DatastoreFailureException | DatastoreTimeoutException e) { - puts.remove(testEntity); - logger.log(Level.WARNING, "Retrying test run insert: " + testEntity.getKey()); + puts.remove(test); + logger.log(Level.WARNING, "Retrying test run insert: " + test.getKey()); if (retries++ >= MAX_WRITE_RETRIES) { logger.log( Level.SEVERE, - "Exceeded maximum test run retries: " + testEntity.getKey()); + "Exceeded maximum test run retries: " + test.getKey()); throw e; } } finally { diff --git a/src/main/webapp/WEB-INF/jsp/show_profiling_list.jsp b/src/main/webapp/WEB-INF/jsp/show_profiling_list.jsp new file mode 100644 index 0000000..f1615d7 --- /dev/null +++ b/src/main/webapp/WEB-INF/jsp/show_profiling_list.jsp @@ -0,0 +1,44 @@ +<%-- + ~ Copyright (c) 2017 The Android Open Source Project + ~ + ~ 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. + --%> +<%@ page contentType='text/html;charset=UTF-8' language='java' %> +<%@ taglib prefix='fn' uri='http://java.sun.com/jsp/jstl/functions' %> +<%@ taglib prefix='c' uri='http://java.sun.com/jsp/jstl/core'%> + +<html> + <link rel='stylesheet' href='/css/show_release.css'> + <%@ include file='header.jsp' %> + <body> + <div class='container'> + <div class='row'> + <div class='col s12'> + <h4 id='section-header'>Profiling Tests</h4> + </div> + </div> + <div class='row' id='options'> + <c:forEach items='${testNames}' var='test'> + <div> + <a href='/show_profiling_overview?testName=${test}'> + <div class='col s12 card hoverable option valign-wrapper waves-effect'> + <span class='entry valign'>${test}</span> + </div> + </a> + </div> + </c:forEach> + </div> + </div> + <%@ include file='footer.jsp' %> + </body> +</html> diff --git a/src/main/webapp/WEB-INF/web.xml b/src/main/webapp/WEB-INF/web.xml index ad494e7..0dfec12 100644 --- a/src/main/webapp/WEB-INF/web.xml +++ b/src/main/webapp/WEB-INF/web.xml @@ -46,6 +46,11 @@ Copyright 2016 Google Inc. All Rights Reserved. </servlet> <servlet> + <servlet-name>show_profiling_list</servlet-name> + <servlet-class>com.android.vts.servlet.ShowProfilingListServlet</servlet-class> +</servlet> + +<servlet> <servlet-name>show_profiling_overview</servlet-name> <servlet-class>com.android.vts.servlet.ShowProfilingOverviewServlet</servlet-class> </servlet> @@ -141,6 +146,11 @@ Copyright 2016 Google Inc. All Rights Reserved. </servlet-mapping> <servlet-mapping> + <servlet-name>show_profiling_list</servlet-name> + <url-pattern>/show_profiling_list/*</url-pattern> +</servlet-mapping> + +<servlet-mapping> <servlet-name>show_profiling_overview</servlet-name> <url-pattern>/show_profiling_overview/*</url-pattern> </servlet-mapping> |