• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2016 Google Inc. All Rights Reserved.
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.DeviceInfoEntity;
20 import com.android.vts.entity.ProfilingPointRunEntity;
21 import com.android.vts.entity.TestEntity;
22 import com.android.vts.entity.TestRunEntity;
23 import com.android.vts.util.DatastoreHelper;
24 import com.android.vts.util.FilterUtil;
25 import com.android.vts.util.Graph;
26 import com.android.vts.util.GraphSerializer;
27 import com.android.vts.util.Histogram;
28 import com.android.vts.util.LineGraph;
29 import com.android.vts.util.PerformanceUtil;
30 import com.google.appengine.api.datastore.DatastoreService;
31 import com.google.appengine.api.datastore.DatastoreServiceFactory;
32 import com.google.appengine.api.datastore.Entity;
33 import com.google.appengine.api.datastore.EntityNotFoundException;
34 import com.google.appengine.api.datastore.Key;
35 import com.google.appengine.api.datastore.KeyFactory;
36 import com.google.appengine.api.datastore.PropertyProjection;
37 import com.google.appengine.api.datastore.Query;
38 import com.google.appengine.api.datastore.Query.Filter;
39 import com.google.gson.Gson;
40 import com.google.gson.GsonBuilder;
41 import java.io.IOException;
42 import java.util.ArrayList;
43 import java.util.Arrays;
44 import java.util.HashMap;
45 import java.util.HashSet;
46 import java.util.List;
47 import java.util.Map;
48 import java.util.Set;
49 import java.util.concurrent.TimeUnit;
50 import java.util.logging.Level;
51 import javax.servlet.RequestDispatcher;
52 import javax.servlet.ServletException;
53 import javax.servlet.http.HttpServletRequest;
54 import javax.servlet.http.HttpServletResponse;
55 import org.apache.commons.lang.StringUtils;
56 
57 /** Servlet for handling requests to load graphs. */
58 public class ShowGraphServlet extends BaseServlet {
59     private static final String GRAPH_JSP = "WEB-INF/jsp/show_graph.jsp";
60     private static final long DEFAULT_FILTER_OPTION = -1;
61 
62     private static final String HIDL_HAL_OPTION = "hidl_hal_mode";
63     private static final String[] splitKeysArray = new String[] {HIDL_HAL_OPTION};
64     private static final Set<String> splitKeySet =
65             new HashSet<String>(Arrays.asList(splitKeysArray));
66     private static final String PROFILING_DATA_ALERT = "No profiling data was found.";
67 
68     @Override
getNavbarLinks(HttpServletRequest request)69     public List<String[]> getNavbarLinks(HttpServletRequest request) {
70         List<String[]> links = new ArrayList<>();
71         Page root = Page.HOME;
72         String[] rootEntry = new String[] {root.getUrl(), root.getName()};
73         links.add(rootEntry);
74 
75         Page table = Page.TABLE;
76         String testName = request.getParameter("testName");
77         String name = table.getName() + testName;
78         String url = table.getUrl() + "?testName=" + testName;
79         String[] tableEntry = new String[] {url, name};
80         links.add(tableEntry);
81 
82         Page graph = Page.GRAPH;
83         String profilingPointName = request.getParameter("profilingPoint");
84         url = graph.getUrl() + "?testName=" + testName + "&profilingPoint=" + profilingPointName;
85         String[] graphEntry = new String[] {url, graph.getName()};
86         links.add(graphEntry);
87         return links;
88     }
89 
90     /**
91      * Process a profiling report message and add it to the map of graphs.
92      *
93      * @param profilingRun The Entity of a profiling point run to process.
94      * @param idString The ID derived from the test run to identify the profiling report.
95      * @param graphMap A map from graph name to Graph object.
96      */
processProfilingRun( Entity profilingRun, String idString, Map<String, Graph> graphMap)97     private static void processProfilingRun(
98             Entity profilingRun, String idString, Map<String, Graph> graphMap) {
99         ProfilingPointRunEntity pt = ProfilingPointRunEntity.fromEntity(profilingRun);
100         if (pt == null)
101             return;
102         String name = PerformanceUtil.getOptionAlias(profilingRun, splitKeySet);
103         Graph g = null;
104         if (pt.labels != null && pt.labels.size() == pt.values.size()) {
105             g = new LineGraph(name);
106         } else if (pt.labels == null && pt.values.size() > 0) {
107             g = new Histogram(name);
108         } else {
109             return;
110         }
111         if (!graphMap.containsKey(name)) {
112             graphMap.put(name, g);
113         }
114         graphMap.get(name).addData(idString, pt);
115     }
116 
117     /**
118      * Get a summary string describing the devices in the test run.
119      *
120      * @param testRun The entity storing test run information.
121      * @param selectedDevice The name of the selected device.
122      * @return A string describing the devices in the test run, or null if it doesn't match filter.
123      */
getDeviceSummary(Entity testRun, String selectedDevice)124     private static String getDeviceSummary(Entity testRun, String selectedDevice) {
125         DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
126         List<String> buildInfos = new ArrayList<>();
127         Query deviceQuery =
128                 new Query(DeviceInfoEntity.KIND)
129                         .setAncestor(testRun.getKey())
130                         .addProjection(
131                                 new PropertyProjection(DeviceInfoEntity.BUILD_ID, String.class))
132                         .addProjection(
133                                 new PropertyProjection(DeviceInfoEntity.PRODUCT, String.class));
134         boolean isSelectedDevice = selectedDevice == null;
135         for (Entity device : datastore.prepare(deviceQuery).asIterable()) {
136             String product = (String) device.getProperty(DeviceInfoEntity.PRODUCT);
137             if (selectedDevice != null && product.equals(selectedDevice)) {
138                 isSelectedDevice = true;
139             }
140             String buildId = (String) device.getProperty(DeviceInfoEntity.BUILD_ID);
141             buildInfos.add(product + " (" + buildId + ")");
142         }
143         return isSelectedDevice ? StringUtils.join(buildInfos, ", ") : null;
144     }
145 
146     @Override
doGetHandler(HttpServletRequest request, HttpServletResponse response)147     public void doGetHandler(HttpServletRequest request, HttpServletResponse response)
148             throws IOException {
149         RequestDispatcher dispatcher = null;
150         DatastoreService datastore = DatastoreServiceFactory.getDatastoreService();
151         String testName = request.getParameter("testName");
152         String profilingPointName = request.getParameter("profilingPoint");
153         String selectedDevice = request.getParameter("device");
154         Long endTime = null;
155         if (request.getParameter("endTime") != null) {
156             String time = request.getParameter("endTime");
157             try {
158                 endTime = Long.parseLong(time);
159             } catch (NumberFormatException e) {
160             }
161         }
162         if (endTime == null) {
163             endTime = System.currentTimeMillis() * MILLI_TO_MICRO;
164         }
165         Long startTime = endTime - TimeUnit.DAYS.toMicros(1);
166 
167         // Set of device names
168         List<String> devices = DatastoreHelper.getAllProducts(testName);
169         if (!devices.contains(selectedDevice))
170             selectedDevice = null;
171 
172         Map<String, Graph> graphMap = new HashMap<>();
173 
174         // Create a query for test runs matching the time window filter
175         Key parentKey = KeyFactory.createKey(TestEntity.KIND, testName);
176         Filter timeFilter = FilterUtil.getTimeFilter(parentKey, startTime, endTime);
177         Query testRunQuery = new Query(TestRunEntity.KIND)
178                                      .setAncestor(parentKey)
179                                      .setFilter(timeFilter)
180                                      .setKeysOnly();
181 
182         // Process the test runs in the query
183         for (Entity testRun : datastore.prepare(testRunQuery).asIterable()) {
184             String buildInfoString = getDeviceSummary(testRun, selectedDevice);
185             if (buildInfoString == null) {
186                 continue;
187             }
188 
189             try {
190                 Entity profilingRun = datastore.get(KeyFactory.createKey(
191                         testRun.getKey(), ProfilingPointRunEntity.KIND, profilingPointName));
192                 processProfilingRun(profilingRun, buildInfoString, graphMap);
193             } catch (EntityNotFoundException e) {
194                 // Profiling point not collected during this test run
195                 continue;
196             }
197         }
198         // Get the names of the graphs to render
199         String[] names = graphMap.keySet().toArray(new String[graphMap.size()]);
200         Arrays.sort(names);
201 
202         List<Graph> graphList = new ArrayList<>();
203         boolean hasHistogram = false;
204         for (String name : names) {
205             Graph g = graphMap.get(name);
206             if (g.size() > 0) {
207                 graphList.add(g);
208                 if (g instanceof Histogram)
209                     hasHistogram = true;
210             }
211         }
212 
213         String filterVal = request.getParameter("filterVal");
214         try {
215             Long.parseLong(filterVal);
216         } catch (NumberFormatException e) {
217             filterVal = Long.toString(DEFAULT_FILTER_OPTION);
218         }
219         request.setAttribute("testName", request.getParameter("testName"));
220         request.setAttribute("filterVal", filterVal);
221         request.setAttribute("endTime", new Gson().toJson(endTime));
222         request.setAttribute("devices", devices);
223         request.setAttribute("selectedDevice", selectedDevice);
224         request.setAttribute("showFilterDropdown", hasHistogram);
225         if (graphList.size() == 0)
226             request.setAttribute("error", PROFILING_DATA_ALERT);
227 
228         Gson gson = new GsonBuilder()
229                             .registerTypeHierarchyAdapter(Graph.class, new GraphSerializer())
230                             .create();
231         request.setAttribute("graphs", gson.toJson(graphList));
232 
233         request.setAttribute("profilingPointName", profilingPointName);
234         dispatcher = request.getRequestDispatcher(GRAPH_JSP);
235         try {
236             dispatcher.forward(request, response);
237         } catch (ServletException e) {
238             logger.log(Level.SEVERE, "Servlet Excpetion caught : ", e);
239         }
240     }
241 }
242