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

Side by Side Diff: pkg/fletchc/lib/program_info.dart

Issue 1659163007: Rename fletch -> dartino (Closed) Base URL: https://github.com/dartino/sdk.git@master
Patch Set: address comments Created 4 years, 10 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
« no previous file with comments | « pkg/fletchc/lib/input_handler.dart ('k') | pkg/fletchc/lib/src/bytecode_assembler.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright (c) 2015, the Dartino 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.md file.
4
5 library fletchc.program_info;
6
7 import 'dart:async' show
8 Future,
9 Stream,
10 StreamSink;
11
12 import 'dart:io' as io;
13
14 import 'dart:io' show
15 BytesBuilder;
16
17 import 'dart:convert' show
18 JSON,
19 LineSplitter,
20 UTF8;
21
22 import 'dart:typed_data' show
23 Int32List,
24 Uint8List,
25 ByteData,
26 Endianness;
27
28 import 'package:persistent/persistent.dart' show
29 Pair;
30
31 import 'vm_commands.dart' show
32 WriteSnapshotResult;
33
34 import 'fletch_system.dart' show
35 FletchClass,
36 FletchFunction,
37 FletchSystem;
38
39 import 'src/fletch_selector.dart' show
40 FletchSelector;
41
42 enum Configuration {
43 Offset64BitsDouble,
44 Offset64BitsFloat,
45 Offset32BitsDouble,
46 Offset32BitsFloat,
47 }
48
49 class ProgramInfo {
50 final List<String> _strings;
51
52 // Maps selector-id -> string-id
53 final List<int> _selectorNames;
54
55 // Maps configuration -> offset -> string-id
56 final Map<Configuration, Map<int, int>> _classNames;
57
58 // Maps configuration -> offset -> string-id
59 final Map<Configuration, Map<int, int>> _functionNames;
60
61 // Snapshot hashtag for validation.
62 final hashtag;
63
64 ProgramInfo(this._strings, this._selectorNames,
65 this._classNames, this._functionNames,
66 this.hashtag);
67
68 String classNameOfFunction(Configuration conf, int functionOffset) {
69 return _getString(_classNames[conf][functionOffset]);
70 }
71
72 String functionName(Configuration conf, int functionOffset) {
73 return _getString(_functionNames[conf][functionOffset]);
74 }
75
76 String className(Configuration conf, int classOffset) {
77 return _getString(_classNames[conf][classOffset]);
78 }
79
80 String selectorName(FletchSelector selector) {
81 return _getString(_selectorNames[selector.id]);
82 }
83
84 String _getString(int stringId) {
85 String name = null;
86 if (stringId != null && stringId != -1) {
87 name = _strings[stringId];
88 if (name == '') name = null;
89 }
90 return name;
91 }
92 }
93
94 abstract class ProgramInfoJson {
95 static String encode(ProgramInfo info, {List<Configuration> enabledConfigs}) {
96 if (enabledConfigs == null) {
97 enabledConfigs = Configuration.values;
98 }
99
100 Map<String, List<int>> buildTables(
101 Map<Configuration, Map<int, int>> offset2stringIds) {
102
103 List<int> convertMap(Configuration conf) {
104 if (enabledConfigs.contains(conf)) {
105 var map = offset2stringIds[conf];
106 List<int> list = new List<int>(map.length * 2);
107 int offset = 0;
108 map.forEach((int a, int b) {
109 list[offset++] = a;
110 list[offset++] = b;
111 });
112 return list;
113 } else {
114 return const [];
115 }
116 }
117
118 return {
119 'b64double': convertMap(Configuration.Offset64BitsDouble),
120 'b64float': convertMap(Configuration.Offset64BitsFloat),
121 'b32double': convertMap(Configuration.Offset32BitsDouble),
122 'b32float': convertMap(Configuration.Offset32BitsFloat),
123 };
124 }
125
126 return JSON.encode({
127 'strings': info._strings,
128 'selectors': info._selectorNames,
129 'class-names': buildTables(info._classNames),
130 'function-names' : buildTables(info._functionNames),
131 'hashtag': info.hashtag,
132 });
133 }
134
135 static ProgramInfo decode(String string) {
136 var json = JSON.decode(string);
137
138 Map<int, int> convertList(List<int> list) {
139 Map<int, int> map = {};
140 for (int i = 0; i < list.length; i += 2) {
141 map[list[i]] = list[i + 1];
142 }
143 return map;
144 }
145
146 var classNames = {
147 Configuration.Offset64BitsDouble :
148 convertList(json['class-names']['b64double']),
149 Configuration.Offset64BitsFloat:
150 convertList(json['class-names']['b64float']),
151 Configuration.Offset32BitsDouble :
152 convertList(json['class-names']['b32double']),
153 Configuration.Offset32BitsFloat :
154 convertList(json['class-names']['b32float']),
155 };
156
157 var functionNames = {
158 Configuration.Offset64BitsDouble :
159 convertList(json['function-names']['b64double']),
160 Configuration.Offset64BitsFloat:
161 convertList(json['function-names']['b64float']),
162 Configuration.Offset32BitsDouble :
163 convertList(json['function-names']['b32double']),
164 Configuration.Offset32BitsFloat :
165 convertList(json['function-names']['b32float']),
166 };
167
168 return new ProgramInfo(
169 json['strings'], json['selectors'],
170 classNames, functionNames,
171 json['hashtag']);
172 }
173 }
174
175 abstract class ProgramInfoBinary {
176 static const int _INVALID_INDEX = 0xffffff;
177 static final int _HEADER_LENGTH = 4 * (2 + 2 * Configuration.values.length);
178
179 static List<int> encode(ProgramInfo info,
180 {List<Configuration> enabledConfigs}) {
181 if (enabledConfigs == null) {
182 enabledConfigs = Configuration.values;
183 }
184
185 List<int> stringOffsetsInStringTable = [];
186
187 void ensureEncodableAs24Bit(int number) {
188 if (number >= ((1 << 24) - 1)) {
189 throw new Exception(
190 "The binary program information format cannot encode offsets "
191 "larger than 16 MB (24 bits) at the moment.");
192 }
193 }
194
195 List<int> buildStringTable() {
196 BytesBuilder builder = new BytesBuilder();
197 for (int i = 0; i < info._strings.length; i++) {
198 stringOffsetsInStringTable.add(builder.length);
199 String name = info._strings[i];
200 if (name != null) {
201 builder.add(UTF8.encode(name));
202 }
203 builder.addByte(0);
204 }
205 return builder.takeBytes();
206 }
207
208 List<int> buildSelectorTable(List<int> stringIds) {
209 Uint8List bytes = new Uint8List(3 * stringIds.length);
210
211 int offset = 0;
212
213 void writeByte(int byte) {
214 bytes[offset++] = byte;
215 }
216
217 void writeNumber(int number) {
218 ensureEncodableAs24Bit(number);
219
220 // 0xffffff means -1
221 if (number == -1) number = _INVALID_INDEX;
222
223 writeByte(number & 0xff);
224 writeByte((number >> 8) & 0xff);
225 writeByte((number >> 16) & 0xff);
226 }
227
228 // We write tuples [program-offset, string-table-offset].
229 // So the user can use binary search using a program offset to find the
230 // string offset.
231 for (int i = 0; i < stringIds.length; i++) {
232 int stringId = stringIds[i];
233
234 if (stringId != -1) {
235 int stringOffset = stringOffsetsInStringTable[stringId];
236 writeNumber(stringOffset);
237 } else {
238 writeNumber(-1);
239 }
240 }
241
242 assert(offset == bytes.length);
243
244 return bytes;
245 }
246
247 List<int> buildOffsetTable(Map<int, int> map) {
248 Uint8List bytes = new Uint8List(2 * 3 * map.length);
249
250 int offset = 0;
251
252 void writeByte(int byte) {
253 bytes[offset++] = byte;
254 }
255
256 void writeNumber(int number) {
257 // 0xffffff means -1
258 ensureEncodableAs24Bit(number);
259
260 if (number == -1) number = _INVALID_INDEX;
261
262 writeByte(number & 0xff);
263 writeByte((number >> 8) & 0xff);
264 writeByte((number >> 16) & 0xff);
265 }
266
267 // We write tuples [program-offset, string-table-offset].
268 // So the user can use binary search using a program offset to find the
269 // string offset.
270 List<int> offsets = map.keys.toList()..sort();
271 for (int i = 0; i < offsets.length; i++) {
272 int offset = offsets[i];
273 int stringId = map[offset];
274
275 // We only make an entry for [offset] if there is a known string.
276 if (stringId != -1) {
277 int stringOffset = stringOffsetsInStringTable[stringId];
278 writeNumber(offset);
279 writeNumber(stringOffset);
280 }
281 }
282
283 return new Uint8List.view(bytes.buffer, 0, offset);
284 }
285
286 List<List<int>> tables = [];
287 tables.add(buildStringTable());
288 tables.add(buildSelectorTable(info._selectorNames));
289 for (Configuration conf in Configuration.values) {
290 if (enabledConfigs.contains(conf)) {
291 List<int> offsetTable = buildOffsetTable(info._classNames[conf]);
292 tables.add(offsetTable);
293 } else {
294 tables.add([]);
295 }
296 }
297 for (Configuration conf in Configuration.values) {
298 if (enabledConfigs.contains(conf)) {
299 List<int> offsetTable = buildOffsetTable(info._functionNames[conf]);
300 tables.add(offsetTable);
301 } else {
302 tables.add([]);
303 }
304 }
305
306 int tableLengths = tables.map((t) => t.length).fold(0, (a, b) => a + b);
307 int length = _HEADER_LENGTH + tableLengths;
308
309 Uint8List bytes = new Uint8List(length);
310 ByteData header = new ByteData.view(bytes.buffer);
311
312 int offset = 0;
313 writeLength(List<int> data) {
314 header.setUint32(offset, data.length, Endianness.LITTLE_ENDIAN);
315 offset += 4;
316 }
317 writeTable(List<int> data) {
318 bytes.setRange(offset, offset + data.length, data);
319 offset += data.length;
320 }
321
322 tables.forEach(writeLength);
323 assert(offset == _HEADER_LENGTH);
324 tables.forEach(writeTable);
325
326 return bytes;
327 }
328
329 static ProgramInfo decode(List<int> data) {
330 Uint8List bytes = new Uint8List.fromList(data);
331 ByteData header = new ByteData.view(bytes.buffer);
332
333 int offset = 0;
334 int readLength() {
335 int length = header.getUint32(offset, Endianness.LITTLE_ENDIAN);
336 offset += 4;
337 return length;
338 }
339 List<int> readTable(int length) {
340 var view = new Uint8List.view(bytes.buffer, offset, length);
341 offset += length;
342 return view;
343 }
344
345 Map<int, int> stringOffsetToIndex = {};
346 List<String> buildStringDecodingTable(List<int> data) {
347 List<String> strings = [];
348 int start = 0;
349 while (start < data.length) {
350 stringOffsetToIndex[start] = strings.length;
351
352 int end = start;
353 while (data[end] != 0) end++;
354
355 strings.add(UTF8.decode(data.sublist(start, end)));
356 start = end + 1;
357 }
358 return strings;
359 }
360
361 List<int> decodeSelectors(List<int> data) {
362 assert(data.length % 3 == 0);
363 List<int> indices = new List(data.length ~/ 3);
364 for (int offset = 0; offset < data.length; offset += 3) {
365 int number =
366 data[offset] | (data[offset + 1] << 8) | (data[offset + 2] << 16);
367 if (number == _INVALID_INDEX) number = -1;
368 if (number != -1) number = stringOffsetToIndex[number];
369 indices[offset ~/ 3] = number;
370 }
371 return indices;
372 }
373
374 Map<int, int> decodeTable(List<int> data) {
375 assert(data.length % 6 == 0);
376 Map<int, int> offset2stringId = {};
377 for (int offset = 0; offset < data.length; offset += 6) {
378 int programOffset =
379 data[offset] |
380 (data[offset + 1] << 8) |
381 (data[offset + 2] << 16);
382 int stringOffset =
383 data[offset + 3] |
384 (data[offset + 4] << 8) |
385 (data[offset + 5] << 16);
386
387 if (programOffset != _INVALID_INDEX && stringOffset != _INVALID_INDEX) {
388 offset2stringId[programOffset] = stringOffsetToIndex[stringOffset];
389 } else {
390 offset2stringId[programOffset] = -1;
391 }
392 }
393 return offset2stringId;
394 }
395
396 int stringTableLength = readLength();
397 int selectorTableLength = readLength();
398
399 Map<Configuration, int> classTableLengths = {};
400 Configuration.values.forEach(
401 (conf) => classTableLengths[conf] = readLength());
402
403 Map<Configuration, int> functionTableLengths = {};
404 Configuration.values.forEach(
405 (conf) => functionTableLengths[conf] = readLength());
406
407 List<int> stringTable = readTable(stringTableLength);
408
409 List<String> strings = buildStringDecodingTable(stringTable);
410 List<int> selectorTable = decodeSelectors(readTable(selectorTableLength));
411
412 Map<Configuration, Map<int, int>> classNames = {};
413 Configuration.values.forEach((conf) {
414 classNames[conf] = decodeTable(readTable(classTableLengths[conf]));
415 });
416
417 Map<Configuration, Map<int, int>> functionNames = {};
418 Configuration.values.forEach((conf) {
419 functionNames[conf] = decodeTable(readTable(functionTableLengths[conf]));
420 });
421
422 assert(offset == (_HEADER_LENGTH +
423 stringTableLength +
424 selectorTableLength +
425 classTableLengths.values.fold(0, (a, b) => a + b) +
426 functionTableLengths.values.fold(0, (a, b) => a + b)));
427
428 return new ProgramInfo(
429 strings,
430 selectorTable,
431 classNames,
432 functionNames,
433 0); // hashtag for shapshot is not supported for binary format.
434 }
435 }
436
437 ProgramInfo buildProgramInfo(FletchSystem system, WriteSnapshotResult result) {
438 List<String> strings = [];
439 Map<String, int> stringIndices = {};
440 List<int> selectors = [];
441
442 int newName(String name) {
443 if (name == null) return -1;
444
445 var index = stringIndices[name];
446 if (index == null) {
447 index = strings.length;
448 strings.add(name);
449 stringIndices[name] = index;
450 }
451 return index;
452 }
453
454 void setIndex(List<int> list, int index, value) {
455 while (list.length <= index) {
456 list.add(-1);
457 }
458 list[index] = value;
459 }
460
461 system.symbolByFletchSelectorId.forEach((Pair<int, String> pair) {
462 setIndex(selectors, pair.fst, newName(pair.snd));
463 });
464
465 Map<int, FletchClass> functionId2Class = {};
466 system.classesById.forEach((Pair<int, FletchClass> pair) {
467 FletchClass klass = pair.snd;
468 klass.methodTable.forEach((Pair<int, int> pair) {
469 int functionId = pair.snd;
470 functionId2Class[functionId] = klass;
471 });
472 });
473
474 Map<Configuration, Map<int, int>> newTable() {
475 return <Configuration, Map<int, int>>{
476 Configuration.Offset64BitsDouble : <int,int>{},
477 Configuration.Offset64BitsFloat : <int,int>{},
478 Configuration.Offset32BitsDouble : <int,int>{},
479 Configuration.Offset32BitsFloat : <int,int>{},
480 };
481 }
482
483 fillTable(Map<Configuration, Map<int, int>> dst,
484 Int32List list,
485 String symbol(int id)) {
486 for (int offset = 0; offset < list.length; offset += 5) {
487 int id = list[offset + 0];
488 int stringId = newName(symbol(id));
489
490 if (stringId != -1) {
491 dst[Configuration.Offset64BitsDouble][list[offset + 1]] = stringId;
492 dst[Configuration.Offset64BitsFloat][list[offset + 2]] = stringId;
493 dst[Configuration.Offset32BitsDouble][list[offset + 3]] = stringId;
494 dst[Configuration.Offset32BitsFloat][list[offset + 4]] = stringId;
495 }
496 }
497 }
498
499 var functionNames = newTable();
500 var classNames = newTable();
501
502 fillTable(functionNames,
503 result.functionOffsetTable,
504 (id) => system.functionsById[id].name);
505 fillTable(classNames,
506 result.classOffsetTable,
507 (id) {
508 FletchClass klass = system.classesById[id];
509 if (klass == null) {
510 // Why do we get here?
511 return null;
512 }
513 return klass.name;
514 });
515 fillTable(classNames,
516 result.functionOffsetTable,
517 (id) {
518 FletchClass klass = functionId2Class[id];
519 if (klass != null) return klass.name;
520 return null;
521 });
522
523 return new ProgramInfo(strings, selectors, classNames,
524 functionNames, result.hashtag);
525 }
526
527 final RegExp _FrameRegexp =
528 new RegExp(r'^Frame +([0-9]+): Function\(([0-9]+)\)$');
529
530 final RegExp _NSMRegexp =
531 new RegExp(r'^NoSuchMethodError\(([0-9]+), ([0-9]+)\)$');
532
533 Stream<String> decodeStackFrames(Configuration conf,
534 ProgramInfo info,
535 Stream<String> input) async* {
536 await for (String line in input) {
537 Match frameMatch = _FrameRegexp.firstMatch(line);
538 Match nsmMatch = _NSMRegexp.firstMatch(line);
539 if (frameMatch != null) {
540 String frameNr = frameMatch.group(1);
541 int functionOffset = int.parse(frameMatch.group(2));
542
543 String className = info.classNameOfFunction(conf, functionOffset);
544 String functionName = info.functionName(conf, functionOffset);
545
546 if (className == null) {
547 yield ' $frameNr: $functionName\n';
548 } else {
549 yield ' $frameNr: $className.$functionName\n';
550 }
551 } else if (nsmMatch != null) {
552 int classOffset = int.parse(nsmMatch.group(1));
553 FletchSelector selector =
554 new FletchSelector(int.parse(nsmMatch.group(2)));
555 String functionName = info.selectorName(selector);
556 String className = info.className(conf, classOffset);
557
558 if (className != null && functionName != null) {
559 yield 'NoSuchMethodError: $className.$functionName\n';
560 } else if (functionName != null) {
561 yield 'NoSuchMethodError: $functionName\n';
562 } else {
563 yield 'NoSuchMethodError: <unknown method>\n';
564 }
565 } else {
566 yield '$line\n';
567 }
568 }
569 }
570
571 Future<int> decodeProgramMain(
572 List<String> arguments,
573 Stream<List<int>> input,
574 StreamSink<List<int>> output) async {
575
576 usage(message) {
577 print("Invalid arguments: $message");
578 print("Usage: ${io.Platform.script} "
579 "<32/64> <float/double> <snapshot.info.{json/bin}>");
580 }
581
582 if (arguments.length != 3) {
583 usage("Exactly 3 arguments must be supplied");
584 return 1;
585 }
586
587 String bits = arguments[0];
588 if (!['32', '64'].contains(bits)) {
589 usage("Bit width must be 32 or 64.");
590 return 1;
591 }
592
593 String floatOrDouble = arguments[1];
594 if (!['float', 'double'].contains(floatOrDouble)) {
595 usage("Floating point argument must be 'float' or 'double'.");
596 return 1;
597 }
598
599 String filename = arguments[2];
600 bool isJsonFile = filename.endsWith('.json');
601 bool isBinFile = filename.endsWith('.bin');
602 if (!isJsonFile && !isBinFile) {
603 usage("The program info file must end in '.bin' or '.json' "
604 "(was: '$filename').");
605 return 1;
606 }
607
608 io.File file = new io.File(filename);
609 if (!await file.exists()) {
610 usage("The file '$filename' does not exist.");
611 return 1;
612 }
613
614 ProgramInfo info;
615
616 if (isJsonFile) {
617 info = ProgramInfoJson.decode(await file.readAsString());
618 } else {
619 info = ProgramInfoBinary.decode(await file.readAsBytes());
620 }
621
622 Stream<String> inputLines =
623 input.transform(UTF8.decoder).transform(new LineSplitter());
624
625 Configuration conf = _getConfiguration(bits, floatOrDouble);
626 Stream<String> decodedFrames = decodeStackFrames(conf, info, inputLines);
627 await decodedFrames.transform(UTF8.encoder).pipe(output);
628
629 return 0;
630 }
631
632
633 // We are only interested in two kind of lines in the fletch.ticks file.
634 final RegExp tickRegexp =
635 new RegExp(r'^0x([0-9a-f]+),0x([0-9a-f]+),0x([0-9a-f]+)');
636 final RegExp propertyRegexp = new RegExp(r'^(\w+)=(.*$)');
637
638 // Tick contains information from a line matching tickRegexp.
639 class Tick {
640 final int pc; // The actual program counter where the tick occurred.
641 final int bcp; // The bytecode pointer relative to program heap start.
642 final int hashtag;
643 Tick(this.pc, this.bcp,this.hashtag);
644 }
645
646 // Property contains information from a line matching propertyRegexp.
647 class Property {
648 final String name;
649 final String value;
650 Property(this.name, this.value);
651 }
652
653 // FunctionInfo captures profiler information for a function.
654 class FunctionInfo {
655 int ticks = 0; // Accumulated number of ticks.
656 final String name; // Name that indentifies the function.
657
658 FunctionInfo(this.name);
659
660 int Percent(int total_ticks) => ticks * 100 ~/ total_ticks;
661
662 void Print(int total_ticks) {
663 print(" -${Percent(total_ticks).toString().padLeft(3, ' ')}% $name");
664 }
665
666 static String ComputeName(String function_name, String class_name) {
667 if (class_name == null) return function_name;
668 return "$class_name.$function_name";
669 }
670 }
671
672 Stream decode(Stream<List<int>> input) async* {
673 Stream<String> inputLines =
674 input.transform(UTF8.decoder).transform(new LineSplitter());
675 await for (String line in inputLines) {
676 Match t = tickRegexp.firstMatch(line);
677 if (t != null) {
678 int pc = int.parse(t.group(1), radix: 16);
679 int offset = 0;
680 int hashtag = 0;
681 if (t.groupCount > 1) {
682 offset = int.parse(t.group(2), radix: 16);
683 hashtag = int.parse(t.group(3), radix: 16);
684 }
685 yield new Tick(pc, offset, hashtag);
686 } else {
687 t = propertyRegexp.firstMatch(line);
688 if (t != null) yield new Property(t.group(1), t.group(2));
689 }
690 }
691 }
692
693 // Binary search for named entry start.
694 NamedEntry findEntry(List<NamedEntry> functions, Tick t) {
695 int low = 0;
696 int high = functions.length - 1;
697 while (low + 1 < high) {
698 int i = low + ((high - low) ~/ 2);
699 NamedEntry current = functions[i];
700 if (current.offset < t.bcp) {
701 low = i;
702 } else {
703 high = i;
704 }
705 }
706 return functions[low];
707 }
708
709 // NamedEntry captures a named entry caputred in the .info.json file.
710 class NamedEntry {
711 final int offset;
712 final String name;
713 NamedEntry(this.offset, this.name);
714 }
715
716 class Profile {
717 final String sample_filename;
718 final String info_filename;
719 Profile(this.sample_filename,this.info_filename);
720
721 // Tick information.
722 int total_ticks = 0;
723 int runtime_ticks = 0;
724 int interpreter_ticks = 0;
725 int discarded_ticks = 0;
726 int other_snapshot_ticks = 0;
727
728 // Memory model.
729 String model;
730
731 // All the ticks.
732 List<Tick> ticks = <Tick>[];
733
734 // The resulting histogram.
735 List<FunctionInfo> histogram;
736
737 void Print() {
738 print("# Tick based profiler result.");
739
740 for (FunctionInfo func in histogram) {
741 if (func.Percent(total_ticks) < 2) break;
742 func.Print(total_ticks);
743 }
744
745 print("# ticks in interpreter=${interpreter_ticks}");
746 if (runtime_ticks > 0) print(" runtime=${runtime_ticks}");
747 if (discarded_ticks > 0) print(" discarded=${discarded_ticks}");
748 if (other_snapshot_ticks> 0) {
749 print(" other_snapshot=${other_snapshot_ticks}");
750 }
751 }
752 }
753
754 Future<Profile> decodeTickSamples(
755 List<String> arguments,
756 Stream<List<int>> input,
757 StreamSink<List<int>> output) async {
758
759 usage(message) {
760 print("Invalid arguments: $message");
761 print("Usage: ${io.Platform.script} <fletch.ticks> <snapshot.info.json>");
762 }
763
764 if (arguments.length != 2) {
765 usage("Exactly 2 arguments must be supplied");
766 return null;
767 }
768
769 String sample_filename = arguments[0];
770 io.File sample_file = new io.File(sample_filename);
771 if (!await sample_file.exists()) {
772 usage("The file '$sample_filename' does not exist.");
773 return null;
774 }
775
776 String info_filename = arguments[1];
777 if (!info_filename.endsWith('.info.json')) {
778 usage("The program info file must end in '.info.json' "
779 "(was: '$info_filename').");
780 return null;
781 }
782
783 io.File info_file = new io.File(info_filename);
784 if (!await info_file.exists()) {
785 usage("The file '$info_filename' does not exist.");
786 return null;
787 }
788
789 ProgramInfo info = ProgramInfoJson.decode(await info_file.readAsString());
790 Profile profile = new Profile(sample_filename, info_filename);
791
792 // Process the tick sample file.
793 await for (var t in decode(sample_file.openRead())) {
794 if (t is Tick) {
795 profile.ticks.add(t);
796 } else if (t is Property) {
797 if (t.name == 'discarded') profile.discarded_ticks = int.parse(t.value);
798 if (t.name == 'model') profile.model = t.value;
799 }
800 }
801 if (profile.model == null) {
802 print("Memory model absent in sample file.");
803 return null;
804 }
805
806 // Compute the configuration key based on the memory model.
807 Configuration conf;
808 String model = profile.model;
809 if (model == 'b64double') {
810 conf = Configuration.Offset64BitsDouble;
811 } else if (model == 'b64float') {
812 conf = Configuration.Offset64BitsFloat;
813 } else if (model == 'b32double') {
814 conf = Configuration.Offset32BitsDouble;
815 } else if (model == 'b32float') {
816 conf = Configuration.Offset32BitsFloat;
817 } else {
818 print("Memory model in sample file ${model} cannot be recognized.");
819 return null;
820 }
821
822 // Compute a offset sorted list of Function entries.
823 List<NamedEntry> functions = new List<NamedEntry>();
824 Map<int,int> fnames = info._functionNames[conf];
825 fnames.forEach((key, value) {
826 functions.add(new NamedEntry(key, info._getString(value)));
827 });
828 functions.sort((a, b) => a.offset - b.offset);
829
830 // Compute a offset sorted list of Class entries.
831 List<NamedEntry> classes = new List<NamedEntry>();
832 Map<int,int> cnames = info._classNames[conf];
833 cnames.forEach((key, value) {
834 classes.add(new NamedEntry(key, info._getString(value)));
835 });
836 classes.sort((a, b) => a.offset - b.offset);
837
838 Map<String,FunctionInfo> results = <String,FunctionInfo>{};
839 for (Tick t in profile.ticks) {
840 profile.total_ticks++;
841 if (t.bcp == 0) {
842 profile.runtime_ticks++;
843 } else if (t.hashtag != info.hashtag) {
844 profile.other_snapshot_ticks++;
845 } else {
846 profile.interpreter_ticks++;
847 NamedEntry fe = findEntry(functions, t);
848 if (fe?.name != null) {
849 NamedEntry ce = findEntry(classes, t);
850 String key = FunctionInfo.ComputeName(fe.name, ce?.name);
851 FunctionInfo f =
852 results.putIfAbsent(key, () => new FunctionInfo(key));
853 f.ticks++;
854 }
855 }
856 }
857
858 // Sort the values into the histogram.
859 List<FunctionInfo> histogram =
860 new List<FunctionInfo>.from(results.values);
861 histogram.sort((a,b) { return b.ticks - a.ticks; });
862 profile.histogram = histogram;
863
864 return profile;
865 }
866
867 Configuration _getConfiguration(bits, floatOrDouble) {
868 if (bits == '64') {
869 if (floatOrDouble == 'float') return Configuration.Offset64BitsFloat;
870 else if (floatOrDouble == 'double') return Configuration.Offset64BitsDouble;
871 } else if (bits == '32') {
872 if (floatOrDouble == 'float') return Configuration.Offset32BitsFloat;
873 else if (floatOrDouble == 'double') return Configuration.Offset32BitsDouble;
874 }
875 throw 'Invalid arguments';
876 }
OLDNEW
« no previous file with comments | « pkg/fletchc/lib/input_handler.dart ('k') | pkg/fletchc/lib/src/bytecode_assembler.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698