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 @SuppressWarnings("unused") 35 private static final String TAG = "ProfileData"; 36 37 private static class Node { 38 public int id; // this is the name of this node, mapped from mNameToId 39 public Node parent; 40 public int sampleCount; 41 public ArrayList<Node> children; 42 public Node(Node parent, int id) { 43 this.parent = parent; 44 this.id = id; 45 } 46 } 47 48 private Node mRoot; 49 private int mNextId; 50 private HashMap<String, Integer> mNameToId; 51 private DataOutputStream mOut; 52 private byte mScratch[] = new byte[4]; // scratch space for writeInt() 53 54 public ProfileData() { 55 mRoot = new Node(null, -1); // The id of the root node is unused. 56 mNameToId = new HashMap<String, Integer>(); 57 } 58 59 public void reset() { 60 mRoot = new Node(null, -1); 61 mNameToId.clear(); 62 mNextId = 0; 63 } 64 65 private int nameToId(String name) { 66 Integer id = mNameToId.get(name); 67 if (id == null) { 68 id = ++mNextId; // The tool doesn't want id=0, so we start from 1. 69 mNameToId.put(name, id); 70 } 71 return id; 72 } 73 74 public void addSample(String[] stack) { 75 int[] ids = new int[stack.length]; 76 for (int i = 0; i < stack.length; i++) { 77 ids[i] = nameToId(stack[i]); 78 } 79 80 Node node = mRoot; 81 for (int i = stack.length - 1; i >= 0; i--) { 82 if (node.children == null) { 83 node.children = new ArrayList<Node>(); 84 } 85 86 int id = ids[i]; 87 ArrayList<Node> children = node.children; 88 int j; 89 for (j = 0; j < children.size(); j++) { 90 if (children.get(j).id == id) break; 91 } 92 if (j == children.size()) { 93 children.add(new Node(node, id)); 94 } 95 96 node = children.get(j); 97 } 98 99 node.sampleCount++; 100 } 101 102 public void dumpToFile(String filename) { 103 try { 104 mOut = new DataOutputStream(new FileOutputStream(filename)); 105 // Start record 106 writeInt(0); 107 writeInt(3); 108 writeInt(1); 109 writeInt(20000); // Sampling period: 20ms 110 writeInt(0); 111 112 // Samples 113 writeAllStacks(mRoot, 0); 114 115 // End record 116 writeInt(0); 117 writeInt(1); 118 writeInt(0); 119 writeAllSymbols(); 120 } catch (IOException ex) { 121 Log.w("Failed to dump to file", ex); 122 } finally { 123 Utils.closeSilently(mOut); 124 } 125 } 126 127 // Writes out one stack, consisting of N+2 words: 128 // first word: sample count 129 // second word: depth of the stack (N) 130 // N words: each word is the id of one address in the stack 131 private void writeOneStack(Node node, int depth) throws IOException { 132 writeInt(node.sampleCount); 133 writeInt(depth); 134 while (depth-- > 0) { 135 writeInt(node.id); 136 node = node.parent; 137 } 138 } 139 140 private void writeAllStacks(Node node, int depth) throws IOException { 141 if (node.sampleCount > 0) { 142 writeOneStack(node, depth); 143 } 144 145 ArrayList<Node> children = node.children; 146 if (children != null) { 147 for (int i = 0; i < children.size(); i++) { 148 writeAllStacks(children.get(i), depth + 1); 149 } 150 } 151 } 152 153 // Writes out the symbol table. Each line is like: 154 // 0x17e java.util.ArrayList.isEmpty(ArrayList.java:319) 155 private void writeAllSymbols() throws IOException { 156 for (Entry<String, Integer> entry : mNameToId.entrySet()) { 157 mOut.writeBytes(String.format("0x%x %s\n", entry.getValue(), entry.getKey())); 158 } 159 } 160 161 private void writeInt(int v) throws IOException { 162 mScratch[0] = (byte) v; 163 mScratch[1] = (byte) (v >> 8); 164 mScratch[2] = (byte) (v >> 16); 165 mScratch[3] = (byte) (v >> 24); 166 mOut.write(mScratch); 167 } 168 } 169