Convert looper traces to traceview traces

Change-Id: I378bab7d076ab43699d08809e58eb5a478488c74
diff --git a/tools/looperprofiler/LooperTrace.html b/tools/looperprofiler/LooperTrace.html
deleted file mode 100644
index 9df110c..0000000
--- a/tools/looperprofiler/LooperTrace.html
+++ /dev/null
@@ -1,48 +0,0 @@
-<!-- 
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
--->
-<html>
-    <head>
-        <script type="text/javascript" src="looper.trace.json"></script> 
-        <script type="text/javascript" src="trace.js"></script> 
-        <style>
-            div.traces > div {
-                display: inline-block;
-                height: 120px;
-            }
-
-            #wallContainer {
-                background-color: #eeeeee;
-            }
-
-            #threadContainer {
-                background-color: #e0e0e0;
-                margin-top: 1px;
-            }
-        </style>
-    </head>
-
-    <body>
-        <div style="overflow: scroll;">
-            <div id="wallContainer" class="traces"></div>
-            <div id="threadContainer" class="traces"></div>
-        </div>
-        <div>Event name: <span id="eventName"></span></div>
-        <div>Event#: <span id="eventIndex"></span></div>
-        <div>Event id: <span id="eventId"></span></div>
-        <div>Wall time: <span id="wallTime"></span></div>
-        <div>Thread time: <span id="threadTime"></span></div>
-    </body>
-</html>
diff --git a/tools/looperprofiler/LooperTraceToJSON.java b/tools/looperprofiler/LooperTraceToJSON.java
deleted file mode 100644
index a6ad9f4..0000000
--- a/tools/looperprofiler/LooperTraceToJSON.java
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
- 
-import java.io.*;
-import java.util.*;
-
-public class LooperTraceToJSON {
-    private static final int CURRENT_VERSION = 1;
-
-    private static class Entry {
-        int messageId;
-        String name;
-        long wallStart;
-        long wallTime;
-        long threadTime;
-    }
-
-    public static void main(String[] args) throws Exception {
-        if (args.length == 0) {
-            System.out.println("Usage: java LooperTraceToJSON [variablename] <filename>");
-            System.exit(0);
-        }
-
-        String var = "";
-
-        int fileIndex = 0;
-        if (args.length > 1) {
-            var = args[0];
-            fileIndex++;
-        }
-
-        File inputFile = new File(args[fileIndex]);
-        FileInputStream fis = new FileInputStream(inputFile);
-        DataInputStream in = new DataInputStream(new BufferedInputStream(fis));
-
-        int version = in.readInt();
-        if (version != CURRENT_VERSION) {
-            System.out.println("Only traces of version " + CURRENT_VERSION + " are supported");
-            System.exit(1);
-        }
-        int count = in.readInt();
-
-        ArrayList<Entry> entries = new ArrayList<Entry>(count);
-        for (int i = 0; i < count; i++) {
-            entries.add(readEntry(in));
-        }
-
-        String json = generateJSON(var, entries);
-        System.out.println(json);
-    }
-    
-    private static Entry readEntry(DataInputStream in) throws IOException {
-        Entry entry = new Entry();
-        entry.messageId = in.readInt();
-        entry.name = in.readUTF();
-        entry.wallStart = in.readLong();
-        entry.wallTime = in.readLong();
-        entry.threadTime = in.readLong();
-        return entry;
-    }
-    
-    private static String generateJSON(String var, ArrayList<Entry> entries) {
-        StringBuilder buffer = new StringBuilder(256);
-        if (var.length() > 0) {
-            buffer.append("var ").append(var).append(" = ");
-        }
-        buffer.append("[\n");
-
-        for (Entry entry : entries) {
-            buffer.append("    { ");
-
-            appendNumber(buffer, "messageId", entry.messageId);
-            buffer.append(", ");
-            
-            appendName(buffer, entry.name);
-            buffer.append(", ");
-
-            appendNumber(buffer, "wallStart", entry.wallStart);
-            buffer.append(", ");
-
-            appendNumber(buffer, "wallTime", entry.wallTime);
-            buffer.append(", ");
-
-            appendNumber(buffer, "threadTime", entry.threadTime);
-            buffer.append(" },\n");
-        }
-
-        buffer.append("];\n");
-        return buffer.toString();
-    }
-
-    private static void appendName(StringBuilder buffer, String name) {
-        buffer.append("\"name\": \"").append(name).append('"');
-    }
-
-    private static void appendNumber(StringBuilder buffer, String name, long number) {
-        buffer.append('"').append(name).append("\": ").append(number);
-    }
-}
diff --git a/tools/looperprofiler/LooperTraceToTraceview.java b/tools/looperprofiler/LooperTraceToTraceview.java
new file mode 100644
index 0000000..1d5996d
--- /dev/null
+++ b/tools/looperprofiler/LooperTraceToTraceview.java
@@ -0,0 +1,195 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.io.BufferedInputStream;
+import java.io.BufferedOutputStream;
+import java.io.DataInputStream;
+import java.io.DataOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.nio.ByteBuffer;
+import java.nio.ByteOrder;
+import java.nio.channels.FileChannel;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map;
+
+public class LooperTraceToTraceview {
+    private static final int CURRENT_VERSION = 1;
+
+    private static class Entry {
+        int traceId;
+        long wallStart;
+        long wallTime;
+        long threadStart;
+        long threadTime;
+    }
+
+    public static void main(String[] args) throws Exception {
+        if (args.length < 2) {
+            System.out.println("Usage: java LooperTraceToTraceview <filename> <output>");
+            System.exit(0);
+        }
+
+        File inputFile = new File(args[0]);
+        FileInputStream fis = new FileInputStream(inputFile);
+        DataInputStream in = new DataInputStream(new BufferedInputStream(fis));
+
+        int version = in.readInt();
+        if (version != CURRENT_VERSION) {
+            System.out.println("Only traces of version " + CURRENT_VERSION + " are supported");
+            System.exit(1);
+        }
+
+        long wallStart = in.readLong();
+        long threadStart = in.readLong();
+
+        int count = in.readInt();
+        HashMap<String, Integer> names = new HashMap<String, Integer>(count);
+        for (int i = 0; i < count; i++) {
+            readName(in, names);
+        }
+
+        count = in.readInt();
+        ArrayList<Entry> entries = new ArrayList<Entry>(count);
+        for (int i = 0; i < count; i++) {
+            entries.add(readEntry(in));
+        }
+
+        File outputFile = new File(args[1]);
+        FileOutputStream fos = new FileOutputStream(outputFile);
+        DataOutputStream out = new DataOutputStream(new BufferedOutputStream(fos));
+
+        writeHeader(out, wallStart, names, entries);
+        out.flush();
+
+        writeTraces(fos, out.size(), wallStart, threadStart, entries);
+
+        out.close();
+    }
+
+    private static void writeTraces(FileOutputStream out, long offset, long wallStart,
+            long threadStart, ArrayList<Entry> entries) throws IOException {
+
+        FileChannel channel = out.getChannel();
+
+        // Header
+        ByteBuffer buffer = ByteBuffer.allocateDirect(32);
+        buffer.put("SLOW".getBytes());
+        buffer = buffer.order(ByteOrder.LITTLE_ENDIAN);
+        buffer.putShort((short) 3);    // version
+        buffer.putShort((short) 32);   // offset to data
+        buffer.putLong(wallStart);     // start time in usec
+        buffer.putShort((short) 14);   // size of a record in bytes
+        // padding to 32 bytes
+        for (int i = 0; i < 32 - 18; i++) buffer.put((byte) 0);
+
+        buffer.flip();
+        channel.position(offset).write(buffer);
+        
+        buffer = ByteBuffer.allocateDirect(14).order(ByteOrder.LITTLE_ENDIAN);
+        for (Entry entry : entries) {
+            buffer.putShort((short) 1);
+            buffer.putInt(entry.traceId); // entering method
+            buffer.putInt((int) (entry.threadStart - threadStart));
+            buffer.putInt((int) (entry.wallStart - wallStart));
+
+            buffer.flip();
+            channel.write(buffer);
+            buffer.clear();
+
+            buffer.putShort((short) 1);
+            buffer.putInt(entry.traceId | 0x1); // exiting method
+            buffer.putInt((int) (entry.threadStart + entry.threadTime - threadStart));
+            buffer.putInt((int) (entry.wallStart + entry.wallTime - wallStart));
+
+            buffer.flip();
+            channel.write(buffer);
+            buffer.clear();
+        }
+
+        channel.close();
+    }
+
+    private static void writeHeader(DataOutputStream out, long start,
+            HashMap<String, Integer> names, ArrayList<Entry> entries) throws IOException {
+
+        Entry last = entries.get(entries.size() - 1);
+        long wallTotal = (last.wallStart + last.wallTime) - start;
+
+        startSection("version", out);
+        addValue(null, "3", out);
+        addValue("data-file-overflow", "false", out);
+        addValue("clock", "dual", out);
+        addValue("elapsed-time-usec", Long.toString(wallTotal), out);
+        addValue("num-method-calls", Integer.toString(entries.size()), out);
+        addValue("clock-call-overhead-nsec", "1", out);
+        addValue("vm", "dalvik", out);
+
+        startSection("threads", out);
+        addThreadId(1, "main", out);
+
+        startSection("methods", out);
+        addMethods(names, out);
+
+        startSection("end", out);
+    }
+
+    private static void addMethods(HashMap<String, Integer> names, DataOutputStream out)
+            throws IOException {
+
+        for (Map.Entry<String, Integer> name : names.entrySet()) {
+            out.writeBytes("0x" + String.format("%08x", name.getValue()) + "\tEventQueue\t" +
+                    name.getKey().replace('$', '_') + "\t()V\tLooper.java\t-2\n");
+        }
+    }
+
+    private static void addThreadId(int id, String name, DataOutputStream out) throws IOException {
+        out.writeBytes(Integer.toString(id) + '\t' + name + '\n');
+    }
+
+    private static void addValue(String name, String value, DataOutputStream out)
+            throws IOException {
+
+        if (name != null) {
+            out.writeBytes(name + "=");
+        }
+        out.writeBytes(value + '\n');
+    }
+
+    private static void startSection(String name, DataOutputStream out) throws IOException {
+        out.writeBytes("*" + name + '\n');
+    }
+
+    private static void readName(DataInputStream in, HashMap<String, Integer> names)
+            throws IOException {
+        int id = 0x56000000 | (in.readShort() << 2);
+        String name = in.readUTF();
+        names.put(name, id);
+    }
+
+    private static Entry readEntry(DataInputStream in) throws IOException {
+        Entry entry = new Entry();
+        entry.traceId = 0x56000000 | (in.readShort() << 2);
+        entry.wallStart = in.readLong();
+        entry.wallTime = in.readLong();
+        entry.threadStart = in.readLong();
+        entry.threadTime = in.readLong();
+        return entry;
+    }
+}
diff --git a/tools/looperprofiler/README.txt b/tools/looperprofiler/README.txt
index 47a2ccb..476d3dc 100644
--- a/tools/looperprofiler/README.txt
+++ b/tools/looperprofiler/README.txt
@@ -9,6 +9,6 @@
 After profiling the file must be pulled from the device using adb pull.
 
 To use this tool, compile the single .java file and run:
-java LooperTraceToJSON myLooperTracesFile > looper.trace.json
+java LooperTraceToTraceView myLooperTracesFile looperTraceViewFile
 
-Then open LooperTrace.html and you can inspect your looper traces.
+The run traceview looperTraceViewFile
diff --git a/tools/looperprofiler/trace.js b/tools/looperprofiler/trace.js
deleted file mode 100644
index 8167e2e..0000000
--- a/tools/looperprofiler/trace.js
+++ /dev/null
@@ -1,95 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-var UNIT_WIDTH = 5;
-
-function selectEntry(event) {
-    var trace = event.target["traceEntry"];
-    var entry = trace[1];
-    document.getElementById('eventIndex').textContent = trace[0];
-    document.getElementById('eventName').textContent = entry.name;
-    document.getElementById('eventId').textContent = entry.messageId;
-    document.getElementById('wallTime').textContent = entry.wallTime;
-    document.getElementById('threadTime').textContent = entry.threadTime;
-}
-
-function displayTraces() {
-    var wallContainer = document.getElementById('wallContainer');
-    var threadContainer = document.getElementById('threadContainer');
-
-    var totalWidth = 0;
-
-    var x = 0;
-    var prevX = 0;
-    var prevEnd = traces[0].wallStart;
-    
-    var color = [
-        "DeepSkyBlue",
-        "MediumBlue",
-        "OrangeRed",
-        "GoldenRod",
-        "Crimson",
-        "Teal",
-        "Orchid",
-        "Navy",
-        "Gold",
-        "DarkGreen",
-        "DarkOrchid",
-    ];
-    var colorMap = { };
-    
-    var prevWidth = 0;
-
-    for (i in traces) {
-        var entry = traces[i];
-
-        var margin = Math.round((entry.wallStart - prevEnd) / 4);
-        var width = Math.max(1, entry.wallTime) * UNIT_WIDTH;
-
-        element = document.createElement('div');
-        element.style.width = width;
-        if (margin > 0) element.style.marginLeft = margin;
-        element.style.marginRight = 1;
-        if (!colorMap[entry.name]) {
-            colorMap[entry.name] = color[i % color.length];
-        }
-        element.style.backgroundColor = colorMap[entry.name];
-        element["traceEntry"] = [ i, entry ];
-        element.addEventListener("mouseover", selectEntry, false);
-        wallContainer.appendChild(element);
-
-        prevX = x;
-        prevEnd = entry.wallStart + entry.wallTime;
-        x += width + margin + 1;
-        var prevWidth = width;
-
-        width = Math.max(1, entry.threadTime) * UNIT_WIDTH;
-
-        element = document.createElement('div');
-        element.style.marginLeft = margin;
-        element.style.marginRight = prevWidth - width + 1;
-        element.style.width = width;
-        element.style.backgroundColor = colorMap[entry.name];
-        element["traceEntry"] = [ i, entry ];
-        element.addEventListener("mouseover", selectEntry, false);
-        threadContainer.appendChild(element);
-    }
-
-    wallContainer.style.width = x;
-    threadContainer.style.width = x;
-}
-
-window.onload = displayTraces;