1 /* 2 * Copyright (C) 2017 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); you 5 * may not use this file except in compliance with the License. You may 6 * obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 13 * implied. See the License for the specific language governing 14 * permissions and limitations under the License. 15 */ 16 17 package com.android.vts.servlet; 18 19 import com.android.vts.entity.ProfilingPointEntity; 20 import com.android.vts.entity.ProfilingPointSummaryEntity; 21 import com.android.vts.util.BoxPlot; 22 import com.android.vts.util.DatastoreHelper; 23 import com.android.vts.util.FilterUtil; 24 import com.android.vts.util.GraphSerializer; 25 import com.google.appengine.api.datastore.DatastoreService; 26 import com.google.appengine.api.datastore.DatastoreServiceFactory; 27 import com.google.appengine.api.datastore.Entity; 28 import com.google.appengine.api.datastore.Query; 29 import com.google.appengine.api.datastore.Query.Filter; 30 import com.google.gson.Gson; 31 import com.google.gson.GsonBuilder; 32 import java.io.IOException; 33 import java.util.ArrayList; 34 import java.util.Comparator; 35 import java.util.HashMap; 36 import java.util.HashSet; 37 import java.util.List; 38 import java.util.Map; 39 import java.util.Set; 40 import java.util.concurrent.TimeUnit; 41 import java.util.logging.Level; 42 import java.util.stream.Collectors; 43 import javax.servlet.RequestDispatcher; 44 import javax.servlet.ServletException; 45 import javax.servlet.http.HttpServletRequest; 46 import javax.servlet.http.HttpServletResponse; 47 48 /** Servlet for handling requests to load graphs. */ 49 public class ShowProfilingOverviewServlet extends BaseServlet { 50 private static final String PROFILING_OVERVIEW_JSP = "WEB-INF/jsp/show_profiling_overview.jsp"; 51 52 @Override getNavParentType()53 public PageType getNavParentType() { 54 return PageType.PROFILING_LIST; 55 } 56 57 @Override getBreadcrumbLinks(HttpServletRequest request)58 public List<Page> getBreadcrumbLinks(HttpServletRequest request) { 59 List<Page> links = new ArrayList<>(); 60 String testName = request.getParameter("testName"); 61 links.add(new Page(PageType.PROFILING_OVERVIEW, testName, "?testName=" + testName)); 62 return links; 63 } 64 65 @Override doGetHandler(HttpServletRequest request, HttpServletResponse response)66 public void doGetHandler(HttpServletRequest request, HttpServletResponse response) 67 throws IOException { 68 RequestDispatcher dispatcher = null; 69 DatastoreService datastore = DatastoreServiceFactory.getDatastoreService(); 70 71 String testName = request.getParameter("testName"); 72 long endTime = TimeUnit.MILLISECONDS.toMicros(System.currentTimeMillis()); 73 long startTime = endTime - TimeUnit.DAYS.toMicros(30); 74 75 // Create a query for test runs matching the time window filter 76 77 Map<String, String[]> parameterMap = request.getParameterMap(); 78 boolean hasBranchFilter = parameterMap.containsKey(FilterUtil.FilterKey.BRANCH.getValue()); 79 Filter deviceFilter; 80 if (hasBranchFilter) { 81 deviceFilter = 82 FilterUtil.FilterKey.BRANCH.getFilterForString( 83 FilterUtil.getFirstParameter( 84 parameterMap, FilterUtil.FilterKey.BRANCH.getValue())); 85 } else { 86 deviceFilter = 87 FilterUtil.FilterKey.BRANCH.getFilterForString(ProfilingPointSummaryEntity.ALL); 88 } 89 90 boolean hasTargetFilter = parameterMap.containsKey(FilterUtil.FilterKey.TARGET.getValue()); 91 if (hasTargetFilter) { 92 deviceFilter = 93 Query.CompositeFilterOperator.and( 94 deviceFilter, 95 FilterUtil.FilterKey.TARGET.getFilterForString( 96 FilterUtil.getFirstParameter( 97 parameterMap, FilterUtil.FilterKey.TARGET.getValue()))); 98 } else { 99 deviceFilter = 100 Query.CompositeFilterOperator.and( 101 deviceFilter, 102 FilterUtil.FilterKey.TARGET.getFilterForString( 103 ProfilingPointSummaryEntity.ALL)); 104 } 105 106 Filter startFilter = 107 new Query.FilterPredicate( 108 ProfilingPointSummaryEntity.START_TIME, 109 Query.FilterOperator.GREATER_THAN_OR_EQUAL, 110 startTime); 111 Filter endFilter = 112 new Query.FilterPredicate( 113 ProfilingPointSummaryEntity.START_TIME, 114 Query.FilterOperator.LESS_THAN_OR_EQUAL, 115 endTime); 116 Filter timeFilter = Query.CompositeFilterOperator.and(startFilter, endFilter); 117 118 Filter filter = Query.CompositeFilterOperator.and(timeFilter, deviceFilter); 119 120 Query profilingPointQuery = 121 new Query(ProfilingPointEntity.KIND) 122 .setFilter( 123 new Query.FilterPredicate( 124 ProfilingPointEntity.TEST_NAME, 125 Query.FilterOperator.EQUAL, 126 testName)); 127 128 List<ProfilingPointEntity> profilingPoints = new ArrayList<>(); 129 for (Entity e : 130 datastore 131 .prepare(profilingPointQuery) 132 .asIterable(DatastoreHelper.getLargeBatchOptions())) { 133 ProfilingPointEntity pp = ProfilingPointEntity.fromEntity(e); 134 if (pp == null) continue; 135 profilingPoints.add(pp); 136 } 137 138 Map<ProfilingPointEntity, Iterable<Entity>> asyncEntities = new HashMap<>(); 139 for (ProfilingPointEntity pp : profilingPoints) { 140 Query profilingQuery = 141 new Query(ProfilingPointSummaryEntity.KIND) 142 .setAncestor(pp.getKey()) 143 .setFilter(filter); 144 asyncEntities.put( 145 pp, 146 datastore 147 .prepare(profilingQuery) 148 .asIterable(DatastoreHelper.getLargeBatchOptions())); 149 } 150 151 Map<String, BoxPlot> plotMap = new HashMap<>(); 152 for (ProfilingPointEntity pp : profilingPoints) { 153 if (!plotMap.containsKey(pp.getProfilingPointName())) { 154 plotMap.put( 155 pp.getProfilingPointName(), new BoxPlot(pp.getProfilingPointName(), null, pp.getXLabel())); 156 } 157 BoxPlot plot = plotMap.get(pp.getProfilingPointName()); 158 Set<Long> timestamps = new HashSet<>(); 159 for (Entity e : asyncEntities.get(pp)) { 160 ProfilingPointSummaryEntity pps = ProfilingPointSummaryEntity.fromEntity(e); 161 if (pps == null) continue; 162 plot.addSeriesData(Long.toString(pps.getStartTime()), pps.getSeries(), pps.getGlobalStats()); 163 timestamps.add(pps.getStartTime()); 164 } 165 List<Long> timestampList = new ArrayList<>(timestamps); 166 timestampList.sort(Comparator.reverseOrder()); 167 List<String> timestampStrings = 168 timestampList.stream().map(Object::toString).collect(Collectors.toList()); 169 plot.setLabels(timestampStrings); 170 } 171 172 List<BoxPlot> plots = new ArrayList<>(); 173 for (String key : plotMap.keySet()) { 174 BoxPlot plot = plotMap.get(key); 175 if (plot.size() == 0) continue; 176 plots.add(plot); 177 } 178 plots.sort((b1, b2) -> b1.getName().compareTo(b2.getName())); 179 180 Gson gson = 181 new GsonBuilder() 182 .registerTypeHierarchyAdapter(BoxPlot.class, new GraphSerializer()) 183 .create(); 184 185 FilterUtil.setAttributes(request, parameterMap); 186 request.setAttribute("plots", gson.toJson(plots)); 187 request.setAttribute("testName", request.getParameter("testName")); 188 request.setAttribute("branches", new Gson().toJson(DatastoreHelper.getAllBranches())); 189 request.setAttribute("devices", new Gson().toJson(DatastoreHelper.getAllBuildFlavors())); 190 dispatcher = request.getRequestDispatcher(PROFILING_OVERVIEW_JSP); 191 try { 192 dispatcher.forward(request, response); 193 } catch (ServletException e) { 194 logger.log(Level.SEVERE, "Servlet Exception caught : ", e); 195 } 196 } 197 } 198