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