1 /* 2 * Copyright (C) 2012 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package com.android.gallery3d.util; 18 19 import android.util.Log; 20 21 import com.android.gallery3d.common.Utils; 22 23 import java.io.DataOutputStream; 24 import java.io.FileOutputStream; 25 import java.io.IOException; 26 import java.util.ArrayList; 27 import java.util.HashMap; 28 import java.util.Map.Entry; 29 30 // ProfileData keeps profiling samples in a tree structure. 31 // The addSample() method adds a sample. The dumpToFile() method saves the data 32 // to a file. The reset() method clears all samples. 33 public class ProfileData { 34 private static final String TAG = "ProfileData"; 35 36 private static class Node { 37 public int id; // this is the name of this node, mapped from mNameToId 38 public Node parent; 39 public int sampleCount; 40 public ArrayList<Node> children; Node(Node parent, int id)41 public Node(Node parent, int id) { 42 this.parent = parent; 43 this.id = id; 44 } 45 } 46 47 private Node mRoot; 48 private int mNextId; 49 private HashMap<String, Integer> mNameToId; 50 private DataOutputStream mOut; 51 private byte mScratch[] = new byte[4]; // scratch space for writeInt() 52 ProfileData()53 public ProfileData() { 54 mRoot = new Node(null, -1); // The id of the root node is unused. 55 mNameToId = new HashMap<String, Integer>(); 56 } 57 reset()58 public void reset() { 59 mRoot = new Node(null, -1); 60 mNameToId.clear(); 61 mNextId = 0; 62 } 63 nameToId(String name)64 private int nameToId(String name) { 65 Integer id = mNameToId.get(name); 66 if (id == null) { 67 id = ++mNextId; // The tool doesn't want id=0, so we start from 1. 68 mNameToId.put(name, id); 69 } 70 return id; 71 } 72 addSample(String[] stack)73 public void addSample(String[] stack) { 74 int[] ids = new int[stack.length]; 75 for (int i = 0; i < stack.length; i++) { 76 ids[i] = nameToId(stack[i]); 77 } 78 79 Node node = mRoot; 80 for (int i = stack.length - 1; i >= 0; i--) { 81 if (node.children == null) { 82 node.children = new ArrayList<Node>(); 83 } 84 85 int id = ids[i]; 86 ArrayList<Node> children = node.children; 87 int j; 88 for (j = 0; j < children.size(); j++) { 89 if (children.get(j).id == id) break; 90 } 91 if (j == children.size()) { 92 children.add(new Node(node, id)); 93 } 94 95 node = children.get(j); 96 } 97 98 node.sampleCount++; 99 } 100 dumpToFile(String filename)101 public void dumpToFile(String filename) { 102 try { 103 mOut = new DataOutputStream(new FileOutputStream(filename)); 104 // Start record 105 writeInt(0); 106 writeInt(3); 107 writeInt(1); 108 writeInt(20000); // Sampling period: 20ms 109 writeInt(0); 110 111 // Samples 112 writeAllStacks(mRoot, 0); 113 114 // End record 115 writeInt(0); 116 writeInt(1); 117 writeInt(0); 118 writeAllSymbols(); 119 } catch (IOException ex) { 120 Log.w("Failed to dump to file", ex); 121 } finally { 122 Utils.closeSilently(mOut); 123 } 124 } 125 126 // Writes out one stack, consisting of N+2 words: 127 // first word: sample count 128 // second word: depth of the stack (N) 129 // N words: each word is the id of one address in the stack writeOneStack(Node node, int depth)130 private void writeOneStack(Node node, int depth) throws IOException { 131 writeInt(node.sampleCount); 132 writeInt(depth); 133 while (depth-- > 0) { 134 writeInt(node.id); 135 node = node.parent; 136 } 137 } 138 writeAllStacks(Node node, int depth)139 private void writeAllStacks(Node node, int depth) throws IOException { 140 if (node.sampleCount > 0) { 141 writeOneStack(node, depth); 142 } 143 144 ArrayList<Node> children = node.children; 145 if (children != null) { 146 for (int i = 0; i < children.size(); i++) { 147 writeAllStacks(children.get(i), depth + 1); 148 } 149 } 150 } 151 152 // Writes out the symbol table. Each line is like: 153 // 0x17e java.util.ArrayList.isEmpty(ArrayList.java:319) writeAllSymbols()154 private void writeAllSymbols() throws IOException { 155 for (Entry<String, Integer> entry : mNameToId.entrySet()) { 156 mOut.writeBytes(String.format("0x%x %s\n", entry.getValue(), entry.getKey())); 157 } 158 } 159 writeInt(int v)160 private void writeInt(int v) throws IOException { 161 mScratch[0] = (byte) v; 162 mScratch[1] = (byte) (v >> 8); 163 mScratch[2] = (byte) (v >> 16); 164 mScratch[3] = (byte) (v >> 24); 165 mOut.write(mScratch); 166 } 167 } 168