From 447a86c922801a9d268a121862c5ae5619bc7f91 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@duempel.org>
Date: Fri, 4 Jan 2013 20:27:29 +0100
Subject: SliceBuffer: lazy initialization

Avoid page faults on MPD startup.  This saves a lot of memory for an
idle MPD.
---
 src/util/SliceBuffer.hxx | 34 +++++++++++++++++++++-------------
 1 file changed, 21 insertions(+), 13 deletions(-)

(limited to 'src/util')

diff --git a/src/util/SliceBuffer.hxx b/src/util/SliceBuffer.hxx
index 9ddad6b3d..1f5ff873d 100644
--- a/src/util/SliceBuffer.hxx
+++ b/src/util/SliceBuffer.hxx
@@ -47,6 +47,13 @@ class SliceBuffer {
 	 */
 	const unsigned n_max;
 
+	/**
+	 * The number of slices that are initialized.  This is used to
+	 * avoid page faulting on the new allocation, so the kernel
+	 * does not need to reserve physical memory pages.
+	 */
+	unsigned n_initialized;
+
 	/**
 	 * The number of slices currently allocated.
 	 */
@@ -61,15 +68,9 @@ class SliceBuffer {
 
 public:
 	SliceBuffer(unsigned _count)
-		:n_max(_count), n_allocated(0),
-		 data(g_new(Slice, n_max)), available(data) {
+		:n_max(_count), n_initialized(0), n_allocated(0),
+		 data(g_new(Slice, n_max)), available(nullptr) {
 		assert(n_max > 0);
-
-		Slice *const last = data + n_max - 1;
-		for (Slice *slice = data; slice != last; ++slice)
-			slice->next = slice + 1;
-
-		last->next = nullptr;
 	}
 
 	~SliceBuffer() {
@@ -97,12 +98,18 @@ public:
 
 	template<typename... Args>
 	T *Allocate(Args&&... args) {
-		assert(n_allocated <= n_max);
+		assert(n_initialized <= n_max);
+		assert(n_allocated <= n_initialized);
 
 		if (available == nullptr) {
-			/* out of (internal) memory, buffer is full */
-			assert(n_allocated == n_max);
-			return nullptr;
+			if (n_initialized == n_max) {
+				/* out of (internal) memory, buffer is full */
+				assert(n_allocated == n_max);
+				return nullptr;
+			}
+
+			available = &data[n_initialized++];
+			available->next = nullptr;
 		}
 
 		/* allocate a slice */
@@ -115,8 +122,9 @@ public:
 	}
 
 	void Free(T *value) {
+		assert(n_initialized <= n_max);
 		assert(n_allocated > 0);
-		assert(n_allocated <= n_max);
+		assert(n_allocated <= n_initialized);
 
 		Slice *slice = reinterpret_cast<Slice *>(value);
 		assert(slice >= data && slice < data + n_max);
-- 
cgit v1.2.3