xref: /aosp_15_r20/frameworks/native/services/surfaceflinger/Tracing/TransactionRingBuffer.h (revision 38e8c45f13ce32b0dcecb25141ffecaf386fa17f)
1 /*
2  * Copyright 2021 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 #pragma once
18 
19 #include <android-base/file.h>
20 #include <android-base/stringprintf.h>
21 
22 #include <common/trace.h>
23 #include <log/log.h>
24 #include <utils/Errors.h>
25 #include <utils/Timers.h>
26 #include <chrono>
27 #include <fstream>
28 
29 namespace android {
30 
31 class SurfaceFlinger;
32 
33 template <typename FileProto, typename EntryProto>
34 class TransactionRingBuffer {
35 public:
size()36     size_t size() const { return mSizeInBytes; }
used()37     size_t used() const { return mUsedInBytes; }
frameCount()38     size_t frameCount() const { return mStorage.size(); }
setSize(size_t newSize)39     void setSize(size_t newSize) { mSizeInBytes = newSize; }
front()40     const std::string& front() const { return mStorage.front(); }
back()41     const std::string& back() const { return mStorage.back(); }
42 
reset()43     void reset() {
44         // use the swap trick to make sure memory is released
45         std::deque<std::string>().swap(mStorage);
46         mUsedInBytes = 0U;
47     }
48 
writeToProto(FileProto & fileProto)49     void writeToProto(FileProto& fileProto) const {
50         fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()) +
51                                            fileProto.entry().size());
52         for (const std::string& entry : mStorage) {
53             EntryProto* entryProto = fileProto.add_entry();
54             entryProto->ParseFromString(entry);
55         }
56     }
57 
appendToStream(FileProto & fileProto,std::ofstream & out)58     status_t appendToStream(FileProto& fileProto, std::ofstream& out) {
59         SFTRACE_CALL();
60         writeToProto(fileProto);
61         std::string output;
62         if (!fileProto.SerializeToString(&output)) {
63             ALOGE("Could not serialize proto.");
64             return UNKNOWN_ERROR;
65         }
66 
67         out << output;
68         return NO_ERROR;
69     }
70 
emplace(std::string && serializedProto)71     std::vector<std::string> emplace(std::string&& serializedProto) {
72         std::vector<std::string> replacedEntries;
73         size_t protoSize = static_cast<size_t>(serializedProto.size());
74         while (mUsedInBytes + protoSize > mSizeInBytes) {
75             if (mStorage.empty()) {
76                 return {};
77             }
78             mUsedInBytes -= static_cast<size_t>(mStorage.front().size());
79             replacedEntries.emplace_back(mStorage.front());
80             mStorage.pop_front();
81         }
82         mUsedInBytes += protoSize;
83         mStorage.emplace_back(serializedProto);
84         return replacedEntries;
85     }
86 
emplace(EntryProto && proto)87     std::vector<std::string> emplace(EntryProto&& proto) {
88         std::string serializedProto;
89         proto.SerializeToString(&serializedProto);
90         return emplace(std::move(serializedProto));
91     }
92 
dump(std::string & result)93     void dump(std::string& result) const {
94         std::chrono::milliseconds duration(0);
95         if (frameCount() > 0) {
96             EntryProto entry;
97             entry.ParseFromString(mStorage.front());
98             duration = std::chrono::duration_cast<std::chrono::milliseconds>(
99                     std::chrono::nanoseconds(systemTime() - entry.elapsed_realtime_nanos()));
100         }
101         const int64_t durationCount = duration.count();
102         base::StringAppendF(&result,
103                             "  number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
104                             frameCount(), float(used()) / (1024.f * 1024.f),
105                             float(size()) / (1024.f * 1024.f), durationCount);
106     }
107 
108 private:
109     size_t mUsedInBytes = 0U;
110     size_t mSizeInBytes = 0U;
111     std::deque<std::string> mStorage;
112 };
113 
114 } // namespace android
115