• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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