Home | History | Annotate | Download | only in util
      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