| Index: tools/tracemerge.dart
|
| diff --git a/pkg/collection_helpers/lib/algorithms.dart b/tools/tracemerge.dart
|
| similarity index 66%
|
| copy from pkg/collection_helpers/lib/algorithms.dart
|
| copy to tools/tracemerge.dart
|
| index 057111a664625e3d4ab28a0f9421f03b340c73bb..6c7d5ddd45dcf2b9d2cca9aede54f084293ae6d5 100644
|
| --- a/pkg/collection_helpers/lib/algorithms.dart
|
| +++ b/tools/tracemerge.dart
|
| @@ -2,99 +2,10 @@
|
| // for details. All rights reserved. Use of this source code is governed by a
|
| // BSD-style license that can be found in the LICENSE file.
|
|
|
| -/**
|
| - * Operations on collections.
|
| - */
|
| -library dart.collection_helpers.algorithms;
|
| -
|
| -import "dart:math" show Random;
|
| -
|
| -/** Version of [binarySearch] optimized for comparable keys */
|
| -int _comparableBinarySearch(List<Comparable> list, Comparable key) {
|
| - int min = 0;
|
| - int max = list.length;
|
| - while (min < max) {
|
| - int mid = min + ((max - min) >> 1);
|
| - var element = list[mid];
|
| - int comp = element.compareTo(key);
|
| - if (comp == 0) return mid;
|
| - if (comp < 0) {
|
| - min = mid + 1;
|
| - } else {
|
| - max = mid;
|
| - }
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -/**
|
| - * Returns a position of the [key] in [sortedList], if it is there.
|
| - *
|
| - * If the list isn't sorted according to the [compare] function, the result
|
| - * is unpredictable.
|
| - *
|
| - * If [compare] is omitted, it defaults to calling [Comparable.compareTo] on
|
| - * the objects.
|
| - *
|
| - * Returns -1 if [key] is not in the list by default.
|
| - */
|
| -int binarySearch(List sortedList, var key,
|
| - { int compare(var a, var b) }) {
|
| - if (compare == null) {
|
| - return _comparableBinarySearch(sortedList, key);
|
| - }
|
| - int min = 0;
|
| - int max = sortedList.length;
|
| - while (min < max) {
|
| - int mid = min + ((max - min) >> 1);
|
| - var element = sortedList[mid];
|
| - int comp = compare(element, key);
|
| - if (comp == 0) return mid;
|
| - if (comp < 0) {
|
| - min = mid + 1;
|
| - } else {
|
| - max = mid;
|
| - }
|
| - }
|
| - return -1;
|
| -}
|
| -
|
| -
|
| -/**
|
| - * Shuffles a list randomly.
|
| - *
|
| - * A sub-range of a list can be shuffled by providing [start] and [end].
|
| - */
|
| -void shuffle(List list, [int start = 0, int end = null]) {
|
| - Random random = new Random();
|
| - if (end == null) end = list.length;
|
| - int length = end - start;
|
| - while (length > 1) {
|
| - int pos = random.nextInt(length);
|
| - length--;
|
| - var tmp1 = list[start + pos];
|
| - list[start + pos] = list[start + length];
|
| - list[start + length] = tmp1;
|
| - }
|
| -}
|
| -
|
| +// Merge multiple isolate profiler tracing dumps into one.
|
|
|
| -/**
|
| - * Reverses a list, or a part of a list, in-place.
|
| - */
|
| -void reverse(List list, [int start = 0, int end = null]) {
|
| - if (end == null) end = list.length;
|
| - _reverse(list, start, end);
|
| -}
|
| -
|
| -// Internal helper function that assumes valid arguments.
|
| -void _reverse(List list, int start, int end) {
|
| - for (int i = start, j = end - 1; i < j; i++, j--) {
|
| - var tmp = list[i];
|
| - list[i] = list[j];
|
| - list[j] = tmp;
|
| - }
|
| -}
|
| +import 'dart:convert';
|
| +import 'dart:io';
|
|
|
| /**
|
| * Sort a list using insertion sort.
|
| @@ -299,3 +210,152 @@ void _merge(int compare(a, b),
|
| target.setRange(targetOffset, targetOffset + (secondEnd - cursor2),
|
| secondList, cursor2);
|
| }
|
| +
|
| +class TraceMerge {
|
| + Map _processes = {};
|
| + List _metaEvents = [];
|
| +
|
| + void _processEventsFromFile(String name) {
|
| + var file = new File(name);
|
| + var events = [];
|
| + try {
|
| + var contents = file.readAsStringSync();
|
| + events = JSON.decode(contents);
|
| + } catch (e) {
|
| + print('Exception for $name $e');
|
| + }
|
| + _processEvents(events);
|
| + }
|
| +
|
| + List _findOrAddProcessThread(pid, tid) {
|
| + var process = _processes[pid];
|
| + if (process == null) {
|
| + process = {};
|
| + _processes[pid] = process;
|
| + }
|
| + var thread = process[tid];
|
| + if (thread == null) {
|
| + thread = [];
|
| + process[tid] = thread;
|
| + }
|
| + return thread;
|
| + }
|
| +
|
| + void _processEvents(List events) {
|
| + for (var i = 0; i < events.length; i++) {
|
| + Map event = events[i];
|
| + if (event['ph'] == 'M') {
|
| + _metaEvents.add(event);
|
| + } else {
|
| + var pid = event['pid'];
|
| + if (pid == null) {
|
| + throw "No pid in ${event}";
|
| + }
|
| + var tid = event['tid'];
|
| + if (tid == null) {
|
| + throw "No tid in ${event}";
|
| + }
|
| + var thread = _findOrAddProcessThread(pid, tid);
|
| + if (thread == null) {
|
| + throw "No thread list returned.";
|
| + }
|
| + thread.add(event);
|
| + }
|
| + }
|
| + }
|
| +
|
| + int _compare(Map a, Map b) {
|
| + if (a['ts'] > b['ts']) {
|
| + return 1;
|
| + } else if (a['ts'] < b['ts']) {
|
| + return -1;
|
| + }
|
| + return 0;
|
| + }
|
| +
|
| + void _sortEvents() {
|
| + _processes.forEach((k, Map process) {
|
| + process.forEach((k, List thread) {
|
| + mergeSort(thread, compare:_compare);
|
| + });
|
| + });
|
| + }
|
| +
|
| + void _mergeEventsForThread(List thread) {
|
| + List<Map> stack = [];
|
| + int stackDepth = 0;
|
| + thread.forEach((event) {
|
| + if (event['ph'] == 'B') {
|
| + if (stackDepth == stack.length) {
|
| + stack.add(null);
|
| + }
|
| + stackDepth++;
|
| + var end_event = stack[stackDepth - 1];
|
| + if (end_event != null) {
|
| + if (end_event['name'] == event['name'] && stackDepth > 1) {
|
| + // Kill these events.
|
| + // event['dead'] = true;
|
| + // end_event['dead'] = true;
|
| + }
|
| + }
|
| + } else {
|
| + if (event['ph'] != 'E') {
|
| + throw 'Expected E event: ${event}';
|
| + }
|
| + if (stackDepth <= 0) {
|
| + throw 'Stack out of sync ${event}.';
|
| + }
|
| + stackDepth--;
|
| + stack[stackDepth] = event;
|
| + }
|
| + });
|
| + }
|
| +
|
| + void _mergeEvents() {
|
| + _processes.forEach((k, Map process) {
|
| + process.forEach((k, List thread) {
|
| + _mergeEventsForThread(thread);
|
| + });
|
| + });
|
| + }
|
| +
|
| + void writeEventsToFile(String name) {
|
| + var file = new File(name);
|
| + List final_events = _metaEvents;
|
| + _processes.forEach((pid, Map process) {
|
| + process.forEach((tid, List thread) {
|
| + thread.forEach((event) {
|
| + if (event['dead'] == null) {
|
| + // Not dead.
|
| + final_events.add(event);
|
| + }
|
| + });
|
| + });
|
| + });
|
| + file.writeAsStringSync(JSON.encode(final_events));
|
| + }
|
| +
|
| + void merge(List<String> inputs) {
|
| + for (var i = 0; i < inputs.length; i++) {
|
| + _processEventsFromFile(inputs[i]);
|
| + }
|
| + _sortEvents();
|
| + _mergeEvents();
|
| + }
|
| +}
|
| +
|
| +main(List<String> arguments) {
|
| + if (arguments.length < 2) {
|
| + print('${Platform.executable} ${Platform.script} <output> <inputs>');
|
| + return;
|
| + }
|
| + String output = arguments[0];
|
| + List<String> inputs = new List<String>();
|
| + for (var i = 1; i < arguments.length; i++) {
|
| + inputs.add(arguments[i]);
|
| + }
|
| + print('Merging $inputs into $output.');
|
| + TraceMerge tm = new TraceMerge();
|
| + tm.merge(inputs);
|
| + tm.writeEventsToFile(output);
|
| +}
|
|
|