1cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom/*
2cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * Copyright (C) 2010 The Android Open Source Project
3cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom *
4cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * Licensed under the Apache License, Version 2.0 (the "License");
5cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * you may not use this file except in compliance with the License.
6cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * You may obtain a copy of the License at
7cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom *
8cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom *      http://www.apache.org/licenses/LICENSE-2.0
9cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom *
10cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * Unless required by applicable law or agreed to in writing, software
11cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * distributed under the License is distributed on an "AS IS" BASIS,
12cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * See the License for the specific language governing permissions and
14cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * limitations under the License.
15cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom */
16cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
17cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrompackage dalvik.system.profiler;
18cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
19cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.DataOutputStream;
20cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.IOException;
21cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.OutputStream;
22cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.HashMap;
23cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Map;
24cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Set;
25cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
26e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom/**
27e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom * BinaryHprofWriter produces hprof compatible binary output for use
28e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom * with third party tools. Such files can be converted to text with
29e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom * with {@link HprofBinaryToAscii} or read back in with {@link BinaryHprofReader}.
30e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom */
31e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrompublic final class BinaryHprofWriter {
32cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
33cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int nextStringId = 1; // id 0 => null
34cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int nextClassId = 1;
35cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int nextStackFrameId = 1;
36cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<String, Integer> stringToId = new HashMap<String, Integer>();
37cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<String, Integer> classNameToId = new HashMap<String, Integer>();
38cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<StackTraceElement, Integer> stackFrameToId
39cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            = new HashMap<StackTraceElement, Integer>();
40cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
41cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final HprofData data;
42cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final DataOutputStream out;
43cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
44e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom    /**
45e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom     * Writes the provided data to the specified stream.
46e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom     */
47e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom    public static void write(HprofData data, OutputStream outputStream) throws IOException {
48e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        new BinaryHprofWriter(data, outputStream).write();
49e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom    }
50e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom
51e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom    private BinaryHprofWriter(HprofData data, OutputStream outputStream) {
52cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.data = data;
53cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.out = new DataOutputStream(outputStream);
54cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
55cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
56e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom    private void write() throws IOException {
57cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        try {
58cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            writeHeader(data.getStartMillis());
59cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
60cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            writeControlSettings(data.getFlags(), data.getDepth());
61cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
62cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            for (HprofData.ThreadEvent event : data.getThreadHistory()) {
63cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                writeThreadEvent(event);
64cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
65cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
66cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            Set<HprofData.Sample> samples = data.getSamples();
67cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int total = 0;
68cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            for (HprofData.Sample sample : samples) {
69cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                total += sample.count;
70cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                writeStackTrace(sample.stackTrace);
71cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
72cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            writeCpuSamples(total, samples);
73cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
74cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        } finally {
75cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            out.flush();
76cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
77cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
78cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
79cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeHeader(long dumpTimeInMilliseconds) throws IOException {
80e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        out.writeBytes(BinaryHprof.MAGIC + "1.0.2");
81cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeByte(0); // null terminated string
82cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(BinaryHprof.ID_SIZE);
83cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeLong(dumpTimeInMilliseconds);
84cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
85cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
86cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeControlSettings(int flags, int depth) throws IOException {
87cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (depth > Short.MAX_VALUE) {
88cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalArgumentException("depth too large for binary hprof: "
89cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                               + depth + " > " + Short.MAX_VALUE);
90cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
91cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.CONTROL_SETTINGS,
92cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
93cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.Tag.CONTROL_SETTINGS.maximumSize);
94cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(flags);
95cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeShort((short) depth);
96cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
97cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
98cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeThreadEvent(HprofData.ThreadEvent e) throws IOException {
99cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        switch (e.type) {
100cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case START:
101cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                writeStartThread(e);
102cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return;
103cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case END:
104cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                writeStopThread(e);
105cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return;
106cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
107cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        throw new IllegalStateException(e.type.toString());
108cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
109cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
110cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeStartThread(HprofData.ThreadEvent e) throws IOException {
111cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int threadNameId = writeString(e.threadName);
112cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int groupNameId = writeString(e.groupName);
113cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int parentGroupNameId = writeString(e.parentGroupName);
114cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.START_THREAD,
115cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
116cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.Tag.START_THREAD.maximumSize);
117cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(e.threadId);
118cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(e.objectId);
119cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(0); // stack trace where thread was started unavailable
120cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(threadNameId);
121cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(groupNameId);
122cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(parentGroupNameId);
123cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
124cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
125cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeStopThread(HprofData.ThreadEvent e) throws IOException {
126cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.END_THREAD,
127cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
128cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.Tag.END_THREAD.maximumSize);
129cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(e.threadId);
130cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
131cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
132cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeRecordHeader(BinaryHprof.Tag hprofTag,
133cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                   int timeDeltaInMicroseconds,
134cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                   int recordLength) throws IOException {
135cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String error = hprofTag.checkSize(recordLength);
136cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (error != null) {
137cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new AssertionError(error);
138cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
139cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeByte(hprofTag.tag);
140cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(timeDeltaInMicroseconds);
141cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(recordLength);
142cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
143cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
144cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeId(int id) throws IOException {
145cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(id);
146cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
147cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
148cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
149cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Ensures that a string has been writen to the out and
150cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * returns its ID. The ID of a null string is zero, and
151cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * doesn't actually result in any output. In a string has
152cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * already been written previously, the earlier ID will be
153cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * returned and no output will be written.
154cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
155cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int writeString(String string) throws IOException {
156cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (string == null) {
157cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return 0;
158cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
159cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        Integer identifier = stringToId.get(string);
160cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (identifier != null) {
161cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return identifier;
162cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
163cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
164cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int id = nextStringId++;
165cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        stringToId.put(string, id);
166cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
167cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        byte[] bytes = string.getBytes("UTF-8");
168cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.STRING_IN_UTF8,
169cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
170cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.ID_SIZE + bytes.length);
171cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(id);
172cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.write(bytes, 0, bytes.length);
173cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
174cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return id;
175cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
176cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
177cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeCpuSamples(int totalSamples, Set<HprofData.Sample> samples)
178cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throws IOException {
179cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int samplesCount = samples.size();
180cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (samplesCount == 0) {
181cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return;
182cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
183cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.CPU_SAMPLES, 0, 4 + 4 + (samplesCount * (4 + 4)));
184cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(totalSamples);
185cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(samplesCount);
186cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (HprofData.Sample sample : samples) {
187cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            out.writeInt(sample.count);
188cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            out.writeInt(sample.stackTrace.stackTraceId);
189cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
190cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
191cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
192cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void writeStackTrace(HprofData.StackTrace stackTrace) throws IOException {
193cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int frames = stackTrace.stackFrames.length;
194cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int[] stackFrameIds = new int[frames];
195cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (int i = 0; i < frames; i++) {
196cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            stackFrameIds[i] = writeStackFrame(stackTrace.stackFrames[i]);
197cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
198cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.STACK_TRACE,
199cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
200cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          4 + 4 + 4 + (frames * BinaryHprof.ID_SIZE));
201cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(stackTrace.stackTraceId);
202cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(stackTrace.threadId);
203cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(frames);
204cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (int stackFrameId : stackFrameIds) {
205cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            writeId(stackFrameId);
206cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
207cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
208cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
209cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int writeLoadClass(String className) throws IOException {
210cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        Integer identifier = classNameToId.get(className);
211cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (identifier != null) {
212cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return identifier;
213cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
214cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int id = nextClassId++;
215cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        classNameToId.put(className, id);
216cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
217cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int classNameId = writeString(className);
218cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.LOAD_CLASS,
219cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
220cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.Tag.LOAD_CLASS.maximumSize);
221cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(id);
222cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(0); // class object ID
223cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(0); // stack trace where class was loaded is unavailable
224cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(classNameId);
225cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
226cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return id;
227cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
228cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
229cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int writeStackFrame(StackTraceElement stackFrame) throws IOException {
230cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        Integer identifier = stackFrameToId.get(stackFrame);
231cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (identifier != null) {
232cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return identifier;
233cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
234cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
235cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int id = nextStackFrameId++;
236cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        stackFrameToId.put(stackFrame, id);
237cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
238cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int classId = writeLoadClass(stackFrame.getClassName());
239cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int methodNameId = writeString(stackFrame.getMethodName());
240cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int sourceId = writeString(stackFrame.getFileName());
241cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeRecordHeader(BinaryHprof.Tag.STACK_FRAME,
242cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          0,
243cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                          BinaryHprof.Tag.STACK_FRAME.maximumSize);
244cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(id);
245cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(methodNameId);
246cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(0); // method signature is unavailable from StackTraceElement
247cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        writeId(sourceId);
248cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(classId);
249cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        out.writeInt(stackFrame.getLineNumber());
250cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
251cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return id;
252cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
253cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom}
254