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