1 /*
2 * Copyright 2020 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 #include "CameraUsageStats.h"
18
19 #include <android-base/logging.h>
20
21 #include <statslog_evs.h>
22
23 namespace {
24
25 // Length of frame roundtrip history
26 const int kMaxHistoryLength = 100;
27
28 } // namespace
29
30 namespace android {
31 namespace automotive {
32 namespace evs {
33 namespace V1_1 {
34 namespace implementation {
35
36 using ::android::base::Result;
37 using ::android::base::StringAppendF;
38 using ::android::hardware::hidl_vec;
39 using ::android::hardware::automotive::evs::V1_1::BufferDesc;
40
updateFrameStatsOnArrival(const hidl_vec<BufferDesc> & bufs)41 void CameraUsageStats::updateFrameStatsOnArrival(const hidl_vec<BufferDesc>& bufs) {
42 const auto now = android::uptimeMillis();
43 for (const auto& b : bufs) {
44 auto it = mBufferHistory.find(b.bufferId);
45 if (it == mBufferHistory.end()) {
46 mBufferHistory.emplace(b.bufferId, now);
47 } else {
48 it->second.timestamp = now;
49 }
50 }
51 }
52
updateFrameStatsOnReturn(const hidl_vec<BufferDesc> & bufs)53 void CameraUsageStats::updateFrameStatsOnReturn(const hidl_vec<BufferDesc>& bufs) {
54 const auto now = android::uptimeMillis();
55 for (auto& b : bufs) {
56 auto it = mBufferHistory.find(b.bufferId);
57 if (it == mBufferHistory.end()) {
58 LOG(WARNING) << "Buffer " << b.bufferId << " from " << b.deviceId << " is unknown.";
59 } else {
60 const auto roundtrip = now - it->second.timestamp;
61 it->second.history.emplace(roundtrip);
62 it->second.sum += roundtrip;
63 if (it->second.history.size() > kMaxHistoryLength) {
64 it->second.sum -= it->second.history.front();
65 it->second.history.pop();
66 }
67
68 if (roundtrip > it->second.peak) {
69 it->second.peak = roundtrip;
70 }
71
72 if (mStats.framesFirstRoundtripLatency == 0) {
73 mStats.framesFirstRoundtripLatency = roundtrip;
74 }
75 }
76 }
77 }
78
framesReceived(int n)79 void CameraUsageStats::framesReceived(int n) {
80 AutoMutex lock(mMutex);
81 mStats.framesReceived += n;
82 }
83
framesReceived(const hidl_vec<BufferDesc> & bufs)84 void CameraUsageStats::framesReceived(const hidl_vec<BufferDesc>& bufs) {
85 AutoMutex lock(mMutex);
86 mStats.framesReceived += bufs.size();
87
88 updateFrameStatsOnArrival(bufs);
89 }
90
framesReturned(int n)91 void CameraUsageStats::framesReturned(int n) {
92 AutoMutex lock(mMutex);
93 mStats.framesReturned += n;
94 }
95
framesReturned(const hidl_vec<BufferDesc> & bufs)96 void CameraUsageStats::framesReturned(const hidl_vec<BufferDesc>& bufs) {
97 AutoMutex lock(mMutex);
98 mStats.framesReturned += bufs.size();
99
100 updateFrameStatsOnReturn(bufs);
101 }
102
framesIgnored(int n)103 void CameraUsageStats::framesIgnored(int n) {
104 AutoMutex lock(mMutex);
105 mStats.framesIgnored += n;
106 }
107
framesSkippedToSync(int n)108 void CameraUsageStats::framesSkippedToSync(int n) {
109 AutoMutex lock(mMutex);
110 mStats.framesSkippedToSync += n;
111 }
112
eventsReceived()113 void CameraUsageStats::eventsReceived() {
114 AutoMutex lock(mMutex);
115 ++mStats.erroneousEventsCount;
116 }
117
updateNumClients(size_t n)118 void CameraUsageStats::updateNumClients(size_t n) {
119 AutoMutex lock(mMutex);
120 if (n > mStats.peakClientsCount) {
121 mStats.peakClientsCount = n;
122 }
123 }
124
getTimeCreated() const125 int64_t CameraUsageStats::getTimeCreated() const {
126 AutoMutex lock(mMutex);
127 return mTimeCreatedMs;
128 }
129
getFramesReceived() const130 int64_t CameraUsageStats::getFramesReceived() const {
131 AutoMutex lock(mMutex);
132 return mStats.framesReceived;
133 }
134
getFramesReturned() const135 int64_t CameraUsageStats::getFramesReturned() const {
136 AutoMutex lock(mMutex);
137 return mStats.framesReturned;
138 }
139
snapshot()140 CameraUsageStatsRecord CameraUsageStats::snapshot() {
141 AutoMutex lock(mMutex);
142
143 int32_t sum = 0;
144 int32_t peak = 0;
145 int32_t len = 0;
146 for (auto& [id, rec] : mBufferHistory) {
147 sum += rec.sum;
148 len += rec.history.size();
149 if (peak < rec.peak) {
150 peak = rec.peak;
151 }
152 }
153
154 mStats.framesPeakRoundtripLatency = peak;
155 mStats.framesAvgRoundtripLatency = (double)sum / len;
156 return mStats;
157 }
158
writeStats() const159 Result<void> CameraUsageStats::writeStats() const {
160 AutoMutex lock(mMutex);
161
162 // EvsUsageStatsReported atom is defined in
163 // frameworks/base/cmds/statsd/src/atoms.proto
164 const auto duration = android::uptimeMillis() - mTimeCreatedMs;
165 auto result =
166 stats::stats_write(stats::EVS_USAGE_STATS_REPORTED, mId, mStats.peakClientsCount,
167 mStats.erroneousEventsCount, mStats.framesFirstRoundtripLatency,
168 mStats.framesAvgRoundtripLatency, mStats.framesPeakRoundtripLatency,
169 mStats.framesReceived, mStats.framesIgnored,
170 mStats.framesSkippedToSync, duration);
171 if (result < 0) {
172 LOG(WARNING) << "Failed to report usage stats";
173 }
174 return {};
175 }
176
toString(const CameraUsageStatsRecord & record,const char * indent)177 std::string CameraUsageStats::toString(const CameraUsageStatsRecord& record, const char* indent) {
178 return record.toString(indent);
179 }
180
181 } // namespace implementation
182 } // namespace V1_1
183 } // namespace evs
184 } // namespace automotive
185 } // namespace android
186