Zsh Mailing List Archive
Messages sorted by: Reverse Date, Date, Thread, Author

Re: Slowdown around 5.0.5-dev-0



On Oct 10,  5:06pm, Bart Schaefer wrote:
}
} This suggests a couple of possible fixes, but I've run out of time to
} experiment right now.

OK, this is the least intrusive change I can think of that might make
a difference.  What this attempts to do is maintain a second pointer
into the list of heaps that tells freeheap() where to start working.  
It's set on pushheap() and reset on popheap() so it freeheap() should
avoid searching for free space in some arenas that were completely
filled before pushheap() was called.  However, it won't improve the
performance if there are a whole lot of heap arenas each with a small
amount of space available at the time of pushheap().

To improve THAT situation, I think we'd have to be willing to "leak"
those small pieces of heap until a popheap() happens, and instead
use at least one new arena following most calls to pushheap().  This
might mean that zsh's memory footprint grows, but on modern hardware
that may not be an issue.

All tests pass with this change in place, let's see what it does with
Sebastian's 89k array elements.


diff --git a/Src/mem.c b/Src/mem.c
index b9569ea..01072a3 100644
--- a/Src/mem.c
+++ b/Src/mem.c
@@ -127,6 +127,12 @@ static Heap heaps;
 
 static Heap fheap;
 
+/* same as fheap, except in the preceding stack context (it will be the
+ * first heap from which space in the current context may be recovered
+ * when heap space is freed) */
+
+static Heap fpop;
+
 /**/
 #ifdef ZSH_HEAP_DEBUG
 /*
@@ -293,8 +299,11 @@ pushheap(void)
     h_push++;
 #endif
 
+    fpop = NULL;
     for (h = heaps; h; h = h->next) {
 	DPUTS(!h->used, "BUG: empty heap");
+	if (!fpop && h->used < ARENA_SIZEOF(h))
+	    fpop = h;
 	hs = (Heapstack) zalloc(sizeof(*hs));
 	hs->next = h->sp;
 	h->sp = hs;
@@ -341,9 +350,10 @@ freeheap(void)
      *
      * However, if the arena to which fheap points is unused, we want to
      * free it, so we have no choice but to do the sweep for a new fheap.
+     * fpop is the first heap with free space following pushheap().
      */
     if (fheap && !fheap->sp)
-	fheap = NULL;	/* We used to do this unconditionally */
+	fheap = fpop;
     /*
      * In other cases, either fheap is already correct, or it has never
      * been set and this loop will do it, or it'll be reset from scratch
@@ -417,7 +427,7 @@ popheap(void)
     h_pop++;
 #endif
 
-    fheap = NULL;
+    fheap = fpop = NULL;
     for (h = heaps; h; h = hn) {
 	hn = h->next;
 	if ((hs = h->sp)) {
@@ -443,6 +453,8 @@ popheap(void)
 #endif
 	    if (!fheap && h->used < ARENA_SIZEOF(h))
 		fheap = h;
+	    if (!fpop && h->sp && h->sp->used < ARENA_SIZEOF(h))
+		fpop = h;
 	    zfree(hs, sizeof(*hs));
 
 	    hl = h;



Messages sorted by: Reverse Date, Date, Thread, Author