123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208 |
- 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)
|