summaryrefslogtreecommitdiffstats
path: root/package/mpatrol/mpatrol-unwindcache.patch
diff options
context:
space:
mode:
Diffstat (limited to 'package/mpatrol/mpatrol-unwindcache.patch')
-rw-r--r--package/mpatrol/mpatrol-unwindcache.patch208
1 files changed, 208 insertions, 0 deletions
diff --git a/package/mpatrol/mpatrol-unwindcache.patch b/package/mpatrol/mpatrol-unwindcache.patch
new file mode 100644
index 000000000..3234d5c81
--- /dev/null
+++ b/package/mpatrol/mpatrol-unwindcache.patch
@@ -0,0 +1,208 @@
+Patch to improve MIPS call stack unwind performance by caching the results
+of code reading.
+by Dan Howell <dahowell@directv.com>
+
+diff -urN mpatrol-uclibc/src/stack.c mpatrol-unwindcache/src/stack.c
+--- mpatrol-uclibc/src/stack.c 2006-06-22 15:39:04.000000000 -0700
++++ mpatrol-unwindcache/src/stack.c 2006-06-22 15:42:20.000000000 -0700
+@@ -68,6 +68,7 @@
+ #define ucontext asm_ucontext
+ #include <asm/ucontext.h>
+ #undef ucontext
++#include "heap.h"
+ #endif /* ARCH */
+ #endif /* SYSTEM */
+ #endif /* TARGET */
+@@ -280,6 +281,136 @@
+
+ #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT
+ #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
++/* Set up a tree to cache the results of code searching to determine the
++ location of the return address for each code point encountered. */
++
++/* An unwind node belongs to a binary search tree of nodes, ordered by
++ * code address, and contains call stack unwinding details for a given
++ * code address. An internal index node stores details of a single memory
++ * block allocated for unwind node slots.
++ */
++typedef union unwindnode
++{
++ struct
++ {
++ treenode node; /* internal tree node */
++ void *block; /* pointer to block of memory */
++ size_t size; /* size of block of memory */
++ }
++ index;
++ struct
++ {
++ treenode node; /* tree node */
++ long p; /* return address offset in the stack */
++ long m; /* frame pointer offset in stack */
++ long s; /* stack pointer offset from previous frame */
++ unsigned long a; /* flags */
++ }
++ data;
++}
++unwindnode;
++
++/* An unwindhead holds the table of address node slots as well as the
++ * internal list of memory blocks allocated for address node slots.
++ */
++typedef struct unwindhead
++{
++ heaphead heap; /* pointer to heap */
++ slottable table; /* table of address nodes */
++ treeroot itree; /* internal list of memory blocks */
++ treeroot dtree; /* tree for sorting */
++ size_t size; /* memory used by internal blocks */
++ char init; /* initialization flag */
++}
++unwindhead;
++
++static unwindhead unwindcache;
++
++/* Initialise the fields of an unwindhead so that there are no allocated,
++ * freed or free blocks.
++ */
++
++static
++void
++newunwindcache(void)
++{
++ struct { char x; unwindnode y; } z;
++ long n;
++
++ __mp_newheap(&unwindcache.heap);
++ /* Determine the minimum alignment for an unwind node on this
++ * system and force the alignment to be a power of two. This
++ * information is used when initialising the slot table.
++ */
++ n = (char *) &z.y - &z.x;
++ __mp_newslots(&unwindcache.table, sizeof(unwindnode), __mp_poweroftwo(n));
++ __mp_newtree(&unwindcache.itree);
++ __mp_newtree(&unwindcache.dtree);
++ unwindcache.size = 0;
++ unwindcache.init = 1;
++}
++
++
++/* Forget all unwind information.
++ */
++
++static
++void
++deleteunwindcache(void)
++{
++ /* We don't need to explicitly free any memory as this is dealt with
++ * at a lower level by the heap manager.
++ */
++ __mp_deleteheap(&unwindcache.heap);
++ unwindcache.table.free = NULL;
++ unwindcache.table.size = 0;
++ __mp_newtree(&unwindcache.itree);
++ __mp_newtree(&unwindcache.dtree);
++ unwindcache.size = 0;
++ unwindcache.init = 0;
++}
++
++
++/* Allocate a new unwind node.
++ */
++
++static
++unwindnode *
++getunwindnode(void)
++{
++ unwindnode *n;
++ heapnode *p;
++
++ /* If we have no more allocation node slots left then we must allocate
++ * some more memory for them. An extra MP_ALLOCFACTOR pages of memory
++ * should suffice.
++ */
++ if ((n = (unwindnode *) __mp_getslot(&unwindcache.table)) == NULL)
++ {
++ if ((p = __mp_heapalloc(&unwindcache.heap, unwindcache.heap.memory.page * MP_ALLOCFACTOR,
++ unwindcache.table.entalign, 1)) == NULL)
++ return NULL;
++ __mp_initslots(&unwindcache.table, p->block, p->size);
++ n = (unwindnode *) __mp_getslot(&unwindcache.table);
++ __mp_treeinsert(&unwindcache.itree, &n->index.node, (unsigned long) p->block);
++ n->index.block = p->block;
++ n->index.size = p->size;
++ unwindcache.size += p->size;
++ n = (unwindnode *) __mp_getslot(&unwindcache.table);
++ }
++ return n;
++}
++
++/* Search for the unwind node associated with a given address.
++ */
++static
++unwindnode *
++findunwindnode(unsigned long p)
++{
++ return (unwindnode *) __mp_search(unwindcache.dtree.root, p);
++}
++
++
+ /* Determine the stack pointer and return address of the previous stack frame
+ * by performing code reading.
+ */
+@@ -289,8 +420,9 @@
+ unwind(frameinfo *f)
+ {
+ long p, m, s;
+- unsigned long a, i, q, t, b, r;
++ unsigned long a, i, q, t, b, r, k;
+ unsigned short l, u;
++ unwindnode *n = NULL;
+
+ s = -1;
+ p = m = 0;
+@@ -322,7 +454,23 @@
+ #endif
+ /* Save initial code-reading starting point.
+ */
+- r = f->ra;
++ r = k = f->ra;
++ /* Create the cache if not yet created.
++ */
++ if (!unwindcache.init)
++ {
++ newunwindcache();
++ __mp_atexit(deleteunwindcache);
++ }
++ if ((n = findunwindnode(f->ra)) != NULL)
++ {
++ /* We've been here before, so get the cached information.
++ */
++ p = n->data.p;
++ m = n->data.m;
++ s = n->data.s;
++ a = n->data.a;
++ }
+ /* Search for the return address offset in the stack frame.
+ */
+ while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q))
+@@ -478,6 +626,19 @@
+ return 1;
+ }
+ #endif
++ if (n == NULL)
++ {
++ if ((n = getunwindnode()) != NULL)
++ {
++ /* Cache the information we just got in the tree.
++ */
++ n->data.p = p;
++ n->data.m = m;
++ n->data.s = s;
++ n->data.a = a;
++ __mp_treeinsert(&unwindcache.dtree, &n->data.node, k);
++ }
++ }
+ if (a & SP_IN_FP)
+ f->sp = f->fp;
+ if (m > 0)