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