xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Tracing/TransactionRingBuffer.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1*38e8c45fSAndroid Build Coastguard Worker /*
2*38e8c45fSAndroid Build Coastguard Worker  * Copyright 2021 The Android Open Source Project
3*38e8c45fSAndroid Build Coastguard Worker  *
4*38e8c45fSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*38e8c45fSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*38e8c45fSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*38e8c45fSAndroid Build Coastguard Worker  *
8*38e8c45fSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*38e8c45fSAndroid Build Coastguard Worker  *
10*38e8c45fSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*38e8c45fSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*38e8c45fSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*38e8c45fSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*38e8c45fSAndroid Build Coastguard Worker  * limitations under the License.
15*38e8c45fSAndroid Build Coastguard Worker  */
16*38e8c45fSAndroid Build Coastguard Worker 
17*38e8c45fSAndroid Build Coastguard Worker #pragma once
18*38e8c45fSAndroid Build Coastguard Worker 
19*38e8c45fSAndroid Build Coastguard Worker #include <android-base/file.h>
20*38e8c45fSAndroid Build Coastguard Worker #include <android-base/stringprintf.h>
21*38e8c45fSAndroid Build Coastguard Worker 
22*38e8c45fSAndroid Build Coastguard Worker #include <common/trace.h>
23*38e8c45fSAndroid Build Coastguard Worker #include <log/log.h>
24*38e8c45fSAndroid Build Coastguard Worker #include <utils/Errors.h>
25*38e8c45fSAndroid Build Coastguard Worker #include <utils/Timers.h>
26*38e8c45fSAndroid Build Coastguard Worker #include <chrono>
27*38e8c45fSAndroid Build Coastguard Worker #include <fstream>
28*38e8c45fSAndroid Build Coastguard Worker 
29*38e8c45fSAndroid Build Coastguard Worker namespace android {
30*38e8c45fSAndroid Build Coastguard Worker 
31*38e8c45fSAndroid Build Coastguard Worker class SurfaceFlinger;
32*38e8c45fSAndroid Build Coastguard Worker 
33*38e8c45fSAndroid Build Coastguard Worker template <typename FileProto, typename EntryProto>
34*38e8c45fSAndroid Build Coastguard Worker class TransactionRingBuffer {
35*38e8c45fSAndroid Build Coastguard Worker public:
size()36*38e8c45fSAndroid Build Coastguard Worker     size_t size() const { return mSizeInBytes; }
used()37*38e8c45fSAndroid Build Coastguard Worker     size_t used() const { return mUsedInBytes; }
frameCount()38*38e8c45fSAndroid Build Coastguard Worker     size_t frameCount() const { return mStorage.size(); }
setSize(size_t newSize)39*38e8c45fSAndroid Build Coastguard Worker     void setSize(size_t newSize) { mSizeInBytes = newSize; }
front()40*38e8c45fSAndroid Build Coastguard Worker     const std::string& front() const { return mStorage.front(); }
back()41*38e8c45fSAndroid Build Coastguard Worker     const std::string& back() const { return mStorage.back(); }
42*38e8c45fSAndroid Build Coastguard Worker 
reset()43*38e8c45fSAndroid Build Coastguard Worker     void reset() {
44*38e8c45fSAndroid Build Coastguard Worker         // use the swap trick to make sure memory is released
45*38e8c45fSAndroid Build Coastguard Worker         std::deque<std::string>().swap(mStorage);
46*38e8c45fSAndroid Build Coastguard Worker         mUsedInBytes = 0U;
47*38e8c45fSAndroid Build Coastguard Worker     }
48*38e8c45fSAndroid Build Coastguard Worker 
writeToProto(FileProto & fileProto)49*38e8c45fSAndroid Build Coastguard Worker     void writeToProto(FileProto& fileProto) const {
50*38e8c45fSAndroid Build Coastguard Worker         fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
51*38e8c45fSAndroid Build Coastguard Worker                                            fileProto.entry().size());
52*38e8c45fSAndroid Build Coastguard Worker         for (const std::string& entry : mStorage) {
53*38e8c45fSAndroid Build Coastguard Worker             EntryProto* entryProto = fileProto.add_entry();
54*38e8c45fSAndroid Build Coastguard Worker             entryProto->ParseFromString(entry);
55*38e8c45fSAndroid Build Coastguard Worker         }
56*38e8c45fSAndroid Build Coastguard Worker     }
57*38e8c45fSAndroid Build Coastguard Worker 
appendToStream(FileProto & fileProto,std::ofstream & out)58*38e8c45fSAndroid Build Coastguard Worker     status_t appendToStream(FileProto& fileProto, std::ofstream& out) {
59*38e8c45fSAndroid Build Coastguard Worker         SFTRACE_CALL();
60*38e8c45fSAndroid Build Coastguard Worker         writeToProto(fileProto);
61*38e8c45fSAndroid Build Coastguard Worker         std::string output;
62*38e8c45fSAndroid Build Coastguard Worker         if (!fileProto.SerializeToString(&output)) {
63*38e8c45fSAndroid Build Coastguard Worker             ALOGE("Could not serialize proto.");
64*38e8c45fSAndroid Build Coastguard Worker             return UNKNOWN_ERROR;
65*38e8c45fSAndroid Build Coastguard Worker         }
66*38e8c45fSAndroid Build Coastguard Worker 
67*38e8c45fSAndroid Build Coastguard Worker         out << output;
68*38e8c45fSAndroid Build Coastguard Worker         return NO_ERROR;
69*38e8c45fSAndroid Build Coastguard Worker     }
70*38e8c45fSAndroid Build Coastguard Worker 
emplace(std::string && serializedProto)71*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::string> emplace(std::string&& serializedProto) {
72*38e8c45fSAndroid Build Coastguard Worker         std::vector<std::string> replacedEntries;
73*38e8c45fSAndroid Build Coastguard Worker         size_t protoSize = static_cast<size_t>(serializedProto.size());
74*38e8c45fSAndroid Build Coastguard Worker         while (mUsedInBytes + protoSize > mSizeInBytes) {
75*38e8c45fSAndroid Build Coastguard Worker             if (mStorage.empty()) {
76*38e8c45fSAndroid Build Coastguard Worker                 return {};
77*38e8c45fSAndroid Build Coastguard Worker             }
78*38e8c45fSAndroid Build Coastguard Worker             mUsedInBytes -= static_cast<size_t>(mStorage.front().size());
79*38e8c45fSAndroid Build Coastguard Worker             replacedEntries.emplace_back(mStorage.front());
80*38e8c45fSAndroid Build Coastguard Worker             mStorage.pop_front();
81*38e8c45fSAndroid Build Coastguard Worker         }
82*38e8c45fSAndroid Build Coastguard Worker         mUsedInBytes += protoSize;
83*38e8c45fSAndroid Build Coastguard Worker         mStorage.emplace_back(serializedProto);
84*38e8c45fSAndroid Build Coastguard Worker         return replacedEntries;
85*38e8c45fSAndroid Build Coastguard Worker     }
86*38e8c45fSAndroid Build Coastguard Worker 
emplace(EntryProto && proto)87*38e8c45fSAndroid Build Coastguard Worker     std::vector<std::string> emplace(EntryProto&& proto) {
88*38e8c45fSAndroid Build Coastguard Worker         std::string serializedProto;
89*38e8c45fSAndroid Build Coastguard Worker         proto.SerializeToString(&serializedProto);
90*38e8c45fSAndroid Build Coastguard Worker         return emplace(std::move(serializedProto));
91*38e8c45fSAndroid Build Coastguard Worker     }
92*38e8c45fSAndroid Build Coastguard Worker 
dump(std::string & result)93*38e8c45fSAndroid Build Coastguard Worker     void dump(std::string& result) const {
94*38e8c45fSAndroid Build Coastguard Worker         std::chrono::milliseconds duration(0);
95*38e8c45fSAndroid Build Coastguard Worker         if (frameCount() > 0) {
96*38e8c45fSAndroid Build Coastguard Worker             EntryProto entry;
97*38e8c45fSAndroid Build Coastguard Worker             entry.ParseFromString(mStorage.front());
98*38e8c45fSAndroid Build Coastguard Worker             duration = std::chrono::duration_cast<std::chrono::milliseconds>(
99*38e8c45fSAndroid Build Coastguard Worker                     std::chrono::nanoseconds(systemTime() - entry.elapsed_realtime_nanos()));
100*38e8c45fSAndroid Build Coastguard Worker         }
101*38e8c45fSAndroid Build Coastguard Worker         const int64_t durationCount = duration.count();
102*38e8c45fSAndroid Build Coastguard Worker         base::StringAppendF(&result,
103*38e8c45fSAndroid Build Coastguard Worker                             "  number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
104*38e8c45fSAndroid Build Coastguard Worker                             frameCount(), float(used()) / (1024.f * 1024.f),
105*38e8c45fSAndroid Build Coastguard Worker                             float(size()) / (1024.f * 1024.f), durationCount);
106*38e8c45fSAndroid Build Coastguard Worker     }
107*38e8c45fSAndroid Build Coastguard Worker 
108*38e8c45fSAndroid Build Coastguard Worker private:
109*38e8c45fSAndroid Build Coastguard Worker     size_t mUsedInBytes = 0U;
110*38e8c45fSAndroid Build Coastguard Worker     size_t mSizeInBytes = 0U;
111*38e8c45fSAndroid Build Coastguard Worker     std::deque<std::string> mStorage;
112*38e8c45fSAndroid Build Coastguard Worker };
113*38e8c45fSAndroid Build Coastguard Worker 
114*38e8c45fSAndroid Build Coastguard Worker } // namespace android
115