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

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

Issue 1219023006: move performance measurement to benchmark/integration (Closed) Base URL: git@github.com:dart-lang/sdk.git@master
Patch Set: merge Created 5 years, 5 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
(Empty)
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
3 // BSD-style license that can be found in the LICENSE file.
4
5 library input.transformer;
6
7 import 'dart:async';
8 import 'dart:convert';
9 import 'dart:io';
10
11 import 'package:analysis_server/src/constants.dart';
12 import 'package:analysis_server/src/protocol.dart';
13 import 'package:logging/logging.dart';
14 import 'package:path/path.dart' as path;
15
16 import 'instrumentation_input_converter.dart';
17 import 'log_file_input_converter.dart';
18 import 'operation.dart';
19
20 /**
21 * Common input converter superclass for sharing implementation.
22 */
23 abstract class CommonInputConverter extends Converter<String, Operation> {
24 static final ERROR_PREFIX = 'Server responded with an error: ';
25 final Logger logger = new Logger('InstrumentationInputConverter');
26 final Set<String> eventsSeen = new Set<String>();
27
28 /**
29 * A mapping from request/response id to request json
30 * for those requests for which a response has not been processed.
31 */
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 = {};
47
48 /**
49 * A mapping of current overlay content
50 * parallel to what is in the analysis server
51 * so that we can update the file system.
52 */
53 final Map<String, String> overlays = {};
54
55 /**
56 * The prefix used to determine if a request parameter is a file path.
57 */
58 final String rootPrefix = path.rootPrefix(path.current);
59
60 /**
61 * A mapping of source path prefixes
62 * from location where instrumentation or log file was generated
63 * to the target location of the source using during performance measurement.
64 */
65 final Map<String, String> srcPathMap;
66
67 /**
68 * The root directory for all source being modified
69 * during performance measurement.
70 */
71 final String tmpSrcDirPath;
72
73 /**
74 * The diagnostic port for Analysis Server or `null` if none.
75 */
76 final int diagnosticPort;
77
78 CommonInputConverter(this.tmpSrcDirPath, this.srcPathMap,
79 {this.diagnosticPort});
80
81 /**
82 * Return an operation for the notification or `null` if none.
83 */
84 Operation convertNotification(Map<String, dynamic> json) {
85 String event = json['event'];
86 if (event == SERVER_STATUS) {
87 // {"event":"server.status","params":{"analysis":{"isAnalyzing":false}}}
88 Map<String, dynamic> params = json['params'];
89 if (params != null) {
90 Map<String, dynamic> analysis = params['analysis'];
91 if (analysis != null && analysis['isAnalyzing'] == false) {
92 return new WaitForAnalysisCompleteOperation();
93 }
94 }
95 }
96 if (event == SERVER_CONNECTED) {
97 // {"event":"server.connected","params":{"version":"1.7.0"}}
98 return new StartServerOperation(diagnosticPort: diagnosticPort);
99 }
100 if (eventsSeen.add(event)) {
101 logger.log(Level.INFO, 'Ignored notification: $event\n $json');
102 }
103 return null;
104 }
105
106 /**
107 * Return an operation for the request or `null` if none.
108 */
109 Operation convertRequest(Map<String, dynamic> origJson) {
110 Map<String, dynamic> json = translateSrcPaths(origJson);
111 requestMap[json['id']] = json;
112 String method = json['method'];
113 // Sanity check operations that modify source
114 // to ensure that the operation is on source in temp space
115 if (method == ANALYSIS_UPDATE_CONTENT) {
116 // Track overlays in parallel with the analysis server
117 // so that when an overlay is removed, the file can be updated on disk
118 Request request = new Request.fromJson(json);
119 var params = new AnalysisUpdateContentParams.fromRequest(request);
120 params.files.forEach((String filePath, change) {
121 if (change is AddContentOverlay) {
122 String content = change.content;
123 if (content == null) {
124 throw 'expected new overlay content\n$json';
125 }
126 overlays[filePath] = content;
127 } else if (change is ChangeContentOverlay) {
128 String content = overlays[filePath];
129 if (content == null) {
130 throw 'expected cached overlay content\n$json';
131 }
132 overlays[filePath] = SourceEdit.applySequence(content, change.edits);
133 } else if (change is RemoveContentOverlay) {
134 String content = overlays.remove(filePath);
135 if (content == null) {
136 throw 'expected cached overlay content\n$json';
137 }
138 if (!path.isWithin(tmpSrcDirPath, filePath)) {
139 throw 'found path referencing source outside temp space\n$filePath\n $json';
140 }
141 new File(filePath).writeAsStringSync(content);
142 } else {
143 throw 'unknown overlay change $change\n$json';
144 }
145 });
146 return new RequestOperation(this, json);
147 }
148 // Track performance for completion notifications
149 if (method == COMPLETION_GET_SUGGESTIONS) {
150 return new CompletionRequestOperation(this, json);
151 }
152 // TODO(danrubel) replace this with code
153 // that just forwards the translated request
154 if (method == ANALYSIS_GET_HOVER ||
155 method == ANALYSIS_SET_ANALYSIS_ROOTS ||
156 method == ANALYSIS_SET_PRIORITY_FILES ||
157 method == ANALYSIS_SET_SUBSCRIPTIONS ||
158 method == ANALYSIS_UPDATE_OPTIONS ||
159 method == EDIT_GET_ASSISTS ||
160 method == EDIT_GET_AVAILABLE_REFACTORINGS ||
161 method == EDIT_GET_FIXES ||
162 method == EDIT_GET_REFACTORING ||
163 method == EDIT_SORT_MEMBERS ||
164 method == EXECUTION_CREATE_CONTEXT ||
165 method == EXECUTION_DELETE_CONTEXT ||
166 method == EXECUTION_MAP_URI ||
167 method == EXECUTION_SET_SUBSCRIPTIONS ||
168 method == SEARCH_FIND_ELEMENT_REFERENCES ||
169 method == SEARCH_FIND_MEMBER_DECLARATIONS ||
170 method == SERVER_GET_VERSION ||
171 method == SERVER_SET_SUBSCRIPTIONS) {
172 return new RequestOperation(this, json);
173 }
174 throw 'unknown request: $method\n $json';
175 }
176
177 /**
178 * Return an operation for the recorded/expected response.
179 */
180 Operation convertResponse(Map<String, dynamic> json) {
181 return new ResponseOperation(
182 this, requestMap.remove(json['id']), translateSrcPaths(json));
183 }
184
185 /**
186 * Process an error response from the server by either
187 * completing the associated completer in the [responseCompleters]
188 * or stashing it in [responseMap] if no completer exists.
189 */
190 void processErrorResponse(String id, exception) {
191 var result = exception;
192 if (exception is UnimplementedError) {
193 if (exception.message.startsWith(ERROR_PREFIX)) {
194 result = JSON.decode(exception.message.substring(ERROR_PREFIX.length));
195 }
196 }
197 processResponseResult(id, result);
198 }
199
200 /**
201 * Process the expected response by completing the given completer
202 * with the result if it has alredy been received,
203 * or caching the completer to be completed when the server
204 * returns the associated result.
205 * Return a future that completes when the response is received
206 * or `null` if the response has already been received
207 * and the completer completed.
208 */
209 Future processExpectedResponse(String id, Completer completer) {
210 if (responseMap.containsKey(id)) {
211 logger.log(Level.INFO, 'processing cached response $id');
212 completer.complete(responseMap.remove(id));
213 return null;
214 } else {
215 logger.log(Level.INFO, 'waiting for response $id');
216 responseCompleters[id] = completer;
217 return completer.future;
218 }
219 }
220
221 /**
222 * Process a success response result from the server by either
223 * completing the associated completer in the [responseCompleters]
224 * or stashing it in [responseMap] if no completer exists.
225 * The response result may be `null`.
226 */
227 void processResponseResult(String id, result) {
228 Completer completer = responseCompleters[id];
229 if (completer != null) {
230 logger.log(Level.INFO, 'processing response $id');
231 completer.complete(result);
232 } else {
233 logger.log(Level.INFO, 'caching response $id');
234 responseMap[id] = result;
235 }
236 }
237
238 /**
239 * Recursively translate source paths in the specified JSON to reference
240 * the temporary source used during performance measurement rather than
241 * the original source when the instrumentation or log file was generated.
242 */
243 translateSrcPaths(json) {
244 if (json is String) {
245 String result = json;
246 srcPathMap.forEach((String oldPrefix, String newPrefix) {
247 if (json.startsWith(oldPrefix)) {
248 result = '$newPrefix${json.substring(oldPrefix.length)}';
249 }
250 });
251 return result;
252 }
253 if (json is List) {
254 List result = [];
255 for (int i = 0; i < json.length; ++i) {
256 result.add(translateSrcPaths(json[i]));
257 }
258 return result;
259 }
260 if (json is Map) {
261 Map<String, dynamic> result = new Map<String, dynamic>();
262 json.forEach((String origKey, value) {
263 result[translateSrcPaths(origKey)] = translateSrcPaths(value);
264 });
265 return result;
266 }
267 return json;
268 }
269 }
270
271 /**
272 * [InputConverter] converts an input stream
273 * into a series of operations to be sent to the analysis server.
274 * The input stream can be either an instrumenation or log file.
275 */
276 class InputConverter extends Converter<String, Operation> {
277 final Logger logger = new Logger('InputConverter');
278
279 /**
280 * A mapping of source path prefixes
281 * from location where instrumentation or log file was generated
282 * to the target location of the source using during performance measurement.
283 */
284 final Map<String, String> srcPathMap;
285
286 /**
287 * The root directory for all source being modified
288 * during performance measurement.
289 */
290 final String tmpSrcDirPath;
291
292 /**
293 * The diagnostic port for Analysis Server or `null` if none.
294 */
295 final int diagnosticPort;
296
297 /**
298 * The number of lines read before the underlying converter was determined
299 * or the end of file was reached.
300 */
301 int headerLineCount = 0;
302
303 /**
304 * The underlying converter used to translate lines into operations
305 * or `null` if it has not yet been determined.
306 */
307 Converter<String, Operation> converter;
308
309 /**
310 * [active] is `true` if converting lines to operations
311 * or `false` if an exception has occurred.
312 */
313 bool active = true;
314
315 InputConverter(this.tmpSrcDirPath, this.srcPathMap, {this.diagnosticPort});
316
317 @override
318 Operation convert(String line) {
319 if (!active) {
320 return null;
321 }
322 if (converter != null) {
323 try {
324 return converter.convert(line);
325 } catch (e) {
326 active = false;
327 rethrow;
328 }
329 }
330 if (headerLineCount == 20) {
331 throw 'Failed to determine input file format';
332 }
333 if (InstrumentationInputConverter.isFormat(line)) {
334 converter = new InstrumentationInputConverter(tmpSrcDirPath, srcPathMap,
335 diagnosticPort: diagnosticPort);
336 } else if (LogFileInputConverter.isFormat(line)) {
337 converter = new LogFileInputConverter(tmpSrcDirPath, srcPathMap,
338 diagnosticPort: diagnosticPort);
339 }
340 if (converter != null) {
341 return converter.convert(line);
342 }
343 logger.log(Level.INFO, 'skipped input line: $line');
344 return null;
345 }
346
347 @override
348 _InputSink startChunkedConversion(outSink) {
349 return new _InputSink(this, outSink);
350 }
351 }
352
353 class _InputSink extends ChunkedConversionSink<String> {
354 final Converter<String, Operation> converter;
355 final outSink;
356
357 _InputSink(this.converter, this.outSink);
358
359 @override
360 void add(String line) {
361 Operation op = converter.convert(line);
362 if (op != null) {
363 outSink.add(op);
364 }
365 }
366
367 @override
368 void close() {
369 outSink.close();
370 }
371 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698