• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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