mpatrol-unwindcache.patch 5.9 KB

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