alt_gmon.c 9.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. /******************************************************************************
  2. * *
  3. * License Agreement *
  4. * *
  5. * Copyright (c) 2003-2005 Altera Corporation, San Jose, California, USA. *
  6. * All rights reserved. *
  7. * *
  8. * Permission is hereby granted, free of charge, to any person obtaining a *
  9. * copy of this software and associated documentation files (the "Software"), *
  10. * to deal in the Software without restriction, including without limitation *
  11. * the rights to use, copy, modify, merge, publish, distribute, sublicense, *
  12. * and/or sell copies of the Software, and to permit persons to whom the *
  13. * Software is furnished to do so, subject to the following conditions: *
  14. * *
  15. * The above copyright notice and this permission notice shall be included in *
  16. * all copies or substantial portions of the Software. *
  17. * *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
  19. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
  20. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE *
  21. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
  22. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING *
  23. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER *
  24. * DEALINGS IN THE SOFTWARE. *
  25. * *
  26. * This agreement shall be governed in all respects by the laws of the State *
  27. * of California and by the laws of the United States of America. *
  28. * *
  29. ******************************************************************************/
  30. #include <assert.h>
  31. #include <string.h>
  32. #include <unistd.h>
  33. #include "priv/nios2_gmon_data.h"
  34. #include "sys/alt_irq.h"
  35. #include "sys/alt_alarm.h"
  36. /* Macros */
  37. /* How large should the bins be which we use to generate the histogram */
  38. #define PCSAMPLE_BYTES_PER_BUCKET 32
  39. #define NIOS2_READ_EA(dest) __asm__ ("mov %0, ea" : "=r" (dest))
  40. /* The compiler inserts calls to mcount() at the start of
  41. * every function call. The structure mcount_fn_arc records t
  42. * he return address of the function called (in from_pc)
  43. * and the return address of the mcount function
  44. * (in self_pc). The number of times this arc is executed is
  45. * recorded in the field count.
  46. */
  47. struct mcount_fn_arc
  48. {
  49. struct mcount_fn_arc * next;
  50. void * from_pc;
  51. unsigned int count;
  52. };
  53. /* We need to maintain a list of pointers to the heads of each adjacency
  54. * list so that we can find them when writing out the gmon.out file. Since
  55. * we don't know at the start of program execution how many functions will
  56. * be called we use a list structure to do this.
  57. */
  58. struct mcount_fn_entry
  59. {
  60. struct mcount_fn_entry * next;
  61. void * self_pc;
  62. struct mcount_fn_arc * arc_head;
  63. };
  64. /* function prototypes */
  65. void __mcount_record(void * self_pc, void * from_pc, struct mcount_fn_entry * fn_entry, struct mcount_fn_entry * * fn_head) __attribute__ ((no_instrument_function));
  66. static __inline__ void * mcount_allocate(unsigned int size) __attribute__ ((no_instrument_function));
  67. static int nios2_pcsample_init(void) __attribute__ ((no_instrument_function));
  68. static alt_u32 nios2_pcsample(void* alarm) __attribute__ ((no_instrument_function));
  69. /* global variables */
  70. /* stext and etext are defined in the linker script */
  71. extern char stext[];
  72. extern char etext[];
  73. /* Is the PC sampling stuff enabled yet? */
  74. static int pcsample_need_init = 1;
  75. #define HASH_BUCKETS 64 /* Must be a power of 2 */
  76. /* This points to the list of adjacency list pointers. */
  77. struct mcount_fn_entry * __mcount_fn_head[HASH_BUCKETS];
  78. /* pointer to the in-memory buffer containing the histogram */
  79. static unsigned short* s_pcsamples = 0;
  80. /* the address of the start and end of text section */
  81. static const unsigned int s_low_pc = (unsigned int)stext;
  82. static const unsigned int s_high_pc = (unsigned int)etext;
  83. /* the alarm structure to register for pc sampling */
  84. static alt_alarm s_nios2_pcsample_alarm;
  85. unsigned int alt_gmon_data[GMON_DATA_SIZE] =
  86. {
  87. 0x6e6f6d67, /* "gmon" */
  88. GMON_DATA_SIZE,
  89. 0,
  90. (unsigned int)stext,
  91. (unsigned int)etext,
  92. PCSAMPLE_BYTES_PER_BUCKET,
  93. 0,
  94. (unsigned int)__mcount_fn_head,
  95. (unsigned int)(__mcount_fn_head + HASH_BUCKETS)
  96. };
  97. /* This holds the current slab of memory we're allocating out of */
  98. static char * mcount_slab_ptr = 0;
  99. static int mcount_slab_size = 0;
  100. #define MCOUNT_SLAB_INCREMENT 1020
  101. /*
  102. * We can't use malloc to allocate memory because that's too complicated, and
  103. * can't be called at interrupt time. Use the lower level allocator instead
  104. * because that's interrupt safe (and because we never free anything).
  105. *
  106. * For speed, we allocate a block of data at once.
  107. */
  108. static __inline__ void * mcount_allocate(unsigned int size)
  109. {
  110. void * data;
  111. if (size > mcount_slab_size)
  112. {
  113. mcount_slab_ptr = sbrk(MCOUNT_SLAB_INCREMENT);
  114. mcount_slab_size = MCOUNT_SLAB_INCREMENT;
  115. }
  116. data = mcount_slab_ptr;
  117. mcount_slab_ptr += size;
  118. mcount_slab_size -= size;
  119. return data;
  120. }
  121. /*
  122. * Add the arc with the values of frompc and topc given to the graph.
  123. * This function might be called at interrupt time so must be able to
  124. * cope with reentrancy.
  125. *
  126. * The fast case, where we have already allocated a function arc, has been
  127. * handled by the assmebler code.
  128. */
  129. void __mcount_record(void * self_pc, void * from_pc, struct mcount_fn_entry * fn_entry, struct mcount_fn_entry * * fn_head)
  130. {
  131. alt_irq_context context;
  132. struct mcount_fn_arc * arc_entry;
  133. /* Keep trying to start up the PC sampler until it is running.
  134. * (It can't start until the timer is going).
  135. */
  136. if (pcsample_need_init)
  137. {
  138. pcsample_need_init = 0;
  139. pcsample_need_init = nios2_pcsample_init();
  140. }
  141. /*
  142. * We must disable interrupts around the allocation and the list update to
  143. * prevent corruption if the instrumented function is re-entrant.
  144. *
  145. * It's safe for the code above to be stepping through the chain and be
  146. * interrupted by this code modifying it - there is an edge case which will
  147. * leave two copies of the same arc on the list (both with count=1), but
  148. * this is dealt with on the host.
  149. */
  150. context = alt_irq_disable_all();
  151. if (fn_entry == NULL)
  152. {
  153. /* Add it to the list of functions we must output later. */
  154. fn_entry = (struct mcount_fn_entry *)mcount_allocate(sizeof(struct mcount_fn_entry));
  155. fn_entry->self_pc = self_pc;
  156. fn_entry->arc_head = NULL;
  157. fn_entry->next = *fn_head;
  158. *fn_head = fn_entry;
  159. }
  160. /* We will need a new list entry - if there was a list entry before
  161. * then the assembler code would have handled it. */
  162. arc_entry = (struct mcount_fn_arc *)mcount_allocate(sizeof(struct mcount_fn_arc));
  163. arc_entry->from_pc = from_pc;
  164. arc_entry->count = 1;
  165. arc_entry->next = fn_entry->arc_head;
  166. fn_entry->arc_head = arc_entry;
  167. alt_irq_enable_all(context);
  168. }
  169. /*
  170. * nios2_pcsample_init starts profiling.
  171. * It is called the first time mcount is called, and on subsequent calls to
  172. * mcount until it returns zero. It initializes the pc histogram and turns on
  173. * timer driven pc sampling.
  174. */
  175. static int nios2_pcsample_init(void)
  176. {
  177. unsigned int pcsamples_size;
  178. /* We sample the PC every tick */
  179. unsigned int prof_rate = alt_ticks_per_second();
  180. if (prof_rate == 0)
  181. return 1;
  182. /* allocate the histogram buffer s_pcsamples */
  183. pcsamples_size = (s_high_pc - s_low_pc)/PCSAMPLE_BYTES_PER_BUCKET;
  184. s_pcsamples = (unsigned short*)sbrk(pcsamples_size * sizeof(unsigned short));
  185. if (s_pcsamples != 0)
  186. {
  187. /* initialize the buffer to zero */
  188. memset(s_pcsamples, 0, pcsamples_size * sizeof(unsigned short));
  189. alt_gmon_data[GMON_DATA_PROFILE_DATA] = (int)s_pcsamples;
  190. alt_gmon_data[GMON_DATA_PROFILE_RATE] = prof_rate;
  191. /* Sample every tick (it's cheap) */
  192. alt_alarm_start(&s_nios2_pcsample_alarm, 1, nios2_pcsample, 0);
  193. }
  194. return 0;
  195. }
  196. /*
  197. * Sample the PC value and store it in the histogram
  198. */
  199. static alt_u32 nios2_pcsample(void* context)
  200. {
  201. unsigned int pc=0;
  202. unsigned int bucket;
  203. /* read the exception return address - this will be
  204. * inaccurate if there are nested interrupts but we
  205. * assume that this is rare and the inaccuracy will
  206. * not be great */
  207. NIOS2_READ_EA(pc);
  208. /*
  209. * If we're within the profilable range then increment the relevant
  210. * bucket in the histogram
  211. */
  212. if (pc >= s_low_pc && pc < s_high_pc && s_pcsamples != 0)
  213. {
  214. bucket = (pc - s_low_pc)/PCSAMPLE_BYTES_PER_BUCKET;
  215. s_pcsamples[bucket]++;
  216. }
  217. /* Sample every tick */
  218. return 1;
  219. }