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