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     explicit Slice(size_t size);
38     Slice(Slice&& slice) noexcept;
39     ~Slice();
40 
GetTotalRange()41     inline protozero::ContiguousMemoryRange GetTotalRange() const {
42       return {buffer_.get(), buffer_.get() + size_};
43     }
44 
GetUsedRange()45     inline protozero::ContiguousMemoryRange GetUsedRange() const {
46       return {buffer_.get(), buffer_.get() + size_ - unused_bytes_};
47     }
48 
start()49     uint8_t* start() const { return buffer_.get(); }
size()50     size_t size() const { return size_; }
unused_bytes()51     size_t unused_bytes() const { return unused_bytes_; }
set_unused_bytes(size_t unused_bytes)52     void set_unused_bytes(size_t unused_bytes) {
53       PERFETTO_DCHECK(unused_bytes_ <= size_);
54       unused_bytes_ = unused_bytes;
55     }
56 
57    private:
58     std::unique_ptr<uint8_t[]> buffer_;
59     const size_t size_;
60     size_t unused_bytes_;
61   };
62 
63   ScatteredHeapBuffer(size_t initial_slice_size_bytes = 128,
64                       size_t maximum_slice_size_bytes = 128 * 1024);
65   ~ScatteredHeapBuffer() override;
66 
67   // protozero::ScatteredStreamWriter::Delegate implementation.
68   protozero::ContiguousMemoryRange GetNewBuffer() override;
69 
70   // Stitch all the slices into a single contiguous buffer.
71   std::vector<uint8_t> StitchSlices();
72 
slices()73   const std::vector<Slice>& slices() const { return slices_; }
74 
set_writer(protozero::ScatteredStreamWriter * writer)75   void set_writer(protozero::ScatteredStreamWriter* writer) {
76     writer_ = writer;
77   }
78 
79   // Update unused_bytes() of the current |Slice| based on the writer's state.
80   void AdjustUsedSizeOfCurrentSlice();
81 
82   // Returns the total size the slices occupy in heap memory (including unused).
83   size_t GetTotalSize();
84 
85  private:
86   size_t next_slice_size_;
87   const size_t maximum_slice_size_;
88   protozero::ScatteredStreamWriter* writer_ = nullptr;
89   std::vector<Slice> slices_;
90 };
91 
92 // Helper function to create heap-based protozero messages in one line.
93 // This is a convenience wrapper, mostly for tests, to avoid having to do:
94 //   MyMessage msg;
95 //   ScatteredHeapBuffer shb;
96 //   ScatteredStreamWriter writer(&shb);
97 //   shb.set_writer(&writer);
98 //   msg.Reset(&shb);
99 // Just to get an easily serializable message. Instead this allows simply:
100 //   HeapBuffered<MyMessage> msg;
101 //   msg->set_stuff(...);
102 //   msg->SerializeAsString();
103 template <typename T = ::protozero::Message>
104 class HeapBuffered {
105  public:
HeapBuffered()106   HeapBuffered() : shb_(4096, 4096), writer_(&shb_) {
107     shb_.set_writer(&writer_);
108     msg_.Reset(&writer_);
109   }
110 
111   // This can't be neither copied nor moved because Message hands out pointers
112   // to itself when creating submessages.
113   HeapBuffered(const HeapBuffered&) = delete;
114   HeapBuffered& operator=(const HeapBuffered&) = delete;
115   HeapBuffered(HeapBuffered&&) = delete;
116   HeapBuffered& operator=(HeapBuffered&&) = delete;
117 
get()118   T* get() { return &msg_; }
119   T* operator->() { return &msg_; }
120 
SerializeAsArray()121   std::vector<uint8_t> SerializeAsArray() { return shb_.StitchSlices(); }
122 
SerializeAsString()123   std::string SerializeAsString() {
124     auto vec = SerializeAsArray();
125     return std::string(reinterpret_cast<const char*>(vec.data()), vec.size());
126   }
127 
128  private:
129   ScatteredHeapBuffer shb_;
130   ScatteredStreamWriter writer_;
131   T msg_;
132 };
133 
134 }  // namespace protozero
135 
136 #endif  // INCLUDE_PERFETTO_PROTOZERO_SCATTERED_HEAP_BUFFER_H_
137