blob: 1d5996dcfd4f02b9d298ab965533341c400f4f9c [file] [log] [blame]
/*
* 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;
}
}