Reduce allocations in lzma_encoder

Every time we flushed, we were freeing the buffer and then re-allocating
it.  The usage pattern has a very constant memory usage and no peaks, so
a free list will reduce fragmentation and prevent us from thrashing the
allocator.

Change-Id: I82060dff1fe95c950e39b1bef0955e20abc5b99a
Signed-off-by: Austin Schuh <austin.linux@gmail.com>
diff --git a/aos/events/logging/lzma_encoder.cc b/aos/events/logging/lzma_encoder.cc
index f354638..d348b70 100644
--- a/aos/events/logging/lzma_encoder.cc
+++ b/aos/events/logging/lzma_encoder.cc
@@ -84,6 +84,13 @@
   // efficient to allocate if we go over a threshold to keep the static memory
   // in use smaller, or just allocate the worst case like we are doing here?
   input_buffer_.resize(max_message_size);
+
+  // Start our queues out with a reasonable space allocation.  The cost of this
+  // is negligable compared to the buffer cost, but removes a bunch of
+  // allocations at runtime.
+  queue_.reserve(4);
+  free_queue_.reserve(4);
+  return_queue_.reserve(4);
 }
 
 LzmaEncoder::~LzmaEncoder() { lzma_end(&stream_); }
@@ -111,6 +118,9 @@
 void LzmaEncoder::Clear(const int n) {
   CHECK_GE(n, 0);
   CHECK_LE(static_cast<size_t>(n), queue_size());
+  for (int i = 0; i < n; ++i) {
+    free_queue_.emplace_back(std::move(queue_[i]));
+  }
   queue_.erase(queue_.begin(), queue_.begin() + n);
   if (queue_.empty()) {
     stream_.next_out = nullptr;
@@ -155,8 +165,13 @@
     // construction or a Reset, or when an input buffer is large enough to fill
     // more than one output buffer.
     if (stream_.avail_out == 0) {
-      queue_.emplace_back();
-      queue_.back().resize(kEncodedBufferSizeBytes);
+      if (!free_queue_.empty()) {
+        queue_.emplace_back(std::move(free_queue_.back()));
+        free_queue_.pop_back();
+      } else {
+        queue_.emplace_back();
+        queue_.back().resize(kEncodedBufferSizeBytes);
+      }
       stream_.next_out = queue_.back().data();
       stream_.avail_out = kEncodedBufferSizeBytes;
       // Update the byte count.
diff --git a/aos/events/logging/lzma_encoder.h b/aos/events/logging/lzma_encoder.h
index b4964fb..3136d93 100644
--- a/aos/events/logging/lzma_encoder.h
+++ b/aos/events/logging/lzma_encoder.h
@@ -54,6 +54,11 @@
   lzma_stream stream_;
   uint32_t compression_preset_;
   std::vector<ResizeableBuffer> queue_;
+  // Since we pretty much just allocate a couple of buffers, then allocate and
+  // release them over and over with very similar memory usage and without much
+  // variation in the peak usage, put the allocate chunks in a free queue to
+  // reduce fragmentation.
+  std::vector<ResizeableBuffer> free_queue_;
   bool finished_ = false;
   // Total bytes that resulted from encoding raw data since the last call to
   // Reset.