Make BufferEncoder use 512 byte aligned buffers
Performance testing suggest that O_DIRECT is significantly faster than
using the more standard write calls. This requires much larger
alignment in the buffers used, and larger buffer sizes to be performant.
Modify BufferEncoder to use sector sized alignment.
Change-Id: Ie07b864b98b85caf631926565c97a56a469ca21d
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/containers/resizeable_buffer.h b/aos/containers/resizeable_buffer.h
index 4a4038c..ed0d23e 100644
--- a/aos/containers/resizeable_buffer.h
+++ b/aos/containers/resizeable_buffer.h
@@ -11,18 +11,21 @@
// Kind of like a subset of vector<uint8_t>, but with less destructor calls.
// When building unoptimized, especially with sanitizers, the vector<uint8_t>
// version ends up being really slow in tests.
-class ResizeableBuffer {
+//
+// F is the allocator used for reallocating the memory used by the buffer.
+template <class F>
+class AllocatorResizeableBuffer {
public:
- ResizeableBuffer() = default;
+ AllocatorResizeableBuffer() = default;
- ResizeableBuffer(const ResizeableBuffer &other) { *this = other; }
- ResizeableBuffer(ResizeableBuffer &&other) { *this = std::move(other); }
- ResizeableBuffer &operator=(const ResizeableBuffer &other) {
+ AllocatorResizeableBuffer(const AllocatorResizeableBuffer &other) { *this = other; }
+ AllocatorResizeableBuffer(AllocatorResizeableBuffer &&other) { *this = std::move(other); }
+ AllocatorResizeableBuffer &operator=(const AllocatorResizeableBuffer &other) {
resize(other.size());
memcpy(storage_.get(), other.storage_.get(), size());
return *this;
}
- ResizeableBuffer &operator=(ResizeableBuffer &&other) {
+ AllocatorResizeableBuffer &operator=(AllocatorResizeableBuffer &&other) {
std::swap(storage_, other.storage_);
std::swap(size_, other.size_);
std::swap(capacity_, other.capacity_);
@@ -93,7 +96,7 @@
void Allocate(size_t new_capacity) {
void *const old = storage_.release();
- storage_.reset(CHECK_NOTNULL(realloc(old, new_capacity)));
+ storage_.reset(CHECK_NOTNULL(F::Realloc(old, capacity_, new_capacity)));
capacity_ = new_capacity;
}
@@ -101,6 +104,18 @@
size_t size_ = 0, capacity_ = 0;
};
+// An allocator which just uses realloc to allocate.
+class Reallocator {
+ public:
+ static void *Realloc(void *old, size_t /*old_size*/, size_t new_capacity) {
+ return realloc(old, new_capacity);
+ }
+};
+
+// A resizable buffer which uses realloc when it needs to grow to attempt to
+// avoid full coppies.
+class ResizeableBuffer : public AllocatorResizeableBuffer<Reallocator> {};
+
} // namespace aos
#endif // AOS_CONTAINERS_RESIZEABLE_BUFFER_H_
diff --git a/aos/events/logging/buffer_encoder.h b/aos/events/logging/buffer_encoder.h
index 34de00a..f4a6251 100644
--- a/aos/events/logging/buffer_encoder.h
+++ b/aos/events/logging/buffer_encoder.h
@@ -112,7 +112,21 @@
private:
size_t total_bytes_ = 0;
- ResizeableBuffer input_buffer_;
+ // A class which uses aligned_alloc to allocate sector aligned blocks of
+ // memory.
+ class AlignedReallocator {
+ public:
+ static void *Realloc(void *old, size_t old_size, size_t new_capacity) {
+ void *new_memory = std::aligned_alloc(512, new_capacity);
+ if (old) {
+ memcpy(new_memory, old, old_size);
+ free(old);
+ }
+ return new_memory;
+ }
+ };
+
+ AllocatorResizeableBuffer<AlignedReallocator> input_buffer_;
std::vector<absl::Span<const uint8_t>> return_queue_;
};