Home | History | Annotate | Download | only in tilebenchmark
      1 /*
      2  * Copyright (C) 2011 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.test.tilebenchmark;
     18 
     19 import android.content.res.Resources;
     20 import android.graphics.Canvas;
     21 import android.graphics.Color;
     22 import android.graphics.Paint;
     23 import android.graphics.Rect;
     24 import android.graphics.drawable.ShapeDrawable;
     25 
     26 import com.test.tilebenchmark.RunData.TileData;
     27 
     28 import java.util.ArrayList;
     29 import java.util.Arrays;
     30 import java.util.HashMap;
     31 
     32 public class PlaybackGraphs {
     33     private static final int BAR_WIDTH = PlaybackView.TILE_SCALE * 3;
     34     private static final float CANVAS_SCALE = 0.2f;
     35     private static final double IDEAL_FRAMES = 60;
     36     private static final int LABELOFFSET = 100;
     37     private static Paint whiteLabels;
     38 
     39     private static double viewportCoverage(TileData view, TileData tile) {
     40         if (tile.left < (view.right * view.scale)
     41                 && tile.right >= (view.left * view.scale)
     42                 && tile.top < (view.bottom * view.scale)
     43                 && tile.bottom >= (view.top * view.scale)) {
     44             return 1.0f;
     45         }
     46         return 0.0f;
     47     }
     48 
     49     protected interface MetricGen {
     50         public double getValue(TileData[] frame);
     51 
     52         public double getMax();
     53 
     54         public int getLabelId();
     55     };
     56 
     57     protected static MetricGen[] Metrics = new MetricGen[] {
     58             new MetricGen() {
     59                 // framerate graph
     60                 @Override
     61                 public double getValue(TileData[] frame) {
     62                     int renderTimeUS = frame[0].level;
     63                     return 1.0e6f / renderTimeUS;
     64                 }
     65 
     66                 @Override
     67                 public double getMax() {
     68                     return IDEAL_FRAMES;
     69                 }
     70 
     71                 @Override
     72                 public int getLabelId() {
     73                     return R.string.frames_per_second;
     74                 }
     75             }, new MetricGen() {
     76                 // coverage graph
     77                 @Override
     78                 public double getValue(TileData[] frame) {
     79                     double total = 0, totalCount = 0;
     80                     for (int tileID = 1; tileID < frame.length; tileID++) {
     81                         TileData data = frame[tileID];
     82                         double coverage = viewportCoverage(frame[0], data);
     83                         total += coverage * (data.isReady ? 100 : 0);
     84                         totalCount += coverage;
     85                     }
     86                     if (totalCount == 0) {
     87                         return -1;
     88                     }
     89                     return total / totalCount;
     90                 }
     91 
     92                 @Override
     93                 public double getMax() {
     94                     return 100;
     95                 }
     96 
     97                 @Override
     98                 public int getLabelId() {
     99                     return R.string.viewport_coverage;
    100                 }
    101             }
    102     };
    103 
    104     protected interface StatGen {
    105         public double getValue(double sortedValues[]);
    106 
    107         public int getLabelId();
    108     }
    109 
    110     public static double getPercentile(double sortedValues[], double ratioAbove) {
    111         if (sortedValues.length == 0)
    112             return -1;
    113 
    114         double index = ratioAbove * (sortedValues.length - 1);
    115         int intIndex = (int) Math.floor(index);
    116         if (index == intIndex) {
    117             return sortedValues[intIndex];
    118         }
    119         double alpha = index - intIndex;
    120         return sortedValues[intIndex] * (1 - alpha)
    121                 + sortedValues[intIndex + 1] * (alpha);
    122     }
    123 
    124     public static double getMean(double sortedValues[]) {
    125         if (sortedValues.length == 0)
    126             return -1;
    127 
    128         double agg = 0;
    129         for (double val : sortedValues) {
    130             agg += val;
    131         }
    132         return agg / sortedValues.length;
    133     }
    134 
    135     public static double getStdDev(double sortedValues[]) {
    136         if (sortedValues.length == 0)
    137             return -1;
    138 
    139         double agg = 0;
    140         double sqrAgg = 0;
    141         for (double val : sortedValues) {
    142             agg += val;
    143             sqrAgg += val*val;
    144         }
    145         double mean = agg / sortedValues.length;
    146         return Math.sqrt((sqrAgg / sortedValues.length) - (mean * mean));
    147     }
    148 
    149     protected static StatGen[] Stats = new StatGen[] {
    150             new StatGen() {
    151                 @Override
    152                 public double getValue(double[] sortedValues) {
    153                     return getPercentile(sortedValues, 0.25);
    154                 }
    155 
    156                 @Override
    157                 public int getLabelId() {
    158                     return R.string.percentile_25;
    159                 }
    160             }, new StatGen() {
    161                 @Override
    162                 public double getValue(double[] sortedValues) {
    163                     return getPercentile(sortedValues, 0.5);
    164                 }
    165 
    166                 @Override
    167                 public int getLabelId() {
    168                     return R.string.percentile_50;
    169                 }
    170             }, new StatGen() {
    171                 @Override
    172                 public double getValue(double[] sortedValues) {
    173                     return getPercentile(sortedValues, 0.75);
    174                 }
    175 
    176                 @Override
    177                 public int getLabelId() {
    178                     return R.string.percentile_75;
    179                 }
    180             }, new StatGen() {
    181                 @Override
    182                 public double getValue(double[] sortedValues) {
    183                     return getStdDev(sortedValues);
    184                 }
    185 
    186                 @Override
    187                 public int getLabelId() {
    188                     return R.string.std_dev;
    189                 }
    190             }, new StatGen() {
    191                 @Override
    192                 public double getValue(double[] sortedValues) {
    193                     return getMean(sortedValues);
    194                 }
    195 
    196                 @Override
    197                 public int getLabelId() {
    198                     return R.string.mean;
    199                 }
    200             },
    201     };
    202 
    203     public PlaybackGraphs() {
    204         whiteLabels = new Paint();
    205         whiteLabels.setColor(Color.WHITE);
    206         whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3);
    207     }
    208 
    209     private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
    210     protected final double[][] mStats = new double[Metrics.length][Stats.length];
    211     protected HashMap<String, Double> mSingleStats;
    212 
    213     private void gatherFrameMetric(int metricIndex, double metricValues[], RunData data) {
    214         // create graph out of rectangles, one per frame
    215         int lastBar = 0;
    216         for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
    217             TileData frame[] = data.frames[frameIndex];
    218             int newBar = (int)((frame[0].top + frame[0].bottom) * frame[0].scale / 2.0f);
    219 
    220             MetricGen s = Metrics[metricIndex];
    221             double absoluteValue = s.getValue(frame);
    222             double relativeValue = absoluteValue / s.getMax();
    223             relativeValue = Math.min(1,relativeValue);
    224             relativeValue = Math.max(0,relativeValue);
    225             int rightPos = (int) (-BAR_WIDTH * metricIndex);
    226             int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
    227 
    228             ShapeDrawable graphBar = new ShapeDrawable();
    229             graphBar.getPaint().setColor(Color.BLUE);
    230             graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
    231 
    232             mShapes.add(graphBar);
    233             metricValues[frameIndex] = absoluteValue;
    234             lastBar = newBar;
    235         }
    236     }
    237 
    238     public void setData(RunData data) {
    239         mShapes.clear();
    240         double metricValues[] = new double[data.frames.length];
    241 
    242         mSingleStats = data.singleStats;
    243 
    244         if (data.frames.length == 0) {
    245             return;
    246         }
    247 
    248         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
    249             // calculate metric based on list of frames
    250             gatherFrameMetric(metricIndex, metricValues, data);
    251 
    252             // store aggregate statistics per metric (median, and similar)
    253             Arrays.sort(metricValues);
    254             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
    255                 mStats[metricIndex][statIndex] =
    256                         Stats[statIndex].getValue(metricValues);
    257             }
    258         }
    259     }
    260 
    261     public void drawVerticalShiftedShapes(Canvas canvas,
    262             ArrayList<ShapeDrawable> shapes) {
    263         // Shapes drawn here are drawn relative to the viewRect
    264         Rect viewRect = shapes.get(shapes.size() - 1).getBounds();
    265         canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top);
    266 
    267         for (ShapeDrawable shape : mShapes) {
    268             shape.draw(canvas);
    269         }
    270         for (ShapeDrawable shape : shapes) {
    271             shape.draw(canvas);
    272         }
    273     }
    274 
    275     public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
    276             ArrayList<String> strings, Resources resources) {
    277         canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
    278 
    279         canvas.translate(BAR_WIDTH * Metrics.length, 0);
    280 
    281         canvas.save();
    282         drawVerticalShiftedShapes(canvas, shapes);
    283         canvas.restore();
    284 
    285         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
    286             String label = resources.getString(
    287                     Metrics[metricIndex].getLabelId());
    288             int xPos = (metricIndex + 1) * -BAR_WIDTH;
    289             int yPos = LABELOFFSET;
    290             canvas.drawText(label, xPos, yPos, whiteLabels);
    291             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
    292                 String statLabel = resources.getString(
    293                         Stats[statIndex].getLabelId()).substring(0,3);
    294                 label = statLabel + " " + resources.getString(
    295                         R.string.format_stat, mStats[metricIndex][statIndex]);
    296                 yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
    297                         / 2;
    298                 canvas.drawText(label, xPos, yPos, whiteLabels);
    299             }
    300         }
    301         for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
    302             int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
    303             canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
    304         }
    305     }
    306 }
    307