1 /* 2 * Copyright (C) 2019 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.media.benchmark.library; 18 19 import android.util.Log; 20 21 import java.io.File; 22 import java.io.FileDescriptor; 23 import java.io.FileOutputStream; 24 import java.io.IOException; 25 import java.util.ArrayList; 26 import java.util.List; 27 28 /** 29 * Measures Performance. 30 */ 31 public class Stats { 32 private static final String TAG = "Stats"; 33 private long mInitTimeNs; 34 private long mDeInitTimeNs; 35 private long mStartTimeNs; 36 private ArrayList<Integer> mFrameSizes; 37 /* 38 * Array for holding the wallclock time 39 * for each input buffer available. 40 */ 41 private ArrayList<Long> mInputTimer; 42 /* 43 * Array for holding the wallclock time 44 * for each output buffer available. 45 * This is used for determining the decoded 46 * frame intervals. 47 */ 48 private ArrayList<Long> mOutputTimer; 49 Stats()50 public Stats() { 51 mFrameSizes = new ArrayList<>(); 52 mInputTimer = new ArrayList<>(); 53 mOutputTimer = new ArrayList<>(); 54 mInitTimeNs = 0; 55 mDeInitTimeNs = 0; 56 } 57 getCurTime()58 public long getCurTime() { return System.nanoTime(); } 59 setInitTime(long initTime)60 public void setInitTime(long initTime) { mInitTimeNs = initTime; } 61 setDeInitTime(long deInitTime)62 public void setDeInitTime(long deInitTime) { mDeInitTimeNs = deInitTime; } 63 setStartTime()64 public void setStartTime() { mStartTimeNs = System.nanoTime(); } 65 addFrameSize(int size)66 public void addFrameSize(int size) { mFrameSizes.add(size); } 67 addInputTime()68 public void addInputTime() { mInputTimer.add(System.nanoTime()); } 69 addOutputTime()70 public void addOutputTime() { mOutputTimer.add(System.nanoTime()); } 71 reset()72 public void reset() { 73 if (mFrameSizes.size() != 0) { 74 mFrameSizes.clear(); 75 } 76 77 if (mInputTimer.size() != 0) { 78 mInputTimer.clear(); 79 } 80 81 if (mOutputTimer.size() != 0) { 82 mOutputTimer.clear(); 83 } 84 } 85 getInitTime()86 public long getInitTime() { return mInitTimeNs; } 87 getDeInitTime()88 public long getDeInitTime() { return mDeInitTimeNs; } 89 getStartTime()90 public long getStartTime() { return mStartTimeNs; } 91 getOutputTimers()92 public List<Long> getOutputTimers() { return mOutputTimer; } 93 getInputTimers()94 public List<Long> getInputTimers() { return mInputTimer; } 95 getTimeDiff(long sTime, long eTime)96 public long getTimeDiff(long sTime, long eTime) { return (eTime - sTime); } 97 getTotalTime()98 public long getTotalTime() { 99 if (mOutputTimer.size() == 0) { 100 return -1; 101 } 102 long lastTime = mOutputTimer.get(mOutputTimer.size() - 1); 103 return lastTime - mStartTimeNs; 104 } 105 getTotalSize()106 public long getTotalSize() { 107 long totalSize = 0; 108 for (long size : mFrameSizes) { 109 totalSize += size; 110 } 111 return totalSize; 112 } 113 114 /** 115 * Writes the stats header to a file 116 * <p> 117 * \param statsFile file where the stats data is to be written 118 **/ writeStatsHeader(String statsFile)119 public boolean writeStatsHeader(String statsFile) throws IOException { 120 File outputFile = new File(statsFile); 121 FileOutputStream out = new FileOutputStream(outputFile, true); 122 if (!outputFile.exists()) 123 return false; 124 String statsHeader = 125 "currentTime, fileName, operation, componentName, NDK/SDK, sync/async, setupTime, " 126 + "destroyTime, minimumTime, maximumTime, " 127 + "averageTime, timeToProcess1SecContent, totalBytesProcessedPerSec, " 128 + "timeToFirstFrame, totalSizeInBytes, totalTime\n"; 129 out.write(statsHeader.getBytes()); 130 out.close(); 131 return true; 132 } 133 134 /** 135 * Dumps the stats of the operation for a given input media. 136 * <p> 137 * \param inputReference input media 138 * \param operation describes the operation performed on the input media 139 * (i.e. extract/mux/decode/encode) 140 * \param componentName name of the codec/muxFormat/mime 141 * \param mode the operating mode: sync/async. 142 * \param durationUs is a duration of the input media in microseconds. 143 * \param statsFile the file where the stats data is to be written. 144 */ dumpStatistics(String inputReference, String operation, String componentName, String mode, long durationUs, String statsFile)145 public void dumpStatistics(String inputReference, String operation, String componentName, 146 String mode, long durationUs, String statsFile) throws IOException { 147 if (mOutputTimer.size() == 0) { 148 Log.e(TAG, "No output produced"); 149 return; 150 } 151 long totalTimeTakenNs = getTotalTime(); 152 long timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs; 153 long timeToFirstFrameNs = mOutputTimer.get(0) - mStartTimeNs; 154 long size = getTotalSize(); 155 // get min and max output intervals. 156 long intervalNs; 157 long minTimeTakenNs = Long.MAX_VALUE; 158 long maxTimeTakenNs = 0; 159 long prevIntervalNs = mStartTimeNs; 160 for (int idx = 0; idx < mOutputTimer.size() - 1; idx++) { 161 intervalNs = mOutputTimer.get(idx) - prevIntervalNs; 162 prevIntervalNs = mOutputTimer.get(idx); 163 if (minTimeTakenNs > intervalNs) { 164 minTimeTakenNs = intervalNs; 165 } else if (maxTimeTakenNs < intervalNs) { 166 maxTimeTakenNs = intervalNs; 167 } 168 } 169 170 // Write the stats row data to file 171 String rowData = ""; 172 rowData += System.nanoTime() + ", "; 173 rowData += inputReference + ", "; 174 rowData += operation + ", "; 175 rowData += componentName + ", "; 176 rowData += "SDK, "; 177 rowData += mode + ", "; 178 rowData += mInitTimeNs + ", "; 179 rowData += mDeInitTimeNs + ", "; 180 rowData += minTimeTakenNs + ", "; 181 rowData += maxTimeTakenNs + ", "; 182 rowData += totalTimeTakenNs / mOutputTimer.size() + ", "; 183 rowData += timeTakenPerSec + ", "; 184 rowData += (size * 1000000000) / totalTimeTakenNs + ", "; 185 rowData += timeToFirstFrameNs + ", "; 186 rowData += size + ", "; 187 rowData += totalTimeTakenNs + "\n"; 188 189 File outputFile = new File(statsFile); 190 FileOutputStream out = new FileOutputStream(outputFile, true); 191 assert outputFile.exists() : "Failed to open the stats file for writing!"; 192 out.write(rowData.getBytes()); 193 out.close(); 194 } 195 } 196