bump version
[buildroot.git] / package / mpatrol / mpatrol-unwindcache.patch
blob3234d5c8172b61301c92925b3b571166bdfc4c7b
1 Patch to improve MIPS call stack unwind performance by caching the results
2 of code reading.
3 by Dan Howell <dahowell@directv.com>
5 diff -urN mpatrol-uclibc/src/stack.c mpatrol-unwindcache/src/stack.c
6 --- mpatrol-uclibc/src/stack.c 2006-06-22 15:39:04.000000000 -0700
7 +++ mpatrol-unwindcache/src/stack.c 2006-06-22 15:42:20.000000000 -0700
8 @@ -68,6 +68,7 @@
9 #define ucontext asm_ucontext
10 #include <asm/ucontext.h>
11 #undef ucontext
12 +#include "heap.h"
13 #endif /* ARCH */
14 #endif /* SYSTEM */
15 #endif /* TARGET */
16 @@ -280,6 +281,136 @@
18 #if !MP_BUILTINSTACK_SUPPORT && !MP_LIBRARYSTACK_SUPPORT
19 #if TARGET == TARGET_UNIX && ARCH == ARCH_MIPS
20 +/* Set up a tree to cache the results of code searching to determine the
21 + location of the return address for each code point encountered. */
23 +/* An unwind node belongs to a binary search tree of nodes, ordered by
24 + * code address, and contains call stack unwinding details for a given
25 + * code address. An internal index node stores details of a single memory
26 + * block allocated for unwind node slots.
27 + */
28 +typedef union unwindnode
30 + struct
31 + {
32 + treenode node; /* internal tree node */
33 + void *block; /* pointer to block of memory */
34 + size_t size; /* size of block of memory */
35 + }
36 + index;
37 + struct
38 + {
39 + treenode node; /* tree node */
40 + long p; /* return address offset in the stack */
41 + long m; /* frame pointer offset in stack */
42 + long s; /* stack pointer offset from previous frame */
43 + unsigned long a; /* flags */
44 + }
45 + data;
47 +unwindnode;
49 +/* An unwindhead holds the table of address node slots as well as the
50 + * internal list of memory blocks allocated for address node slots.
51 + */
52 +typedef struct unwindhead
54 + heaphead heap; /* pointer to heap */
55 + slottable table; /* table of address nodes */
56 + treeroot itree; /* internal list of memory blocks */
57 + treeroot dtree; /* tree for sorting */
58 + size_t size; /* memory used by internal blocks */
59 + char init; /* initialization flag */
61 +unwindhead;
63 +static unwindhead unwindcache;
65 +/* Initialise the fields of an unwindhead so that there are no allocated,
66 + * freed or free blocks.
67 + */
69 +static
70 +void
71 +newunwindcache(void)
73 + struct { char x; unwindnode y; } z;
74 + long n;
76 + __mp_newheap(&unwindcache.heap);
77 + /* Determine the minimum alignment for an unwind node on this
78 + * system and force the alignment to be a power of two. This
79 + * information is used when initialising the slot table.
80 + */
81 + n = (char *) &z.y - &z.x;
82 + __mp_newslots(&unwindcache.table, sizeof(unwindnode), __mp_poweroftwo(n));
83 + __mp_newtree(&unwindcache.itree);
84 + __mp_newtree(&unwindcache.dtree);
85 + unwindcache.size = 0;
86 + unwindcache.init = 1;
90 +/* Forget all unwind information.
91 + */
93 +static
94 +void
95 +deleteunwindcache(void)
97 + /* We don't need to explicitly free any memory as this is dealt with
98 + * at a lower level by the heap manager.
99 + */
100 + __mp_deleteheap(&unwindcache.heap);
101 + unwindcache.table.free = NULL;
102 + unwindcache.table.size = 0;
103 + __mp_newtree(&unwindcache.itree);
104 + __mp_newtree(&unwindcache.dtree);
105 + unwindcache.size = 0;
106 + unwindcache.init = 0;
110 +/* Allocate a new unwind node.
111 + */
113 +static
114 +unwindnode *
115 +getunwindnode(void)
117 + unwindnode *n;
118 + heapnode *p;
120 + /* If we have no more allocation node slots left then we must allocate
121 + * some more memory for them. An extra MP_ALLOCFACTOR pages of memory
122 + * should suffice.
123 + */
124 + if ((n = (unwindnode *) __mp_getslot(&unwindcache.table)) == NULL)
126 + if ((p = __mp_heapalloc(&unwindcache.heap, unwindcache.heap.memory.page * MP_ALLOCFACTOR,
127 + unwindcache.table.entalign, 1)) == NULL)
128 + return NULL;
129 + __mp_initslots(&unwindcache.table, p->block, p->size);
130 + n = (unwindnode *) __mp_getslot(&unwindcache.table);
131 + __mp_treeinsert(&unwindcache.itree, &n->index.node, (unsigned long) p->block);
132 + n->index.block = p->block;
133 + n->index.size = p->size;
134 + unwindcache.size += p->size;
135 + n = (unwindnode *) __mp_getslot(&unwindcache.table);
137 + return n;
140 +/* Search for the unwind node associated with a given address.
141 + */
142 +static
143 +unwindnode *
144 +findunwindnode(unsigned long p)
146 + return (unwindnode *) __mp_search(unwindcache.dtree.root, p);
150 /* Determine the stack pointer and return address of the previous stack frame
151 * by performing code reading.
153 @@ -289,8 +420,9 @@
154 unwind(frameinfo *f)
156 long p, m, s;
157 - unsigned long a, i, q, t, b, r;
158 + unsigned long a, i, q, t, b, r, k;
159 unsigned short l, u;
160 + unwindnode *n = NULL;
162 s = -1;
163 p = m = 0;
164 @@ -322,7 +454,23 @@
165 #endif
166 /* Save initial code-reading starting point.
168 - r = f->ra;
169 + r = k = f->ra;
170 + /* Create the cache if not yet created.
171 + */
172 + if (!unwindcache.init)
174 + newunwindcache();
175 + __mp_atexit(deleteunwindcache);
177 + if ((n = findunwindnode(f->ra)) != NULL)
179 + /* We've been here before, so get the cached information.
180 + */
181 + p = n->data.p;
182 + m = n->data.m;
183 + s = n->data.s;
184 + a = n->data.a;
186 /* Search for the return address offset in the stack frame.
188 while (!((a & RA_OFFSET) && (a & SP_OFFSET)) && (f->ra < q))
189 @@ -478,6 +626,19 @@
190 return 1;
192 #endif
193 + if (n == NULL)
195 + if ((n = getunwindnode()) != NULL)
197 + /* Cache the information we just got in the tree.
198 + */
199 + n->data.p = p;
200 + n->data.m = m;
201 + n->data.s = s;
202 + n->data.a = a;
203 + __mp_treeinsert(&unwindcache.dtree, &n->data.node, k);
206 if (a & SP_IN_FP)
207 f->sp = f->fp;
208 if (m > 0)