| /* |
| * 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); |
| } |
| } |