aboutsummaryrefslogtreecommitdiff
path: root/core
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2018-07-31 17:05:27 +1000
committerStewart Smith <stewart@linux.ibm.com>2018-08-01 01:30:04 -0500
commit55cab51c74a8a6c5bb2e298e541ab125c5ade553 (patch)
treec7eb15ba0d4328e2a995a2499e8f9bcc6b7d1eaa /core
parent7a7ff2d6281fa7c4d90c836144f9c451427ecd25 (diff)
downloadskiboot-55cab51c74a8a6c5bb2e298e541ab125c5ade553.zip
skiboot-55cab51c74a8a6c5bb2e298e541ab125c5ade553.tar.gz
skiboot-55cab51c74a8a6c5bb2e298e541ab125c5ade553.tar.bz2
mem_region: Merge similar allocations when dumping
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> Signed-off-by: Stewart Smith <stewart@linux.ibm.com>
Diffstat (limited to 'core')
-rw-r--r--core/mem_region.c49
1 files changed, 42 insertions, 7 deletions
diff --git a/core/mem_region.c b/core/mem_region.c
index 0051ea6..bd387f3 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 *h, *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;
}
- for (hdr = region_start(region); hdr; hdr = next_hdr(region, hdr)) {
- if (hdr->free)
+
+ /*
+ * 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 (h = region_start(region); h; h = next_hdr(region, h))
+ h->printed = false;
+
+ for (h = region_start(region); h; h = next_hdr(region, h)) {
+ unsigned long bytes;
+ int count = 0;
+
+ if (h->free)
continue;
- prlog(PR_INFO, " 0x%.8lx %s\n", hdr->num_longs * sizeof(long),
- hdr_location(hdr));
+ if (h->printed)
+ continue;
+
+ for (i = h; i; i = next_hdr(region, i)) {
+ if (i->free)
+ continue;
+ if (i->num_longs != h->num_longs)
+ continue;
+ if (strcmp(i->location, h->location))
+ continue;
+
+ i->printed = true;
+ count++;
+ }
+
+ bytes = h->num_longs * sizeof(long);
+ prlog(PR_NOTICE, " % 8d allocs of 0x%.8lx bytes at %s (total 0x%lx)\n",
+ count, bytes, hdr_location(h), bytes * count);
}
}
}
@@ -439,6 +469,7 @@ found:
void *mem_alloc(struct mem_region *region, size_t size, size_t align,
const char *location)
{
+ static bool dumped = false;
void *r;
assert(lock_held_by_me(&region->free_list_lock));
@@ -449,7 +480,11 @@ void *mem_alloc(struct mem_region *region, size_t size, size_t align,
prerror("mem_alloc(0x%lx, 0x%lx, \"%s\", %s) failed !\n",
size, align, location, region->name);
- mem_dump_allocs();
+ if (!dumped) {
+ mem_dump_allocs();
+ dumped = true;
+ }
+
return NULL;
}