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 //#define LOG_NDEBUG 0
18 #define LOG_TAG "Stats"
19
20 #include <ctime>
21 #include <iostream>
22 #include <stdint.h>
23 #include <fstream>
24
25 #include "Stats.h"
26
27 /**
28 * Dumps the stats of the operation for a given input media.
29 *
30 * \param operation describes the operation performed on the input media
31 * (i.e. extract/mux/decode/encode)
32 * \param inputReference input media
33 * \param durationUs is a duration of the input media in microseconds.
34 * \param componentName describes the codecName/muxFormat/mimeType.
35 * \param mode the operating mode: sync/async.
36 * \param statsFile the file where the stats data is to be written.
37 */
dumpStatistics(const string & operation,const string & inputReference,int64_t durationUs,const string & componentName,const string & mode,const string & statsFile)38 void Stats::dumpStatistics(const string& operation, const string& inputReference,
39 int64_t durationUs, const string& componentName,
40 const string& mode, const string& statsFile) {
41 ALOGV("In %s", __func__);
42 if (!mOutputTimer.size()) {
43 ALOGE("No output produced");
44 return;
45 }
46 if (statsFile.empty()) {
47 return uploadMetrics(operation, inputReference, durationUs, componentName,
48 mode);
49 }
50 nsecs_t totalTimeTakenNs = getTotalTime();
51 nsecs_t timeTakenPerSec = (totalTimeTakenNs * 1000000) / durationUs;
52 nsecs_t timeToFirstFrameNs = *mOutputTimer.begin() - mStartTimeNs;
53 int32_t size = std::accumulate(mFrameSizes.begin(), mFrameSizes.end(), 0);
54 // get min and max output intervals.
55 nsecs_t intervalNs;
56 nsecs_t minTimeTakenNs = INT64_MAX;
57 nsecs_t maxTimeTakenNs = 0;
58 nsecs_t prevIntervalNs = mStartTimeNs;
59 for (int32_t idx = 0; idx < mOutputTimer.size() - 1; idx++) {
60 intervalNs = mOutputTimer.at(idx) - prevIntervalNs;
61 prevIntervalNs = mOutputTimer.at(idx);
62 if (minTimeTakenNs > intervalNs) minTimeTakenNs = intervalNs;
63 else if (maxTimeTakenNs < intervalNs) maxTimeTakenNs = intervalNs;
64 }
65
66 // Write the stats data to file.
67 int64_t dataSize = size;
68 int64_t bytesPerSec = ((int64_t)dataSize * 1000000000) / totalTimeTakenNs;
69 string rowData = "";
70 rowData.append(to_string(systemTime(CLOCK_MONOTONIC)) + ", ");
71 rowData.append(inputReference + ", ");
72 rowData.append(operation + ", ");
73 rowData.append(componentName + ", ");
74 rowData.append("NDK, ");
75 rowData.append(mode + ", ");
76 rowData.append(to_string(mInitTimeNs) + ", ");
77 rowData.append(to_string(mDeInitTimeNs) + ", ");
78 rowData.append(to_string(minTimeTakenNs) + ", ");
79 rowData.append(to_string(maxTimeTakenNs) + ", ");
80 rowData.append(to_string(totalTimeTakenNs / mOutputTimer.size()) + ", ");
81 rowData.append(to_string(timeTakenPerSec) + ", ");
82 rowData.append(to_string(bytesPerSec) + ", ");
83 rowData.append(to_string(timeToFirstFrameNs) + ", ");
84 rowData.append(to_string(size) + ",");
85 rowData.append(to_string(totalTimeTakenNs) + ",\n");
86
87 ofstream out(statsFile, ios::out | ios::app);
88 if(out.bad()) {
89 ALOGE("Failed to open stats file for writing!");
90 return;
91 }
92 out << rowData;
93 out.close();
94 }
95
96 /**
97 * Dumps the stats of the operation for a given input media to a listener.
98 *
99 * \param operation describes the operation performed on the input media
100 * (i.e. extract/mux/decode/encode)
101 * \param inputReference input media
102 * \param durationUs is a duration of the input media in microseconds.
103 * \param componentName describes the codecName/muxFormat/mimeType.
104 * \param mode the operating mode: sync/async.
105 *
106 */
107
108 #define LOG_METRIC(...) \
109 __android_log_print(ANDROID_LOG_INFO, "ForTimingCollector", __VA_ARGS__)
110
uploadMetrics(const string & operation,const string & inputReference,const int64_t & durationUs,const string & componentName,const string & mode)111 void Stats::uploadMetrics(const string& operation, const string& inputReference,
112 const int64_t& durationUs, const string& componentName,
113 const string& mode) {
114
115 ALOGV("In %s", __func__);
116 (void)durationUs;
117 (void)componentName;
118 if (!mOutputTimer.size()) {
119 ALOGE("No output produced");
120 return;
121 }
122 nsecs_t totalTimeTakenNs = getTotalTime();
123 nsecs_t timeToFirstFrameNs = *mOutputTimer.begin() - mStartTimeNs;
124 int32_t size = std::accumulate(mFrameSizes.begin(), mFrameSizes.end(), 0);
125 // get min and max output intervals.
126 nsecs_t intervalNs;
127 nsecs_t minTimeTakenNs = INT64_MAX;
128 nsecs_t maxTimeTakenNs = 0;
129 nsecs_t prevIntervalNs = mStartTimeNs;
130 for (int32_t idx = 0; idx < mOutputTimer.size() - 1; idx++) {
131 intervalNs = mOutputTimer.at(idx) - prevIntervalNs;
132 prevIntervalNs = mOutputTimer.at(idx);
133 if (minTimeTakenNs > intervalNs) minTimeTakenNs = intervalNs;
134 else if (maxTimeTakenNs < intervalNs) maxTimeTakenNs = intervalNs;
135 }
136
137 // Write the stats data to file.
138 int64_t dataSize = size;
139 int64_t bytesPerSec = ((int64_t)dataSize * 1000000000) / totalTimeTakenNs;
140 (void)mode;
141 (void)operation;
142 (void)inputReference;
143 string prefix = "CodecStats_NativeDec";
144 prefix.append("_").append(componentName);
145 // Reports the time taken to initialize the codec.
146 LOG_METRIC("%s_CodecInitTimeNs:%lld", prefix.c_str(), (long long)mInitTimeNs);
147 // Reports the time taken to free the codec.
148 LOG_METRIC("%s_CodecDeInitTimeNs:%lld", prefix.c_str(), (long long)mDeInitTimeNs);
149 // Reports the min time taken between output frames from the codec
150 LOG_METRIC("%s_CodecMinTimeNs:%lld", prefix.c_str(), (long long)minTimeTakenNs);
151 // Reports the max time between the output frames from the codec
152 LOG_METRIC("%s_CodecMaxTimeNs:%lld", prefix.c_str(), (long long)maxTimeTakenNs);
153 // Report raw throughout ( bytes/sec ) of the codec for the entire media
154 LOG_METRIC("%s_ProcessedBytesPerSec:%lld", prefix.c_str(), (long long)bytesPerSec);
155 // Reports the time taken to get the first frame from the codec
156 LOG_METRIC("%s_TimeforFirstFrame:%lld", prefix.c_str(), (long long)timeToFirstFrameNs);
157
158 }
159