Home | History | Annotate | Download | only in file
      1 /*
      2  * Copyright (C) 2007 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.dexgen.dex.file;
     18 
     19 import com.android.dexgen.util.AnnotatedOutput;
     20 
     21 import java.util.Collection;
     22 import java.util.HashMap;
     23 import java.util.TreeMap;
     24 
     25 /**
     26  * Statistics about the contents of a file.
     27  */
     28 public final class Statistics {
     29     /** {@code non-null;} data about each type of item */
     30     private final HashMap<String, Data> dataMap;
     31 
     32     /**
     33      * Constructs an instance.
     34      */
     35     public Statistics() {
     36         dataMap = new HashMap<String, Data>(50);
     37     }
     38 
     39     /**
     40      * Adds the given item to the statistics.
     41      *
     42      * @param item {@code non-null;} the item to add
     43      */
     44     public void add(Item item) {
     45         String typeName = item.typeName();
     46         Data data = dataMap.get(typeName);
     47 
     48         if (data == null) {
     49             dataMap.put(typeName, new Data(item, typeName));
     50         } else {
     51             data.add(item);
     52         }
     53     }
     54 
     55     /**
     56      * Adds the given list of items to the statistics.
     57      *
     58      * @param list {@code non-null;} the list of items to add
     59      */
     60     public void addAll(Section list) {
     61         Collection<? extends Item> items = list.items();
     62         for (Item item : items) {
     63             add(item);
     64         }
     65     }
     66 
     67     /**
     68      * Writes the statistics as an annotation.
     69      *
     70      * @param out {@code non-null;} where to write to
     71      */
     72     public final void writeAnnotation(AnnotatedOutput out) {
     73         if (dataMap.size() == 0) {
     74             return;
     75         }
     76 
     77         out.annotate(0, "\nstatistics:\n");
     78 
     79         TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
     80 
     81         for (Data data : dataMap.values()) {
     82             sortedData.put(data.name, data);
     83         }
     84 
     85         for (Data data : sortedData.values()) {
     86             data.writeAnnotation(out);
     87         }
     88     }
     89 
     90     public String toHuman() {
     91         StringBuilder sb = new StringBuilder();
     92 
     93         sb.append("Statistics:\n");
     94 
     95         TreeMap<String, Data> sortedData = new TreeMap<String, Data>();
     96 
     97         for (Data data : dataMap.values()) {
     98             sortedData.put(data.name, data);
     99         }
    100 
    101         for (Data data : sortedData.values()) {
    102             sb.append(data.toHuman());
    103         }
    104 
    105         return sb.toString();
    106     }
    107 
    108     /**
    109      * Statistical data about a particular class.
    110      */
    111     private static class Data {
    112         /** {@code non-null;} name to use as a label */
    113         private final String name;
    114 
    115         /** {@code >= 0;} number of instances */
    116         private int count;
    117 
    118         /** {@code >= 0;} total size of instances in bytes */
    119         private int totalSize;
    120 
    121         /** {@code >= 0;} largest size of any individual item */
    122         private int largestSize;
    123 
    124         /** {@code >= 0;} smallest size of any individual item */
    125         private int smallestSize;
    126 
    127         /**
    128          * Constructs an instance for the given item.
    129          *
    130          * @param item {@code non-null;} item in question
    131          * @param name {@code non-null;} type name to use
    132          */
    133         public Data(Item item, String name) {
    134             int size = item.writeSize();
    135 
    136             this.name = name;
    137             this.count = 1;
    138             this.totalSize = size;
    139             this.largestSize = size;
    140             this.smallestSize = size;
    141         }
    142 
    143         /**
    144          * Incorporates a new item. This assumes the type name matches.
    145          *
    146          * @param item {@code non-null;} item to incorporate
    147          */
    148         public void add(Item item) {
    149             int size = item.writeSize();
    150 
    151             count++;
    152             totalSize += size;
    153 
    154             if (size > largestSize) {
    155                 largestSize = size;
    156             }
    157 
    158             if (size < smallestSize) {
    159                 smallestSize = size;
    160             }
    161         }
    162 
    163         /**
    164          * Writes this instance as an annotation.
    165          *
    166          * @param out {@code non-null;} where to write to
    167          */
    168         public void writeAnnotation(AnnotatedOutput out) {
    169             out.annotate(toHuman());
    170         }
    171 
    172         /**
    173          * Generates a human-readable string for this data item.
    174          *
    175          * @return string for human consumption.
    176          */
    177         public String toHuman() {
    178             StringBuilder sb = new StringBuilder();
    179 
    180             sb.append("  " + name + ": " +
    181                          count + " item" + (count == 1 ? "" : "s") + "; " +
    182                          totalSize + " bytes total\n");
    183 
    184             if (smallestSize == largestSize) {
    185                 sb.append("    " + smallestSize + " bytes/item\n");
    186             } else {
    187                 int average = totalSize / count;
    188                 sb.append("    " + smallestSize + ".." + largestSize +
    189                              " bytes/item; average " + average + "\n");
    190             }
    191 
    192             return sb.toString();
    193         }
    194     }
    195 }
    196