13d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang/*
23d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * Copyright (C) 2012 The Android Open Source Project
33d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang *
43d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * Licensed under the Apache License, Version 2.0 (the "License");
53d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * you may not use this file except in compliance with the License.
63d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * You may obtain a copy of the License at
73d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang *
83d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang *      http://www.apache.org/licenses/LICENSE-2.0
93d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang *
103d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * Unless required by applicable law or agreed to in writing, software
113d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * distributed under the License is distributed on an "AS IS" BASIS,
123d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
133d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * See the License for the specific language governing permissions and
143d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang * limitations under the License.
153d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang */
163d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
173d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changpackage com.android.gallery3d.util;
183d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
193d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport android.util.Log;
203d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
212b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Linimport com.android.gallery3d.common.Utils;
222b3ee0ea07246b859a5b75d8a6102a7cce7ec838Owen Lin
233d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.io.DataOutputStream;
243d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.io.FileOutputStream;
253d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.io.IOException;
263d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.util.ArrayList;
273d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.util.HashMap;
283d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changimport java.util.Map.Entry;
293d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
303d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang// ProfileData keeps profiling samples in a tree structure.
313d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang// The addSample() method adds a sample. The dumpToFile() method saves the data
323d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang// to a file. The reset() method clears all samples.
333d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Changpublic class ProfileData {
347817979db0c52ffeacb951625b1e821eba303285Ahbong Chang    @SuppressWarnings("unused")
353d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private static final String TAG = "ProfileData";
363d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
373d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private static class Node {
383d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        public int id;  // this is the name of this node, mapped from mNameToId
393d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        public Node parent;
403d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        public int sampleCount;
413d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        public ArrayList<Node> children;
423d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        public Node(Node parent, int id) {
433d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            this.parent = parent;
443d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            this.id = id;
453d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
463d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
473d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
483d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private Node mRoot;
493d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private int mNextId;
503d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private HashMap<String, Integer> mNameToId;
513d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private DataOutputStream mOut;
523d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private byte mScratch[] = new byte[4];  // scratch space for writeInt()
533d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
543d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public ProfileData() {
553d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mRoot = new Node(null, -1);  // The id of the root node is unused.
563d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mNameToId = new HashMap<String, Integer>();
573d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
583d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
593d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public void reset() {
603d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mRoot = new Node(null, -1);
613d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mNameToId.clear();
623d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mNextId = 0;
633d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
643d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
653d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private int nameToId(String name) {
663d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        Integer id = mNameToId.get(name);
673d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (id == null) {
683d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            id = ++mNextId;  // The tool doesn't want id=0, so we start from 1.
693d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            mNameToId.put(name, id);
703d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
713d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        return id;
723d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
733d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
743d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public void addSample(String[] stack) {
753d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        int[] ids = new int[stack.length];
763d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        for (int i = 0; i < stack.length; i++) {
773d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            ids[i] = nameToId(stack[i]);
783d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
793d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
803d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        Node node = mRoot;
813d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        for (int i = stack.length - 1; i >= 0; i--) {
823d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            if (node.children == null) {
833d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                node.children = new ArrayList<Node>();
843d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            }
853d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
863d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            int id = ids[i];
873d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            ArrayList<Node> children = node.children;
883d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            int j;
893d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            for (j = 0; j < children.size(); j++) {
903d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                if (children.get(j).id == id) break;
913d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            }
923d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            if (j == children.size()) {
933d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                children.add(new Node(node, id));
943d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            }
953d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
963d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            node = children.get(j);
973d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
983d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
993d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        node.sampleCount++;
1003d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1013d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1023d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    public void dumpToFile(String filename) {
1033d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        try {
1043d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            mOut = new DataOutputStream(new FileOutputStream(filename));
1053d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            // Start record
1063d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(0);
1073d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(3);
1083d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(1);
1093d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(20000);  // Sampling period: 20ms
1103d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(0);
1113d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1123d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            // Samples
1133d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeAllStacks(mRoot, 0);
1143d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1153d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            // End record
1163d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(0);
1173d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(1);
1183d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(0);
1193d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeAllSymbols();
1203d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        } catch (IOException ex) {
1213d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Log.w("Failed to dump to file", ex);
1223d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        } finally {
1233d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            Utils.closeSilently(mOut);
1243d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
1253d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1263d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1273d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // Writes out one stack, consisting of N+2 words:
1283d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // first word: sample count
1293d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // second word: depth of the stack (N)
1303d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // N words: each word is the id of one address in the stack
1313d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private void writeOneStack(Node node, int depth) throws IOException {
1323d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        writeInt(node.sampleCount);
1333d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        writeInt(depth);
1343d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        while (depth-- > 0) {
1353d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeInt(node.id);
1363d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            node = node.parent;
1373d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
1383d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1393d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1403d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private void writeAllStacks(Node node, int depth) throws IOException {
1413d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (node.sampleCount > 0) {
1423d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            writeOneStack(node, depth);
1433d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
1443d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1453d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        ArrayList<Node> children = node.children;
1463d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        if (children != null) {
1473d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            for (int i = 0; i < children.size(); i++) {
1483d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang                writeAllStacks(children.get(i), depth + 1);
1493d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            }
1503d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
1513d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1523d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1533d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // Writes out the symbol table. Each line is like:
1543d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    // 0x17e java.util.ArrayList.isEmpty(ArrayList.java:319)
1553d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private void writeAllSymbols() throws IOException {
1563d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        for (Entry<String, Integer> entry : mNameToId.entrySet()) {
1573d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang            mOut.writeBytes(String.format("0x%x %s\n", entry.getValue(), entry.getKey()));
1583d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        }
1593d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1603d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang
1613d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    private void writeInt(int v) throws IOException {
1623d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mScratch[0] = (byte) v;
1633d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mScratch[1] = (byte) (v >> 8);
1643d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mScratch[2] = (byte) (v >> 16);
1653d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mScratch[3] = (byte) (v >> 24);
1663d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang        mOut.write(mScratch);
1673d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang    }
1683d238a7a19b1010578709c63f86e12b2bce0e4fcChih-Chung Chang}
169