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.util.ArrayList;
20cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Arrays;
21cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Collections;
22cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.HashMap;
23cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.HashSet;
24cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.List;
25cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Map.Entry;
26cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Map;
27cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstromimport java.util.Set;
28cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
29cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom/**
30cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * Represents sampling profiler data. Can be converted to ASCII or
31cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * binary hprof-style output using {@link AsciiHprofWriter} or
32cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * {@link BinaryHprofWriter}.
33cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <p>
34cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * The data includes:
35cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <ul>
36cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <li>the start time of the last sampling period
37cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <li>the history of thread start and end events
38cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <li>stack traces with frequency counts
39cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom * <ul>
40cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom */
41cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrompublic final class HprofData {
42cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
43cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public static enum ThreadEventType { START, END };
44cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
45cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
46cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * ThreadEvent represents thread creation and death events for
47cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * reporting. It provides a record of the thread and thread group
48cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * names for tying samples back to their source thread.
49cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
50cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public static final class ThreadEvent {
51cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
52cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final ThreadEventType type;
53cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final int objectId;
54cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final int threadId;
55cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final String threadName;
56cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final String groupName;
57cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final String parentGroupName;
58cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
59cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public static ThreadEvent start(int objectId, int threadId, String threadName,
60cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                        String groupName, String parentGroupName) {
61cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return new ThreadEvent(ThreadEventType.START, objectId, threadId,
62cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                   threadName, groupName, parentGroupName);
63cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
64cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
65cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public static ThreadEvent end(int threadId) {
66cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return new ThreadEvent(ThreadEventType.END, threadId);
67cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
68cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
69cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        private ThreadEvent(ThreadEventType type, int objectId, int threadId,
70cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                            String threadName, String groupName, String parentGroupName) {
71cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (threadName == null) {
72cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new NullPointerException("threadName == null");
73cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
74cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.type = ThreadEventType.START;
75cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.objectId = objectId;
76cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.threadId = threadId;
77cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.threadName = threadName;
78cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.groupName = groupName;
79cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.parentGroupName = parentGroupName;
80cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
81cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
82cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        private ThreadEvent(ThreadEventType type, int threadId) {
83cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.type = ThreadEventType.END;
84cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.objectId = -1;
85cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.threadId = threadId;
86cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.threadName = null;
87cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.groupName = null;
88cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.parentGroupName = null;
89cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
90cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
91cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public int hashCode() {
92cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int result = 17;
93cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + objectId;
94cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + threadId;
95cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + hashCode(threadName);
96cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + hashCode(groupName);
97cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + hashCode(parentGroupName);
98cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return result;
99cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
100cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
101cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        private static int hashCode(Object o) {
102cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return (o == null) ? 0 : o.hashCode();
103cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
104cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
105cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public boolean equals(Object o) {
106cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (!(o instanceof ThreadEvent)) {
107cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return false;
108cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
109cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            ThreadEvent event = (ThreadEvent) o;
110cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return (this.type == event.type
111cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    && this.objectId == event.objectId
112cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    && this.threadId == event.threadId
113cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    && equal(this.threadName, event.threadName)
114cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    && equal(this.groupName, event.groupName)
115cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    && equal(this.parentGroupName, event.parentGroupName));
116cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
117cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
118cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        private static boolean equal(Object a, Object b) {
119cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return a == b || (a != null && a.equals(b));
120cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
121cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
122cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public String toString() {
123cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            switch (type) {
124cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                case START:
125cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    return String.format(
126cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                            "THREAD START (obj=%d, id = %d, name=\"%s\", group=\"%s\")",
127cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                            objectId, threadId, threadName, groupName);
128cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                case END:
129cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    return String.format("THREAD END (id = %d)", threadId);
130cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
131cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalStateException(type.toString());
132cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
133cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
134cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
135cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
136cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * A unique stack trace for a specific thread.
137cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
138cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public static final class StackTrace {
139cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
140cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final int stackTraceId;
141cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int threadId;
142cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        StackTraceElement[] stackFrames;
143cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
144cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        StackTrace() {
145cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.stackTraceId = -1;
146cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
147cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
148cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public StackTrace(int stackTraceId, int threadId, StackTraceElement[] stackFrames) {
149cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (stackFrames == null) {
150cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new NullPointerException("stackFrames == null");
151cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
152cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.stackTraceId = stackTraceId;
153cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.threadId = threadId;
154cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.stackFrames = stackFrames;
155cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
156cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
157cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public int getThreadId() {
158cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return threadId;
159cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
160cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
161cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public StackTraceElement[] getStackFrames() {
162cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return stackFrames;
163cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
164cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
165cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public int hashCode() {
166cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int result = 17;
167cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + threadId;
168cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + Arrays.hashCode(stackFrames);
169cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return result;
170cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
171cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
172cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public boolean equals(Object o) {
173cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (!(o instanceof StackTrace)) {
174cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return false;
175cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
176cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            StackTrace s = (StackTrace) o;
177cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return threadId == s.threadId && Arrays.equals(stackFrames, s.stackFrames);
178cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
179cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
180cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public String toString() {
181cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            StringBuilder frames = new StringBuilder();
182cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (stackFrames.length > 0) {
183cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                frames.append('\n');
184cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                for (StackTraceElement stackFrame : stackFrames) {
185cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    frames.append("\t at ");
186cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    frames.append(stackFrame);
187cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    frames.append('\n');
188cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                }
189cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            } else {
190cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                frames.append("<empty>");
191cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
192cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return "StackTrace[stackTraceId=" + stackTraceId
193cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    + ", threadId=" + threadId
194cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    + ", frames=" + frames + "]";
195cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
196cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
197cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
198cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
199cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
200cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * A read only container combining a stack trace with its frequency.
201cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
202cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public static final class Sample {
203cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
204cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final StackTrace stackTrace;
205cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        public final int count;
206cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
207cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        private Sample(StackTrace stackTrace, int count) {
208cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (stackTrace == null) {
209cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new NullPointerException("stackTrace == null");
210cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
211cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (count < 0) {
212cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                throw new IllegalArgumentException("count < 0:" + count);
213cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
214cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.stackTrace = stackTrace;
215cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            this.count = count;
216cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
217cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
218cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public int hashCode() {
219cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int result = 17;
220cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + stackTrace.hashCode();
221cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            result = 31 * result + count;
222cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return result;
223cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
224cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
225cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public boolean equals(Object o) {
226cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            if (!(o instanceof Sample)) {
227cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                return false;
228cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            }
229cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            Sample s = (Sample) o;
230cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return count == s.count && stackTrace.equals(s.stackTrace);
231cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
232cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
233cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        @Override public String toString() {
234cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            return "Sample[count=" + count + " " + stackTrace + "]";
235cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
236cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
237cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
238cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
239cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
240cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Start of last sampling period.
241cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
242cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private long startMillis;
243cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
244cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
245cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * CONTROL_SETTINGS flags
246cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
247cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int flags;
248cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
249cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
250cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * stack sampling depth
251cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
252cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private int depth;
253cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
254cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
255cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * List of thread creation and death events.
256cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
257cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final List<ThreadEvent> threadHistory = new ArrayList<ThreadEvent>();
258cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
259cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
260cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Map of thread id to a start ThreadEvent
261cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
262cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<Integer, ThreadEvent> threadIdToThreadEvent
263cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            = new HashMap<Integer, ThreadEvent>();
264cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
265cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
266cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Map of stack traces to a mutable sample count. The map is
267cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * provided by the creator of the HprofData so only have
268cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * mutable access to the int[] cells that contain the sample
269cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * count. Only an unmodifiable iterator view is available to
270cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * users of the HprofData.
271cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
272cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    private final Map<HprofData.StackTrace, int[]> stackTraces;
273cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
274cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public HprofData(Map<StackTrace, int[]> stackTraces) {
275cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (stackTraces == null) {
276cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new NullPointerException("stackTraces == null");
277cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
278cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.stackTraces = stackTraces;
279cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
280cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
281cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
282cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * The start time in milliseconds of the last profiling period.
283cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
284cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public long getStartMillis() {
285cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return startMillis;
286cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
287cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
288cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
289cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Set the time for the start of the current sampling period.
290cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
291cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void setStartMillis(long startMillis) {
292cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.startMillis = startMillis;
293cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
294cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
295cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
296cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Get the {@link BinaryHprof.ControlSettings} flags
297cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
298cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public int getFlags() {
299cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return flags;
300cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
301cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
302cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
303cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Set the {@link BinaryHprof.ControlSettings} flags
304cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
305cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void setFlags(int flags) {
306cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.flags = flags;
307cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
308cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
309cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
310cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Get the stack sampling depth
311cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
312cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public int getDepth() {
313cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return depth;
314cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
315cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
316cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
317cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Set the stack sampling depth
318cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
319cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void setDepth(int depth) {
320cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        this.depth = depth;
321cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
322cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
323cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
324cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Return an unmodifiable history of start and end thread events.
325cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
326cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public List<ThreadEvent> getThreadHistory() {
327cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return Collections.unmodifiableList(threadHistory);
328cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
329cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
330cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
331cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Return a new set containing the current sample data.
332cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
333cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public Set<Sample> getSamples() {
334cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        Set<Sample> samples = new HashSet<Sample>(stackTraces.size());
335cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        for (Entry<StackTrace, int[]> e : stackTraces.entrySet()) {
336cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            StackTrace stackTrace = e.getKey();
337cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int countCell[] = e.getValue();
338cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            int count = countCell[0];
339cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            Sample sample = new Sample(stackTrace, count);
340cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            samples.add(sample);
341cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
342cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        return samples;
343cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
344cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
345cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
346cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Record an event in the thread history.
347cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
348cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void addThreadEvent(ThreadEvent event) {
349cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (event == null) {
350cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new NullPointerException("event == null");
351cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
352cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        ThreadEvent old = threadIdToThreadEvent.put(event.threadId, event);
353cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        switch (event.type) {
354cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case START:
355cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                if (old != null) {
356cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    throw new IllegalArgumentException("ThreadEvent already registered for id "
357cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                       + event.threadId);
358cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                }
359cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                break;
360cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            case END:
361cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // Do not assert that the END_THREAD matches a
362cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // START_THREAD unless in strict mode. While thhis
363cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // hold true in the binary hprof BinaryHprofWriter
364cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // produces, it is not true of hprof files created
365cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // by the RI. However, if there is an event
366cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // already registed for a thread id, it should be
367cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                // the matching start, not a duplicate end.
368cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                if (old != null && old.type == ThreadEventType.END) {
369cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                    throw new IllegalArgumentException("Duplicate ThreadEvent.end for id "
370cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                                       + event.threadId);
371cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                }
372cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                break;
373cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
374cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        threadHistory.add(event);
375cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
376cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom
377cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    /**
378cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * Record an stack trace and an associated int[] cell of
379cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * sample cound for the stack trace. The caller is allowed
380cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * retain a pointer to the cell to update the count. The
381cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * SamplingProfiler intentionally does not present a mutable
382cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     * view of the count.
383cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom     */
384cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    public void addStackTrace(StackTrace stackTrace, int[] countCell) {
385cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (!threadIdToThreadEvent.containsKey(stackTrace.threadId)) {
386cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalArgumentException("Unknown thread id " + stackTrace.threadId);
387cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
388cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        int[] old = stackTraces.put(stackTrace, countCell);
389cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        if (old != null) {
390cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom            throw new IllegalArgumentException("StackTrace already registered for id "
391cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom                                               + stackTrace.stackTraceId + ":\n" + stackTrace);
392cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom        }
393cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom    }
394cfa84a2aac159bb8a1763298882df7aa98f7fc6fBrian Carlstrom}
395