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.BufferedInputStream;
20cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.DataInputStream;
21cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.EOFException;
22cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.IOException;
23cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.io.InputStream;
24cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Date;
25cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.HashMap;
26cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Map;
27cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
28cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom/**
29cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <pre>   {@code
30cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * BinaryHprofReader reader = new BinaryHprofReader(new BufferedInputStream(inputStream));
31cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * reader.setStrict(false); // for RI compatability
32cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * reader.read();
33cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * inputStream.close();
34cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * reader.getVersion();
35cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * reader.getHprofData();
36cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * }</pre>
37cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom */
38cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrompublic final class BinaryHprofReader {
39cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
40cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private static final boolean TRACE = false;
41cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
42cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final DataInputStream in;
43cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
44cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
45cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * By default we try to strictly validate rules followed by
46cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * our HprofWriter. For example, every end thread is preceded
47cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * by a matching start thread.
48cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
49cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private boolean strict = true;
50cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
51cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
52cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * version string from header after read has been performed,
53cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * otherwise null. nullness used to detect if callers try to
54cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * access data before read is called.
55cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
56cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private String version;
57cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
58cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<HprofData.StackTrace, int[]> stackTraces
59cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            = new HashMap<HprofData.StackTrace, int[]>();
60cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
61cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final HprofData hprofData = new HprofData(stackTraces);
62cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
63cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<Integer, String> idToString = new HashMap<Integer, String>();
64cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<Integer, String> idToClassName = new HashMap<Integer, String>();
65cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<Integer, StackTraceElement> idToStackFrame
66cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            = new HashMap<Integer, StackTraceElement>();
67cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<Integer, HprofData.StackTrace> idToStackTrace
68cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            = new HashMap<Integer, HprofData.StackTrace>();
69cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
70cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
71cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Creates a BinaryHprofReader around the specified {@code
72cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * inputStream}
73cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
74cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public BinaryHprofReader(InputStream inputStream) throws IOException {
75cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.in = new DataInputStream(inputStream);
76cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
77cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
78cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public boolean getStrict () {
79cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return strict;
80cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
81cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
82cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void setStrict (boolean strict) {
83cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (version != null) {
84cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalStateException("cannot set strict after read()");
85cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
86cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.strict = strict;
87cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
88cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
89cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
90cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * throws IllegalStateException if read() has not been called.
91cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
92cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void checkRead() {
93cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (version == null) {
94cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalStateException("data access before read()");
95cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
96cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
97cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
98cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public String getVersion() {
99cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        checkRead();
100cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return version;
101cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
102cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
103cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public HprofData getHprofData() {
104cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        checkRead();
105cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return hprofData;
106cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
107cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
108cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
109cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Read the hprof header and records from the input
110cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
111cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void read() throws IOException {
112cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        parseHeader();
113cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        parseRecords();
114cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
115cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
116cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseHeader() throws IOException {
117cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
118cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("hprofTag=HEADER");
119cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
120cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        parseVersion();
121cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        parseIdSize();
122cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        parseTime();
123cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
124cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
125cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseVersion() throws IOException {
126e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        String version = BinaryHprof.readMagic(in);
127e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        if (version == null) {
128e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom            throw new MalformedHprofException("Could not find HPROF version");
129e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        }
130e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        if (TRACE) {
131e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom            System.out.println("\tversion=" + version);
132cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
133e9af8901fc4ed7c05d085e2e492f5dcc857f0146Brian Carlstrom        this.version = version;
134cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
135cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
136cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseIdSize() throws IOException {
137cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int idSize = in.readInt();
138cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
139cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tidSize=" + idSize);
140cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
141cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (idSize != BinaryHprof.ID_SIZE) {
142cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Unsupported identifier size: " + idSize);
143cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
144cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
145cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
146cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseTime() throws IOException {
147cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        long time = in.readLong();
148cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
149cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\ttime=" + Long.toHexString(time) + " " + new Date(time));
150cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
151cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        hprofData.setStartMillis(time);
152cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
153cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
154cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseRecords() throws IOException {
155cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        while (parseRecord()) {
156cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            ;
157cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
158cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
159cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
160cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
161cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Read and process the next record. Returns true if a
162cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * record was handled, false on EOF.
163cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
164cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private boolean parseRecord() throws IOException {
165cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int tagOrEOF = in.read();
166cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (tagOrEOF == -1) {
167cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return false;
168cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
169cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        byte tag = (byte) tagOrEOF;
170cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int timeDeltaInMicroseconds = in.readInt();
171cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int recordLength = in.readInt();
172cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        BinaryHprof.Tag hprofTag = BinaryHprof.Tag.get(tag);
173cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
174cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("hprofTag=" + hprofTag);
175cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
176cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (hprofTag == null) {
177cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            skipRecord(hprofTag, recordLength);
178cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return true;
179cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
180cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String error = hprofTag.checkSize(recordLength);
181cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (error != null) {
182cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException(error);
183cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
184cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        switch (hprofTag) {
185cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case CONTROL_SETTINGS:
186cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseControlSettings();
187cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
188cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
189cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case STRING_IN_UTF8:
190cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseStringInUtf8(recordLength);
191cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
192cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
193cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case START_THREAD:
194cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseStartThread();
195cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
196cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case END_THREAD:
197cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseEndThread();
198cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
199cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
200cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case LOAD_CLASS:
201cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseLoadClass();
202cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
203cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case STACK_FRAME:
204cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseStackFrame();
205cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
206cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case STACK_TRACE:
207cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseStackTrace(recordLength);
208cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
209cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
210cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case CPU_SAMPLES:
211cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                parseCpuSamples(recordLength);
212cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
213cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
214cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case UNLOAD_CLASS:
215cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case ALLOC_SITES:
216cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case HEAP_SUMMARY:
217cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case HEAP_DUMP:
218cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case HEAP_DUMP_SEGMENT:
219cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case HEAP_DUMP_END:
220cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            default:
221cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                skipRecord(hprofTag, recordLength);
222cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return true;
223cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
224cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
225cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
226cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void skipRecord(BinaryHprof.Tag hprofTag, long recordLength) throws IOException {
227cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
228cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tskipping recordLength=" + recordLength);
229cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
230cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        long skipped = in.skip(recordLength);
231cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (skipped != recordLength) {
232cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new EOFException("Expected to skip " + recordLength
233cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                   + " bytes but only skipped " + skipped + " bytes");
234cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
235cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
236cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
237cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseControlSettings() throws IOException {
238cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int flags = in.readInt();
239cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        short depth = in.readShort();
240cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
241cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tflags=" + Integer.toHexString(flags));
242cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tdepth=" + depth);
243cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
244cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        hprofData.setFlags(flags);
245cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        hprofData.setDepth(depth);
246cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
247cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
248cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseStringInUtf8(int recordLength) throws IOException {
249cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int stringId = in.readInt();
250cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        byte[] bytes = new byte[recordLength - BinaryHprof.ID_SIZE];
251cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        readFully(in, bytes);
252cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String string = new String(bytes, "UTF-8");
253cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
254cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tstring=" + string);
255cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
256cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String old = idToString.put(stringId, string);
257cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (old != null) {
258cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Duplicate string id: " + stringId);
259cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
260cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
261cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
262cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private static void readFully(InputStream in, byte[] dst) throws IOException {
263cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int offset = 0;
264cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int byteCount = dst.length;
265cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        while (byteCount > 0) {
266cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int bytesRead = in.read(dst, offset, byteCount);
267cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (bytesRead < 0) {
268cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new EOFException();
269cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
270cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            offset += bytesRead;
271cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            byteCount -= bytesRead;
272cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
273cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
274cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
275cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseLoadClass() throws IOException {
276cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int classId = in.readInt();
277cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int classObjectId = readId();
278cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        // serial number apparently not a stack trace id. (int vs ID)
279cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        // we don't use this field.
280cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int stackTraceSerialNumber = in.readInt();
281cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String className = readString();
282cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
283cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tclassId=" + classId);
284cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tclassObjectId=" + classObjectId);
285cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tstackTraceSerialNumber=" + stackTraceSerialNumber);
286cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tclassName=" + className);
287cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
288cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String old = idToClassName.put(classId, className);
289cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (old != null) {
290cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Duplicate class id: " + classId);
291cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
292cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
293cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
294cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int readId() throws IOException {
295cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return in.readInt();
296cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
297cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
298cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private String readString() throws IOException {
299cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int id = readId();
300cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (id == 0) {
301cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return null;
302cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
303cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String string = idToString.get(id);
304cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (string == null) {
305cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Unknown string id " + id);
306cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
307cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return string;
308cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
309cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
310cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private String readClass() throws IOException {
311cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int id = readId();
312cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String string = idToClassName.get(id);
313cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (string == null) {
314cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Unknown class id " + id);
315cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
316cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return string;
317cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
318cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
319cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseStartThread() throws IOException {
320cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int threadId = in.readInt();
321cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int objectId = readId();
322cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        // stack trace where thread was created.
323cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        // serial number apparently not a stack trace id. (int vs ID)
324cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        // we don't use this field.
325cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int stackTraceSerialNumber = in.readInt();
326cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String threadName = readString();
327cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String groupName = readString();
328cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String parentGroupName = readString();
329cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
330cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tthreadId=" + threadId);
331cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tobjectId=" + objectId);
332cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tstackTraceSerialNumber=" + stackTraceSerialNumber);
333cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tthreadName=" + threadName);
334cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tgroupName=" + groupName);
335cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tparentGroupName=" + parentGroupName);
336cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
337cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        HprofData.ThreadEvent event
338cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                = HprofData.ThreadEvent.start(objectId, threadId,
339cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              threadName, groupName, parentGroupName);
340cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        hprofData.addThreadEvent(event);
341cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
342cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
343cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseEndThread() throws IOException {
344cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int threadId = in.readInt();
345cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
346cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tthreadId=" + threadId);
347cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
348cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        HprofData.ThreadEvent event = HprofData.ThreadEvent.end(threadId);
349cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        hprofData.addThreadEvent(event);
350cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
351cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
352cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseStackFrame() throws IOException {
353cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int stackFrameId = readId();
354cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String methodName = readString();
355cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String methodSignature = readString();
356cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String file = readString();
357cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        String className = readClass();
358cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int line = in.readInt();
359cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
360cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tstackFrameId=" + stackFrameId);
361cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tclassName=" + className);
362cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tmethodName=" + methodName);
363cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tmethodSignature=" + methodSignature);
364cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tfile=" + file);
365cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tline=" + line);
366cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
367cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        StackTraceElement stackFrame = new StackTraceElement(className, methodName, file, line);
368cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        StackTraceElement old = idToStackFrame.put(stackFrameId, stackFrame);
369cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (old != null) {
370cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Duplicate stack frame id: " + stackFrameId);
371cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
372cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
373cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
374cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseStackTrace(int recordLength) throws IOException {
375cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int stackTraceId = in.readInt();
376cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int threadId = in.readInt();
377cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int frames = in.readInt();
378cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
379cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tstackTraceId=" + stackTraceId);
380cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tthreadId=" + threadId);
381cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tframes=" + frames);
382cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
383cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int expectedLength = 4 + 4 + 4 + (frames * BinaryHprof.ID_SIZE);
384cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (recordLength != expectedLength) {
385cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Expected stack trace record of size "
386cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + expectedLength
387cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + " based on number of frames but header "
388cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + "specified a length of  " + recordLength);
389cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
390cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        StackTraceElement[] stackFrames = new StackTraceElement[frames];
391cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (int i = 0; i < frames; i++) {
392cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int stackFrameId = readId();
393cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            StackTraceElement stackFrame = idToStackFrame.get(stackFrameId);
394cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (TRACE) {
395cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                System.out.println("\tstackFrameId=" + stackFrameId);
396cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                System.out.println("\tstackFrame=" + stackFrame);
397cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
398cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (stackFrame == null) {
399cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new MalformedHprofException("Unknown stack frame id " + stackFrameId);
400cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
401cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            stackFrames[i] = stackFrame;
402cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
403cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
404cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        HprofData.StackTrace stackTrace
405cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                = new HprofData.StackTrace(stackTraceId, threadId, stackFrames);
406cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (strict) {
407cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            hprofData.addStackTrace(stackTrace, new int[1]);
408cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        } else {
409cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // The RI can have duplicate stacks, presumably they
410cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // have a minor race if two samples with the same
411cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // stack are taken around the same time. if we have a
412cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // duplicate, just skip adding it to hprofData, but
413cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // register it locally in idToStackFrame. if it seen
414cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // in CPU_SAMPLES, we will find a StackTrace is equal
415cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            // to the first, so they will share a countCell.
416cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int[] countCell = stackTraces.get(stackTrace);
417cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (countCell == null) {
418cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                hprofData.addStackTrace(stackTrace, new int[1]);
419cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
420cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
421cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
422cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        HprofData.StackTrace old = idToStackTrace.put(stackTraceId, stackTrace);
423cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (old != null) {
424cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Duplicate stack trace id: " + stackTraceId);
425cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
426cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
427cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
428cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
429cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private void parseCpuSamples(int recordLength) throws IOException {
430cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int totalSamples = in.readInt();
431cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int samplesCount = in.readInt();
432cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (TRACE) {
433cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\ttotalSamples=" + totalSamples);
434cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            System.out.println("\tsamplesCount=" + samplesCount);
435cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
436cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int expectedLength = 4 + 4 + (samplesCount * (4 + 4));
437cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (recordLength != expectedLength) {
438cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Expected CPU samples record of size "
439cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + expectedLength
440cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + " based on number of samples but header "
441cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + "specified a length of  " + recordLength);
442cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
443cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int total = 0;
444cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (int i = 0; i < samplesCount; i++) {
445cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int count = in.readInt();
446cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int stackTraceId = in.readInt();
447cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (TRACE) {
448cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                System.out.println("\tcount=" + count);
449cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                System.out.println("\tstackTraceId=" + stackTraceId);
450cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
451cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            HprofData.StackTrace stackTrace = idToStackTrace.get(stackTraceId);
452cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (stackTrace == null) {
453cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new MalformedHprofException("Unknown stack trace id " + stackTraceId);
454cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
455cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (count == 0) {
456cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new MalformedHprofException("Zero sample count for stack trace "
457cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                  + stackTrace);
458cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
459cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int[] countCell = stackTraces.get(stackTrace);
460cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (strict) {
461cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                if (countCell[0] != 0) {
462cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    throw new MalformedHprofException("Setting sample count of stack trace "
463cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                      + stackTrace + " to " + count
464cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                      + " found it was already initialized to "
465cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                      + countCell[0]);
466cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                }
467cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            } else {
468cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // Coalesce counts from duplicate stack traces.
469cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // For more on this, see comments in parseStackTrace.
470cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                count += countCell[0];
471cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
472cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            countCell[0] = count;
473cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            total += count;
474cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
475cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (strict && totalSamples != total) {
476cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new MalformedHprofException("Expected a total of " + totalSamples
477cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                              + " samples but saw " + total);
478cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
479cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
480cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom}
481