blob: d0fb3f28fe440b702674ba5972942c45fa7cb385 [file] [log] [blame]
Vishnu Nair00b90132021-11-05 14:03:40 -07001/*
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 <log/log.h>
23#include <utils/Errors.h>
24#include <utils/SystemClock.h>
25#include <utils/Trace.h>
26#include <queue>
27
28namespace android {
29
30class SurfaceFlinger;
31
32template <typename FileProto, typename EntryProto>
33class RingBuffer {
34public:
35 size_t size() const { return mSizeInBytes; }
36 size_t used() const { return mUsedInBytes; }
37 size_t frameCount() const { return mStorage.size(); }
38 void setSize(size_t newSize) { mSizeInBytes = newSize; }
39 EntryProto& front() { return mStorage.front(); }
40 const EntryProto& front() const { return mStorage.front(); }
41
42 void reset(size_t newSize) {
43 // use the swap trick to make sure memory is released
44 std::queue<EntryProto>().swap(mStorage);
45 mSizeInBytes = newSize;
46 mUsedInBytes = 0U;
47 }
48 void flush(FileProto& fileProto) {
49 fileProto.mutable_entry()->Reserve(static_cast<int>(mStorage.size()));
50 while (!mStorage.empty()) {
51 auto entry = fileProto.add_entry();
52 entry->Swap(&mStorage.front());
53 mStorage.pop();
54 }
55 }
56
57 status_t writeToFile(FileProto& fileProto, std::string filename) {
58 ATRACE_CALL();
59 std::string output;
60 flush(fileProto);
61 reset(mSizeInBytes);
62 if (!fileProto.SerializeToString(&output)) {
63 ALOGE("Could not serialize proto.");
64 return UNKNOWN_ERROR;
65 }
66
67 // -rw-r--r--
68 const mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
69 if (!android::base::WriteStringToFile(output, filename, mode, getuid(), getgid(), true)) {
70 ALOGE("Could not save the proto file.");
71 return PERMISSION_DENIED;
72 }
73 return NO_ERROR;
74 }
75
76 std::vector<EntryProto> emplace(EntryProto&& proto) {
77 std::vector<EntryProto> replacedEntries;
78 size_t protoSize = static_cast<size_t>(proto.ByteSize());
79 while (mUsedInBytes + protoSize > mSizeInBytes) {
80 if (mStorage.empty()) {
81 return {};
82 }
83 mUsedInBytes -= static_cast<size_t>(mStorage.front().ByteSize());
84 replacedEntries.emplace_back(mStorage.front());
85 mStorage.pop();
86 }
87 mUsedInBytes += protoSize;
88 mStorage.emplace();
89 mStorage.back().Swap(&proto);
90 return replacedEntries;
91 }
92
93 void dump(std::string& result) const {
94 std::chrono::milliseconds duration(0);
95 if (frameCount() > 0) {
96 duration = std::chrono::duration_cast<std::chrono::milliseconds>(
97 std::chrono::nanoseconds(systemTime() - front().elapsed_realtime_nanos()));
98 }
99 const int64_t durationCount = duration.count();
100 base::StringAppendF(&result,
101 " number of entries: %zu (%.2fMB / %.2fMB) duration: %" PRIi64 "ms\n",
102 frameCount(), float(used()) / 1024.f * 1024.f,
103 float(size()) / 1024.f * 1024.f, durationCount);
104 }
105
106private:
107 size_t mUsedInBytes = 0U;
108 size_t mSizeInBytes = 0U;
109 std::queue<EntryProto> mStorage;
110};
111
112} // namespace android