• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 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 #ifndef INCLUDE_PERFETTO_PROTOZERO_SCATTERED_HEAP_BUFFER_H_
18 #define INCLUDE_PERFETTO_PROTOZERO_SCATTERED_HEAP_BUFFER_H_
19 
20 #include <memory>
21 #include <string>
22 #include <vector>
23 
24 #include "perfetto/base/export.h"
25 #include "perfetto/base/logging.h"
26 #include "perfetto/protozero/scattered_stream_writer.h"
27 
28 namespace protozero {
29 
30 class Message;
31 
32 class PERFETTO_EXPORT ScatteredHeapBuffer
33     : public protozero::ScatteredStreamWriter::Delegate {
34  public:
35   class PERFETTO_EXPORT Slice {
36    public:
37     Slice();
38     explicit Slice(size_t size);
39     Slice(Slice&& slice) noexcept;
40     ~Slice();
41     Slice& operator=(Slice&&);
42 
GetTotalRange()43     inline protozero::ContiguousMemoryRange GetTotalRange() const {
44       return {buffer_.get(), buffer_.get() + size_};
45     }
46 
GetUsedRange()47     inline protozero::ContiguousMemoryRange GetUsedRange() const {
48       return {buffer_.get(), buffer_.get() + size_ - unused_bytes_};
49     }
50 
start()51     uint8_t* start() const { return buffer_.get(); }
size()52     size_t size() const { return size_; }
unused_bytes()53     size_t unused_bytes() const { return unused_bytes_; }
set_unused_bytes(size_t unused_bytes)54     void set_unused_bytes(size_t unused_bytes) {
55       PERFETTO_DCHECK(unused_bytes_ <= size_);
56       unused_bytes_ = unused_bytes;
57     }
58 
59     void Clear();
60 
61    private:
62     std::unique_ptr<uint8_t[]> buffer_;
63     size_t size_;
64     size_t unused_bytes_;
65   };
66 
67   ScatteredHeapBuffer(size_t initial_slice_size_bytes = 128,
68                       size_t maximum_slice_size_bytes = 128 * 1024);
69   ~ScatteredHeapBuffer() override;
70 
71   // protozero::ScatteredStreamWriter::Delegate implementation.
72   protozero::ContiguousMemoryRange GetNewBuffer() override;
73 
74   // Stitch all the slices into a single contiguous buffer.
75   std::vector<uint8_t> StitchSlices();
76 
77   // Note that the returned ranges point back to this buffer and thus cannot
78   // outlive it.
79   std::vector<protozero::ContiguousMemoryRange> GetRanges();
80 
slices()81   const std::vector<Slice>& slices() const { return slices_; }
82 
set_writer(protozero::ScatteredStreamWriter * writer)83   void set_writer(protozero::ScatteredStreamWriter* writer) {
84     writer_ = writer;
85   }
86 
87   // Update unused_bytes() of the current |Slice| based on the writer's state.
88   void AdjustUsedSizeOfCurrentSlice();
89 
90   // Returns the total size the slices occupy in heap memory (including unused).
91   size_t GetTotalSize();
92 
93   // Reset the contents of this buffer but retain one slice allocation (if it
94   // exists) to be reused for future writes.
95   void Reset();
96 
97  private:
98   size_t next_slice_size_;
99   const size_t maximum_slice_size_;
100   protozero::ScatteredStreamWriter* writer_ = nullptr;
101   std::vector<Slice> slices_;
102 
103   // Used to keep an allocated slice around after this buffer is reset.
104   Slice cached_slice_;
105 };
106 
107 // Helper function to create heap-based protozero messages in one line.
108 // Useful when manually serializing a protozero message (primarily in
109 // tests/utilities). So instead of the following:
110 //   protozero::MyMessage msg;
111 //   protozero::ScatteredHeapBuffer shb;
112 //   protozero::ScatteredStreamWriter writer(&shb);
113 //   shb.set_writer(&writer);
114 //   msg.Reset(&writer);
115 //   ...
116 // You can write:
117 //   protozero::HeapBuffered<protozero::MyMessage> msg;
118 //   msg->set_stuff(...);
119 //   msg.SerializeAsString();
120 template <typename T = ::protozero::Message>
121 class HeapBuffered {
122  public:
HeapBuffered()123   HeapBuffered() : HeapBuffered(4096, 4096) {}
HeapBuffered(size_t initial_slice_size_bytes,size_t maximum_slice_size_bytes)124   HeapBuffered(size_t initial_slice_size_bytes, size_t maximum_slice_size_bytes)
125       : shb_(initial_slice_size_bytes, maximum_slice_size_bytes),
126         writer_(&shb_) {
127     shb_.set_writer(&writer_);
128     msg_.Reset(&writer_);
129   }
130 
131   // This can't be neither copied nor moved because Message hands out pointers
132   // to itself when creating submessages.
133   HeapBuffered(const HeapBuffered&) = delete;
134   HeapBuffered& operator=(const HeapBuffered&) = delete;
135   HeapBuffered(HeapBuffered&&) = delete;
136   HeapBuffered& operator=(HeapBuffered&&) = delete;
137 
get()138   T* get() { return &msg_; }
139   T* operator->() { return &msg_; }
140 
empty()141   bool empty() const { return shb_.slices().empty(); }
142 
SerializeAsArray()143   std::vector<uint8_t> SerializeAsArray() {
144     msg_.Finalize();
145     return shb_.StitchSlices();
146   }
147 
SerializeAsString()148   std::string SerializeAsString() {
149     auto vec = SerializeAsArray();
150     return std::string(reinterpret_cast<const char*>(vec.data()), vec.size());
151   }
152 
GetRanges()153   std::vector<protozero::ContiguousMemoryRange> GetRanges() {
154     msg_.Finalize();
155     return shb_.GetRanges();
156   }
157 
Reset()158   void Reset() {
159     shb_.Reset();
160     writer_.Reset(protozero::ContiguousMemoryRange{});
161     msg_.Reset(&writer_);
162     PERFETTO_DCHECK(empty());
163   }
164 
165  private:
166   ScatteredHeapBuffer shb_;
167   ScatteredStreamWriter writer_;
168   T msg_;
169 };
170 
171 }  // namespace protozero
172 
173 #endif  // INCLUDE_PERFETTO_PROTOZERO_SCATTERED_HEAP_BUFFER_H_
174