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
     41                 && tile.right >= view.left
     42                 && tile.top < view.bottom
     43                 && tile.bottom >= view.top) {
     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 ? 1 : 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 1;
     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         double index = ratioAbove * (sortedValues.length - 1);
    112         int intIndex = (int) Math.floor(index);
    113         if (index == intIndex) {
    114             return sortedValues[intIndex];
    115         }
    116         double alpha = index - intIndex;
    117         return sortedValues[intIndex] * (1 - alpha)
    118                 + sortedValues[intIndex + 1] * (alpha);
    119     }
    120 
    121     protected static StatGen[] Stats = new StatGen[] {
    122             new StatGen() {
    123                 @Override
    124                 public double getValue(double[] sortedValues) {
    125                     return getPercentile(sortedValues, 0.25);
    126                 }
    127 
    128                 @Override
    129                 public int getLabelId() {
    130                     return R.string.percentile_25;
    131                 }
    132             }, new StatGen() {
    133                 @Override
    134                 public double getValue(double[] sortedValues) {
    135                     return getPercentile(sortedValues, 0.5);
    136                 }
    137 
    138                 @Override
    139                 public int getLabelId() {
    140                     return R.string.percentile_50;
    141                 }
    142             }, new StatGen() {
    143                 @Override
    144                 public double getValue(double[] sortedValues) {
    145                     return getPercentile(sortedValues, 0.75);
    146                 }
    147 
    148                 @Override
    149                 public int getLabelId() {
    150                     return R.string.percentile_75;
    151                 }
    152             },
    153     };
    154 
    155     public PlaybackGraphs() {
    156         whiteLabels = new Paint();
    157         whiteLabels.setColor(Color.WHITE);
    158         whiteLabels.setTextSize(PlaybackView.TILE_SCALE / 3);
    159     }
    160 
    161     private ArrayList<ShapeDrawable> mShapes = new ArrayList<ShapeDrawable>();
    162     protected double[][] mStats = new double[Metrics.length][Stats.length];
    163     protected HashMap<String, Double> mSingleStats;
    164 
    165     public void setData(RunData data) {
    166         mShapes.clear();
    167         double metricValues[] = new double[data.frames.length];
    168 
    169         if (data.frames.length == 0) {
    170             return;
    171         }
    172 
    173         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
    174             // create graph out of rectangles, one per frame
    175             int lastBar = 0;
    176             for (int frameIndex = 0; frameIndex < data.frames.length; frameIndex++) {
    177                 TileData frame[] = data.frames[frameIndex];
    178                 int newBar = (frame[0].top + frame[0].bottom) / 2;
    179 
    180                 MetricGen s = Metrics[metricIndex];
    181                 double absoluteValue = s.getValue(frame);
    182                 double relativeValue = absoluteValue / s.getMax();
    183                 relativeValue = Math.min(1,relativeValue);
    184                 relativeValue = Math.max(0,relativeValue);
    185                 int rightPos = (int) (-BAR_WIDTH * metricIndex);
    186                 int leftPos = (int) (-BAR_WIDTH * (metricIndex + relativeValue));
    187 
    188                 ShapeDrawable graphBar = new ShapeDrawable();
    189                 graphBar.getPaint().setColor(Color.BLUE);
    190                 graphBar.setBounds(leftPos, lastBar, rightPos, newBar);
    191 
    192                 mShapes.add(graphBar);
    193                 metricValues[frameIndex] = absoluteValue;
    194                 lastBar = newBar;
    195             }
    196 
    197             // store aggregate statistics per metric (median, and similar)
    198             Arrays.sort(metricValues);
    199             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
    200                 mStats[metricIndex][statIndex] =
    201                         Stats[statIndex].getValue(metricValues);
    202             }
    203 
    204             mSingleStats = data.singleStats;
    205         }
    206     }
    207 
    208     public void drawVerticalShiftedShapes(Canvas canvas,
    209             ArrayList<ShapeDrawable> shapes) {
    210         // Shapes drawn here are drawn relative to the viewRect
    211         Rect viewRect = shapes.get(shapes.size() - 1).getBounds();
    212         canvas.translate(0, 5 * PlaybackView.TILE_SCALE - viewRect.top);
    213 
    214         for (ShapeDrawable shape : mShapes) {
    215             shape.draw(canvas);
    216         }
    217         for (ShapeDrawable shape : shapes) {
    218             shape.draw(canvas);
    219         }
    220     }
    221 
    222     public void draw(Canvas canvas, ArrayList<ShapeDrawable> shapes,
    223             ArrayList<String> strings, Resources resources) {
    224         canvas.scale(CANVAS_SCALE, CANVAS_SCALE);
    225 
    226         canvas.translate(BAR_WIDTH * Metrics.length, 0);
    227 
    228         canvas.save();
    229         drawVerticalShiftedShapes(canvas, shapes);
    230         canvas.restore();
    231 
    232         for (int metricIndex = 0; metricIndex < Metrics.length; metricIndex++) {
    233             String label = resources.getString(
    234                     Metrics[metricIndex].getLabelId());
    235             int xPos = (metricIndex + 1) * -BAR_WIDTH;
    236             int yPos = LABELOFFSET;
    237             canvas.drawText(label, xPos, yPos, whiteLabels);
    238             for (int statIndex = 0; statIndex < Stats.length; statIndex++) {
    239                 String statLabel = resources.getString(
    240                         Stats[statIndex].getLabelId()).substring(0,3);
    241                 label = statLabel + " " + resources.getString(
    242                         R.string.format_stat, mStats[metricIndex][statIndex]);
    243                 yPos = LABELOFFSET + (1 + statIndex) * PlaybackView.TILE_SCALE
    244                         / 2;
    245                 canvas.drawText(label, xPos, yPos, whiteLabels);
    246             }
    247         }
    248         for (int stringIndex = 0; stringIndex < strings.size(); stringIndex++) {
    249             int yPos = LABELOFFSET + stringIndex * PlaybackView.TILE_SCALE / 2;
    250             canvas.drawText(strings.get(stringIndex), 0, yPos, whiteLabels);
    251         }
    252     }
    253 }
    254