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