Index: tools/tracemerge.dart |
diff --git a/tools/tracemerge.dart b/tools/tracemerge.dart |
deleted file mode 100644 |
index 6c7d5ddd45dcf2b9d2cca9aede54f084293ae6d5..0000000000000000000000000000000000000000 |
--- a/tools/tracemerge.dart |
+++ /dev/null |
@@ -1,361 +0,0 @@ |
-// Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file |
-// 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. |
- |
-// Merge multiple isolate profiler tracing dumps into one. |
- |
-import 'dart:convert'; |
-import 'dart:io'; |
- |
-/** |
- * Sort a list using insertion sort. |
- * |
- * Insertion sort is a simple sorting algorithm. For `n` elements it does on |
- * the order of `n * log(n)` comparisons but up to `n` squared moves. The |
- * sorting is performed in-place, without using extra memory. |
- * |
- * For short lists the many moves have less impact than the simple algorithm, |
- * and it is often the favored sorting algorithm for short lists. |
- * |
- * This insertion sort is stable: Equal elements end up in the same order |
- * as they started in. |
- */ |
-void insertionSort(List list, |
- { int compare(a, b), |
- int start: 0, |
- int end: null }) { |
- // If the same method could have both positional and named optional |
- // parameters, this should be (list, [start, end], {compare}). |
- if (end == null) end = list.length; |
- if (compare == null) compare = Comparable.compare; |
- _insertionSort(list, compare, start, end, start + 1); |
-} |
- |
-/** |
- * Internal helper function that assumes arguments correct. |
- * |
- * Assumes that the elements up to [sortedUntil] (not inclusive) are |
- * already sorted. The [sortedUntil] values should always be at least |
- * `start + 1`. |
- */ |
-void _insertionSort(List list, int compare(a, b), int start, int end, |
- int sortedUntil) { |
- for (int pos = sortedUntil; pos < end; pos++) { |
- int min = start; |
- int max = pos; |
- var element = list[pos]; |
- while (min < max) { |
- int mid = min + ((max - min) >> 1); |
- int comparison = compare(element, list[mid]); |
- if (comparison < 0) { |
- max = mid; |
- } else { |
- min = mid + 1; |
- } |
- } |
- list.setRange(min + 1, pos + 1, list, min); |
- list[min] = element; |
- } |
-} |
- |
-/** Limit below which merge sort defaults to insertion sort. */ |
-const int _MERGE_SORT_LIMIT = 32; |
- |
-/** |
- * Sorts a list, or a range of a list, using the merge sort algorithm. |
- * |
- * Merge-sorting works by splitting the job into two parts, sorting each |
- * recursively, and then merging the two sorted parts. |
- * |
- * This takes on the order of `n * log(n)` comparisons and moves to sort |
- * `n` elements, but requires extra space of about the same size as the list |
- * being sorted. |
- * |
- * This merge sort is stable: Equal elements end up in the same order |
- * as they started in. |
- */ |
-void mergeSort(List list, {int start: 0, int end: null, int compare(a, b)}) { |
- if (end == null) end = list.length; |
- if (compare == null) compare = Comparable.compare; |
- int length = end - start; |
- if (length < 2) return; |
- if (length < _MERGE_SORT_LIMIT) { |
- _insertionSort(list, compare, start, end, start + 1); |
- return; |
- } |
- // Special case the first split instead of directly calling |
- // _mergeSort, because the _mergeSort requires its target to |
- // be different from its source, and it requires extra space |
- // of the same size as the list to sort. |
- // This split allows us to have only half as much extra space, |
- // and it ends up in the original place. |
- int middle = start + ((end - start) >> 1); |
- int firstLength = middle - start; |
- int secondLength = end - middle; |
- // secondLength is always the same as firstLength, or one greater. |
- List scratchSpace = new List(secondLength); |
- _mergeSort(list, compare, middle, end, scratchSpace, 0); |
- int firstTarget = end - firstLength; |
- _mergeSort(list, compare, start, middle, list, firstTarget); |
- _merge(compare, |
- list, firstTarget, end, |
- scratchSpace, 0, secondLength, |
- list, start); |
-} |
- |
-/** |
- * Performs an insertion sort into a potentially different list than the |
- * one containing the original values. |
- * |
- * It will work in-place as well. |
- */ |
-void _movingInsertionSort(List list, int compare(a, b), int start, int end, |
- List target, int targetOffset) { |
- int length = end - start; |
- if (length == 0) return; |
- target[targetOffset] = list[start]; |
- for (int i = 1; i < length; i++) { |
- var element = list[start + i]; |
- int min = targetOffset; |
- int max = targetOffset + i; |
- while (min < max) { |
- int mid = min + ((max - min) >> 1); |
- if (compare(element, target[mid]) < 0) { |
- max = mid; |
- } else { |
- min = mid + 1; |
- } |
- } |
- target.setRange(min + 1, targetOffset + i + 1, |
- target, min); |
- target[min] = element; |
- } |
-} |
- |
-/** |
- * Sorts [list] from [start] to [end] into [target] at [targetOffset]. |
- * |
- * The `target` list must be able to contain the range from `start` to `end` |
- * after `targetOffset`. |
- * |
- * Allows target to be the same list as [list], as long as it's not |
- * overlapping the `start..end` range. |
- */ |
-void _mergeSort(List list, int compare(a, b), int start, int end, |
- List target, int targetOffset) { |
- int length = end - start; |
- if (length < _MERGE_SORT_LIMIT) { |
- _movingInsertionSort(list, compare, start, end, target, targetOffset); |
- return; |
- } |
- int middle = start + (length >> 1); |
- int firstLength = middle - start; |
- int secondLength = end - middle; |
- // Here secondLength >= firstLength (differs by at most one). |
- int targetMiddle = targetOffset + firstLength; |
- // Sort the second half into the end of the target area. |
- _mergeSort(list, compare, middle, end, |
- target, targetMiddle); |
- // Sort the first half into the end of the source area. |
- _mergeSort(list, compare, start, middle, |
- list, middle); |
- // Merge the two parts into the target area. |
- _merge(compare, |
- list, middle, middle + firstLength, |
- target, targetMiddle, targetMiddle + secondLength, |
- target, targetOffset); |
-} |
- |
-/** |
- * Merges two lists into a target list. |
- * |
- * One of the input lists may be positioned at the end of the target |
- * list. |
- * |
- * For equal object, elements from [firstList] are always preferred. |
- * This allows the merge to be stable if the first list contains elements |
- * that started out earlier than the ones in [secondList] |
- */ |
-void _merge(int compare(a, b), |
- List firstList, int firstStart, int firstEnd, |
- List secondList, int secondStart, int secondEnd, |
- List target, int targetOffset) { |
- // No empty lists reaches here. |
- assert(firstStart < firstEnd); |
- assert(secondStart < secondEnd); |
- int cursor1 = firstStart; |
- int cursor2 = secondStart; |
- var firstElement = firstList[cursor1++]; |
- var secondElement = secondList[cursor2++]; |
- while (true) { |
- if (compare(firstElement, secondElement) <= 0) { |
- target[targetOffset++] = firstElement; |
- if (cursor1 == firstEnd) break; // Flushing second list after loop. |
- firstElement = firstList[cursor1++]; |
- } else { |
- target[targetOffset++] = secondElement; |
- if (cursor2 != secondEnd) { |
- secondElement = secondList[cursor2++]; |
- continue; |
- } |
- // Second list empties first. Flushing first list here. |
- target[targetOffset++] = firstElement; |
- target.setRange(targetOffset, targetOffset + (firstEnd - cursor1), |
- firstList, cursor1); |
- return; |
- } |
- } |
- // First list empties first. Reached by break above. |
- target[targetOffset++] = secondElement; |
- 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); |
-} |