Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(176)

Side by Side Diff: pkg/analysis_server/test/performance/input_converter.dart

Issue 1202843010: performance measurement: generate report (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: merge Created 5 years, 6 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library input.transformer; 5 library input.transformer;
6 6
7 import 'dart:async';
7 import 'dart:convert'; 8 import 'dart:convert';
8 import 'dart:io'; 9 import 'dart:io';
9 10
10 import 'package:analysis_server/src/constants.dart'; 11 import 'package:analysis_server/src/constants.dart';
11 import 'package:analysis_server/src/protocol.dart'; 12 import 'package:analysis_server/src/protocol.dart';
12 import 'package:analyzer/src/generated/java_engine.dart';
13 import 'package:logging/logging.dart'; 13 import 'package:logging/logging.dart';
14 import 'package:path/path.dart' as path; 14 import 'package:path/path.dart' as path;
15 15
16 import 'instrumentation_input_converter.dart'; 16 import 'instrumentation_input_converter.dart';
17 import 'log_file_input_converter.dart'; 17 import 'log_file_input_converter.dart';
18 import 'operation.dart'; 18 import 'operation.dart';
19 19
20 /** 20 /**
21 * Common input converter superclass for sharing implementation. 21 * Common input converter superclass for sharing implementation.
22 */ 22 */
23 abstract class CommonInputConverter extends Converter<String, Operation> { 23 abstract class CommonInputConverter extends Converter<String, Operation> {
24 static final ERROR_PREFIX = 'Server responded with an error: '; 24 static final ERROR_PREFIX = 'Server responded with an error: ';
25 final Logger logger = new Logger('InstrumentationInputConverter'); 25 final Logger logger = new Logger('InstrumentationInputConverter');
26 final Set<String> eventsSeen = new Set<String>(); 26 final Set<String> eventsSeen = new Set<String>();
27 27
28 /** 28 /**
29 * A mapping from request/response id to expected error message. 29 * A mapping from request/response id to request json
30 * for those requests for which a response has not been processed.
30 */ 31 */
31 final Map<String, dynamic> expectedErrors = new Map<String, dynamic>(); 32 final Map<String, dynamic> requestMap = {};
33
34 /**
35 * A mapping from request/response id to a completer
36 * for those requests for which a response has not been processed.
37 * The completer is called with the actual json response
38 * when it becomes available.
39 */
40 final Map<String, Completer> responseCompleters = {};
41
42 /**
43 * A mapping from request/response id to the actual response result
44 * for those responses that have not been processed.
45 */
46 final Map<String, dynamic> responseMap = {};
32 47
33 /** 48 /**
34 * A mapping of current overlay content 49 * A mapping of current overlay content
35 * parallel to what is in the analysis server 50 * parallel to what is in the analysis server
36 * so that we can update the file system. 51 * so that we can update the file system.
37 */ 52 */
38 final Map<String, String> overlays = new Map<String, String>(); 53 final Map<String, String> overlays = {};
39 54
40 /** 55 /**
41 * The prefix used to determine if a request parameter is a file path. 56 * The prefix used to determine if a request parameter is a file path.
42 */ 57 */
43 final String rootPrefix = path.rootPrefix(path.current); 58 final String rootPrefix = path.rootPrefix(path.current);
44 59
45 /** 60 /**
46 * A mapping of source path prefixes 61 * A mapping of source path prefixes
47 * from location where instrumentation or log file was generated 62 * from location where instrumentation or log file was generated
48 * to the target location of the source using during performance measurement. 63 * to the target location of the source using during performance measurement.
(...skipping 31 matching lines...) Expand 10 before | Expand all | Expand 10 after
80 logger.log(Level.INFO, 'Ignored notification: $event\n $json'); 95 logger.log(Level.INFO, 'Ignored notification: $event\n $json');
81 } 96 }
82 return null; 97 return null;
83 } 98 }
84 99
85 /** 100 /**
86 * Return an operation for the request or `null` if none. 101 * Return an operation for the request or `null` if none.
87 */ 102 */
88 Operation convertRequest(Map<String, dynamic> origJson) { 103 Operation convertRequest(Map<String, dynamic> origJson) {
89 Map<String, dynamic> json = translateSrcPaths(origJson); 104 Map<String, dynamic> json = translateSrcPaths(origJson);
105 requestMap[json['id']] = json;
90 String method = json['method']; 106 String method = json['method'];
91 // Sanity check operations that modify source 107 // Sanity check operations that modify source
92 // to ensure that the operation is on source in temp space 108 // to ensure that the operation is on source in temp space
93 if (method == ANALYSIS_UPDATE_CONTENT) { 109 if (method == ANALYSIS_UPDATE_CONTENT) {
94 try {
95 validateSrcPaths(json);
96 } catch (e, s) {
97 throw new AnalysisException('invalid src path in update request\n$json',
98 new CaughtException(e, s));
99 }
100 // Track overlays in parallel with the analysis server 110 // Track overlays in parallel with the analysis server
101 // so that when an overlay is removed, the file can be updated on disk 111 // so that when an overlay is removed, the file can be updated on disk
102 Request request = new Request.fromJson(json); 112 Request request = new Request.fromJson(json);
103 var params = new AnalysisUpdateContentParams.fromRequest(request); 113 var params = new AnalysisUpdateContentParams.fromRequest(request);
104 params.files.forEach((String path, change) { 114 params.files.forEach((String filePath, change) {
105 if (change is AddContentOverlay) { 115 if (change is AddContentOverlay) {
106 String content = change.content; 116 String content = change.content;
107 if (content == null) { 117 if (content == null) {
108 throw 'expected new overlay content\n$json'; 118 throw 'expected new overlay content\n$json';
109 } 119 }
110 overlays[path] = content; 120 overlays[filePath] = content;
111 } else if (change is ChangeContentOverlay) { 121 } else if (change is ChangeContentOverlay) {
112 String content = overlays[path]; 122 String content = overlays[filePath];
113 if (content == null) { 123 if (content == null) {
114 throw 'expected cached overlay content\n$json'; 124 throw 'expected cached overlay content\n$json';
115 } 125 }
116 overlays[path] = SourceEdit.applySequence(content, change.edits); 126 overlays[filePath] = SourceEdit.applySequence(content, change.edits);
117 } else if (change is RemoveContentOverlay) { 127 } else if (change is RemoveContentOverlay) {
118 String content = overlays.remove(path); 128 String content = overlays.remove(filePath);
119 if (content == null) { 129 if (content == null) {
120 throw 'expected cached overlay content\n$json'; 130 throw 'expected cached overlay content\n$json';
121 } 131 }
122 validateSrcPaths(path); 132 if (!path.isWithin(tmpSrcDirPath, filePath)) {
123 new File(path).writeAsStringSync(content); 133 throw 'found path referencing source outside temp space\n$filePath\n $json';
134 }
135 new File(filePath).writeAsStringSync(content);
124 } else { 136 } else {
125 throw 'unknown overlay change $change\n$json'; 137 throw 'unknown overlay change $change\n$json';
126 } 138 }
127 }); 139 });
128 return new RequestOperation(this, json); 140 return new RequestOperation(this, json);
129 } 141 }
130 // TODO(danrubel) replace this with code 142 // Track performance for completion notifications
143 if (method == COMPLETION_GET_SUGGESTIONS) {
144 return new CompletionRequestOperation(this, json);
145 }
146 // TODO(danrubel) replace this with code
131 // that just forwards the translated request 147 // that just forwards the translated request
132 if (method == ANALYSIS_GET_HOVER || 148 if (method == ANALYSIS_GET_HOVER ||
133 method == ANALYSIS_SET_ANALYSIS_ROOTS || 149 method == ANALYSIS_SET_ANALYSIS_ROOTS ||
134 method == ANALYSIS_SET_PRIORITY_FILES || 150 method == ANALYSIS_SET_PRIORITY_FILES ||
135 method == ANALYSIS_SET_SUBSCRIPTIONS || 151 method == ANALYSIS_SET_SUBSCRIPTIONS ||
136 method == ANALYSIS_UPDATE_OPTIONS || 152 method == ANALYSIS_UPDATE_OPTIONS ||
137 method == COMPLETION_GET_SUGGESTIONS ||
138 method == EDIT_GET_ASSISTS || 153 method == EDIT_GET_ASSISTS ||
139 method == EDIT_GET_AVAILABLE_REFACTORINGS || 154 method == EDIT_GET_AVAILABLE_REFACTORINGS ||
140 method == EDIT_GET_FIXES || 155 method == EDIT_GET_FIXES ||
141 method == EDIT_GET_REFACTORING || 156 method == EDIT_GET_REFACTORING ||
142 method == EDIT_SORT_MEMBERS || 157 method == EDIT_SORT_MEMBERS ||
143 method == EXECUTION_CREATE_CONTEXT || 158 method == EXECUTION_CREATE_CONTEXT ||
144 method == EXECUTION_DELETE_CONTEXT || 159 method == EXECUTION_DELETE_CONTEXT ||
145 method == EXECUTION_MAP_URI || 160 method == EXECUTION_MAP_URI ||
146 method == EXECUTION_SET_SUBSCRIPTIONS || 161 method == EXECUTION_SET_SUBSCRIPTIONS ||
147 method == SEARCH_FIND_ELEMENT_REFERENCES || 162 method == SEARCH_FIND_ELEMENT_REFERENCES ||
163 method == SEARCH_FIND_MEMBER_DECLARATIONS ||
148 method == SERVER_GET_VERSION || 164 method == SERVER_GET_VERSION ||
149 method == SERVER_SET_SUBSCRIPTIONS) { 165 method == SERVER_SET_SUBSCRIPTIONS) {
150 return new RequestOperation(this, json); 166 return new RequestOperation(this, json);
151 } 167 }
152 throw 'unknown request: $method\n $json'; 168 throw 'unknown request: $method\n $json';
153 } 169 }
154 170
155 /** 171 /**
156 * Determine if the given request is expected to fail 172 * Return an operation for the recorded/expected response.
157 * and log an exception if not.
158 */ 173 */
159 void recordErrorResponse(Map<String, dynamic> jsonRequest, exception) { 174 Operation convertResponse(Map<String, dynamic> json) {
160 var actualErr; 175 return new ResponseOperation(
161 if (exception is UnimplementedError) { 176 this, requestMap.remove(json['id']), translateSrcPaths(json));
162 if (exception.message.startsWith(ERROR_PREFIX)) {
163 Map<String, dynamic> jsonResponse =
164 JSON.decode(exception.message.substring(ERROR_PREFIX.length));
165 actualErr = jsonResponse['error'];
166 }
167 }
168 String id = jsonRequest['id'];
169 if (id != null && actualErr != null) {
170 var expectedErr = expectedErrors[id];
171 if (expectedErr != null && actualErr == expectedErr) {
172 return;
173 }
174 // if (jsonRequest['method'] == EDIT_SORT_MEMBERS) {
175 // var params = jsonRequest['params'];
176 // if (params is Map) {
177 // var filePath = params['file'];
178 // if (filePath is String) {
179 // var content = overlays[filePath];
180 // if (content is String) {
181 // logger.log(Level.WARNING, 'sort failed: $filePath\n$content');
182 // }
183 // }
184 // }
185 // }
186 }
187 logger.log(
188 Level.SEVERE, 'Send request failed for $id\n$exception\n$jsonRequest');
189 } 177 }
190 178
191 /** 179 /**
192 * Examine recorded responses and record any expected errors. 180 * Process an error response from the server by either
181 * completing the associated completer in the [responseCompleters]
182 * or stashing it in [responseMap] if no completer exists.
193 */ 183 */
194 void recordResponse(Map<String, dynamic> json) { 184 void processErrorResponse(String id, exception) {
195 var error = json['error']; 185 var result = exception;
196 if (error != null) { 186 if (exception is UnimplementedError) {
197 String id = json['id']; 187 if (exception.message.startsWith(ERROR_PREFIX)) {
198 print('expected error for $id is $error'); 188 result = JSON.decode(exception.message.substring(ERROR_PREFIX.length));
189 }
190 }
191 processResponseResult(id, result);
192 }
193
194 /**
195 * Process the expected response by completing the given completer
196 * with the result if it has alredy been received,
197 * or caching the completer to be completed when the server
198 * returns the associated result.
199 * Return a future that completes when the response is received
200 * or `null` if the response has already been received
201 * and the completer completed.
202 */
203 Future processExpectedResponse(String id, Completer completer) {
204 if (responseMap.containsKey(id)) {
205 logger.log(Level.INFO, 'processing cached response $id');
206 completer.complete(responseMap.remove(id));
207 return null;
208 } else {
209 logger.log(Level.INFO, 'waiting for response $id');
210 responseCompleters[id] = completer;
211 return completer.future;
199 } 212 }
200 } 213 }
201 214
215 /**
216 * Process a success response result from the server by either
217 * completing the associated completer in the [responseCompleters]
218 * or stashing it in [responseMap] if no completer exists.
219 * The response result may be `null`.
220 */
221 void processResponseResult(String id, result) {
222 Completer completer = responseCompleters[id];
223 if (completer != null) {
224 logger.log(Level.INFO, 'processing response $id');
225 completer.complete(result);
226 } else {
227 logger.log(Level.INFO, 'caching response $id');
228 responseMap[id] = result;
229 }
230 }
231
202 /** 232 /**
203 * Recursively translate source paths in the specified JSON to reference 233 * Recursively translate source paths in the specified JSON to reference
204 * the temporary source used during performance measurement rather than 234 * the temporary source used during performance measurement rather than
205 * the original source when the instrumentation or log file was generated. 235 * the original source when the instrumentation or log file was generated.
206 */ 236 */
207 translateSrcPaths(json) { 237 translateSrcPaths(json) {
208 if (json is String) { 238 if (json is String) {
209 String result = json; 239 String result = json;
210 srcPathMap.forEach((String oldPrefix, String newPrefix) { 240 srcPathMap.forEach((String oldPrefix, String newPrefix) {
211 if (json.startsWith(oldPrefix)) { 241 if (json.startsWith(oldPrefix)) {
(...skipping 11 matching lines...) Expand all
223 } 253 }
224 if (json is Map) { 254 if (json is Map) {
225 Map<String, dynamic> result = new Map<String, dynamic>(); 255 Map<String, dynamic> result = new Map<String, dynamic>();
226 json.forEach((String origKey, value) { 256 json.forEach((String origKey, value) {
227 result[translateSrcPaths(origKey)] = translateSrcPaths(value); 257 result[translateSrcPaths(origKey)] = translateSrcPaths(value);
228 }); 258 });
229 return result; 259 return result;
230 } 260 }
231 return json; 261 return json;
232 } 262 }
233
234 /**
235 * Recursively verify that the source paths in the specified JSON
236 * only reference the temporary source used during performance measurement.
237 */
238 void validateSrcPaths(json) {
239 if (json is String) {
240 if (json != null &&
241 path.isWithin(rootPrefix, json) &&
242 !path.isWithin(tmpSrcDirPath, json)) {
243 throw 'found path referencing source outside temp space\n$json';
244 }
245 } else if (json is List) {
246 for (int i = json.length - 1; i >= 0; --i) {
247 validateSrcPaths(json[i]);
248 }
249 } else if (json is Map) {
250 json.forEach((String key, value) {
251 validateSrcPaths(key);
252 validateSrcPaths(value);
253 });
254 }
255 }
256 } 263 }
257 264
258 /** 265 /**
259 * [InputConverter] converts an input stream 266 * [InputConverter] converts an input stream
260 * into a series of operations to be sent to the analysis server. 267 * into a series of operations to be sent to the analysis server.
261 * The input stream can be either an instrumenation or log file. 268 * The input stream can be either an instrumenation or log file.
262 */ 269 */
263 class InputConverter extends Converter<String, Operation> { 270 class InputConverter extends Converter<String, Operation> {
264 final Logger logger = new Logger('InputConverter'); 271 final Logger logger = new Logger('InputConverter');
265 272
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
342 if (op != null) { 349 if (op != null) {
343 outSink.add(op); 350 outSink.add(op);
344 } 351 }
345 } 352 }
346 353
347 @override 354 @override
348 void close() { 355 void close() {
349 outSink.close(); 356 outSink.close();
350 } 357 }
351 } 358 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698