mem_region: Merge similar allocations when dumping

Message ID 20180712021326.16277-1-oohall@gmail.com
State New
Headers show
Series
  • mem_region: Merge similar allocations when dumping
Related show

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success master/apply_patch Successfully applied
snowpatch_ozlabs/make_check success Test make_check on branch master

Commit Message

Oliver July 12, 2018, 2:13 a.m.
Currently we print one line for each allocation done at runtime when
dumping the memory allocations. We do a few thousand allocations at
boot so this can result in a huge amount of text being printed which
is a) slow to print, and b) Can result in the log buffer overflowing
which destroys otherwise useful information.

This patch adds a de-duplication to this memory allocation dump by
merging "similar" allocations (same location, same size) into one.

Unfortunately, the algorithm used to do the de-duplication is quadratic,
but considering we only dump the allocations in the event of a fatal
error I think this is acceptable. I also did some benchmarking and found
that on a ZZ it takes ~3ms to do a dump with 12k allocations. On a Zaius
it's slightly longer at about ~10ms for 10k allocs. However, the
difference there was due to the output being written to the UART.

This patch also bumps the log level to PR_NOTICE. PR_INFO messages are
suppressed at the default log level, which probably isn't something you
want considering we only dump the allocations when we run out of skiboot
heap space.

Signed-off-by: Oliver O'Halloran <oohall@gmail.com>
---
---
 core/mem_region.c | 38 ++++++++++++++++++++++++++++++++++----
 1 file changed, 34 insertions(+), 4 deletions(-)

Patch

diff --git a/core/mem_region.c b/core/mem_region.c
index 8ae49bb790fd..f17ba1508037 100644
--- a/core/mem_region.c
+++ b/core/mem_region.c
@@ -96,7 +96,8 @@  static struct mem_region skiboot_cpu_stacks = {
 struct alloc_hdr {
 	bool free : 1;
 	bool prev_free : 1;
-	unsigned long num_longs : BITS_PER_LONG-2; /* Including header. */
+	bool printed : 1;
+	unsigned long num_longs : BITS_PER_LONG-3; /* Including header. */
 	const char *location;
 };
 
@@ -285,7 +286,7 @@  static bool region_is_reserved(struct mem_region *region)
 void mem_dump_allocs(void)
 {
 	struct mem_region *region;
-	struct alloc_hdr *hdr;
+	struct alloc_hdr *hdr, *i;
 
 	/* Second pass: populate property data */
 	prlog(PR_INFO, "Memory regions:\n");
@@ -301,11 +302,40 @@  void mem_dump_allocs(void)
 			prlog(PR_INFO, "    no allocs\n");
 			continue;
 		}
+
+		/*
+		 * XXX: When dumping the allocation list we coalase allocations
+		 * with the same location and size into a single line. This is
+		 * quadratic, but it makes the dump human-readable and the raw
+		 * dump sometimes causes the log buffer to wrap.
+		 */
+		for (hdr = region_start(region); hdr; hdr = next_hdr(region, hdr))
+			hdr->printed = false;
+
 		for (hdr = region_start(region); hdr; hdr = next_hdr(region, hdr)) {
+			unsigned long bytes;
+			int count = 0;
+
 			if (hdr->free)
 				continue;
-			prlog(PR_INFO, "    0x%.8lx %s\n", hdr->num_longs * sizeof(long),
-			       hdr_location(hdr));
+			if (hdr->printed)
+				continue;
+
+			for (i = hdr; i; i = next_hdr(region, i)) {
+				if (i->free)
+					continue;
+				if (i->num_longs != hdr->num_longs)
+					continue;
+				if (strcmp(i->location, hdr->location))
+					continue;
+
+				i->printed = true;
+				count++;
+			}
+
+			bytes = hdr->num_longs * sizeof(long);
+			prlog(PR_NOTICE, " % 8d allocs of 0x%.8lx bytes at %s (total 0x%lx)\n",
+				count, bytes, hdr_location(hdr), bytes * count);
 		}
 	}
 }