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