summaryrefslogtreecommitdiffstats
path: root/src/com/android/gallery3d/util/ProfileData.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/com/android/gallery3d/util/ProfileData.java')
-rw-r--r--src/com/android/gallery3d/util/ProfileData.java168
1 files changed, 168 insertions, 0 deletions
diff --git a/src/com/android/gallery3d/util/ProfileData.java b/src/com/android/gallery3d/util/ProfileData.java
new file mode 100644
index 000000000..a1bb8e1e4
--- /dev/null
+++ b/src/com/android/gallery3d/util/ProfileData.java
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2012 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.gallery3d.util;
+
+import android.util.Log;
+
+import com.android.gallery3d.common.Utils;
+
+import java.io.DataOutputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Map.Entry;
+
+// ProfileData keeps profiling samples in a tree structure.
+// The addSample() method adds a sample. The dumpToFile() method saves the data
+// to a file. The reset() method clears all samples.
+public class ProfileData {
+ @SuppressWarnings("unused")
+ private static final String TAG = "ProfileData";
+
+ private static class Node {
+ public int id; // this is the name of this node, mapped from mNameToId
+ public Node parent;
+ public int sampleCount;
+ public ArrayList<Node> children;
+ public Node(Node parent, int id) {
+ this.parent = parent;
+ this.id = id;
+ }
+ }
+
+ private Node mRoot;
+ private int mNextId;
+ private HashMap<String, Integer> mNameToId;
+ private DataOutputStream mOut;
+ private byte mScratch[] = new byte[4]; // scratch space for writeInt()
+
+ public ProfileData() {
+ mRoot = new Node(null, -1); // The id of the root node is unused.
+ mNameToId = new HashMap<String, Integer>();
+ }
+
+ public void reset() {
+ mRoot = new Node(null, -1);
+ mNameToId.clear();
+ mNextId = 0;
+ }
+
+ private int nameToId(String name) {
+ Integer id = mNameToId.get(name);
+ if (id == null) {
+ id = ++mNextId; // The tool doesn't want id=0, so we start from 1.
+ mNameToId.put(name, id);
+ }
+ return id;
+ }
+
+ public void addSample(String[] stack) {
+ int[] ids = new int[stack.length];
+ for (int i = 0; i < stack.length; i++) {
+ ids[i] = nameToId(stack[i]);
+ }
+
+ Node node = mRoot;
+ for (int i = stack.length - 1; i >= 0; i--) {
+ if (node.children == null) {
+ node.children = new ArrayList<Node>();
+ }
+
+ int id = ids[i];
+ ArrayList<Node> children = node.children;
+ int j;
+ for (j = 0; j < children.size(); j++) {
+ if (children.get(j).id == id) break;
+ }
+ if (j == children.size()) {
+ children.add(new Node(node, id));
+ }
+
+ node = children.get(j);
+ }
+
+ node.sampleCount++;
+ }
+
+ public void dumpToFile(String filename) {
+ try {
+ mOut = new DataOutputStream(new FileOutputStream(filename));
+ // Start record
+ writeInt(0);
+ writeInt(3);
+ writeInt(1);
+ writeInt(20000); // Sampling period: 20ms
+ writeInt(0);
+
+ // Samples
+ writeAllStacks(mRoot, 0);
+
+ // End record
+ writeInt(0);
+ writeInt(1);
+ writeInt(0);
+ writeAllSymbols();
+ } catch (IOException ex) {
+ Log.w("Failed to dump to file", ex);
+ } finally {
+ Utils.closeSilently(mOut);
+ }
+ }
+
+ // Writes out one stack, consisting of N+2 words:
+ // first word: sample count
+ // second word: depth of the stack (N)
+ // N words: each word is the id of one address in the stack
+ private void writeOneStack(Node node, int depth) throws IOException {
+ writeInt(node.sampleCount);
+ writeInt(depth);
+ while (depth-- > 0) {
+ writeInt(node.id);
+ node = node.parent;
+ }
+ }
+
+ private void writeAllStacks(Node node, int depth) throws IOException {
+ if (node.sampleCount > 0) {
+ writeOneStack(node, depth);
+ }
+
+ ArrayList<Node> children = node.children;
+ if (children != null) {
+ for (int i = 0; i < children.size(); i++) {
+ writeAllStacks(children.get(i), depth + 1);
+ }
+ }
+ }
+
+ // Writes out the symbol table. Each line is like:
+ // 0x17e java.util.ArrayList.isEmpty(ArrayList.java:319)
+ private void writeAllSymbols() throws IOException {
+ for (Entry<String, Integer> entry : mNameToId.entrySet()) {
+ mOut.writeBytes(String.format("0x%x %s\n", entry.getValue(), entry.getKey()));
+ }
+ }
+
+ private void writeInt(int v) throws IOException {
+ mScratch[0] = (byte) v;
+ mScratch[1] = (byte) (v >> 8);
+ mScratch[2] = (byte) (v >> 16);
+ mScratch[3] = (byte) (v >> 24);
+ mOut.write(mScratch);
+ }
+}