vec.c 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279
  1. /* Vector API for GNU compiler.
  2. Copyright (C) 2004-2015 Free Software Foundation, Inc.
  3. Contributed by Nathan Sidwell <nathan@codesourcery.com>
  4. Re-implemented in C++ by Diego Novillo <dnovillo@google.com>
  5. This file is part of GCC.
  6. GCC is free software; you can redistribute it and/or modify it under
  7. the terms of the GNU General Public License as published by the Free
  8. Software Foundation; either version 3, or (at your option) any later
  9. version.
  10. GCC is distributed in the hope that it will be useful, but WITHOUT ANY
  11. WARRANTY; without even the implied warranty of MERCHANTABILITY or
  12. FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
  13. for more details.
  14. You should have received a copy of the GNU General Public License
  15. along with GCC; see the file COPYING3. If not see
  16. <http://www.gnu.org/licenses/>. */
  17. /* This file is compiled twice: once for the generator programs
  18. once for the compiler. */
  19. #ifdef GENERATOR_FILE
  20. #include "bconfig.h"
  21. #else
  22. #include "config.h"
  23. #endif
  24. #include "system.h"
  25. #include "coretypes.h"
  26. #include "ggc.h"
  27. #include "vec.h"
  28. #include "diagnostic-core.h"
  29. #include "hashtab.h"
  30. /* vNULL is an empty type with a template cast operation that returns
  31. a zero-initialized vec<T, A, L> instance. Use this when you want
  32. to assign nil values to new vec instances or pass a nil vector as
  33. a function call argument.
  34. We use this technique because vec<T, A, L> must be PODs (they are
  35. stored in unions and passed in vararg functions), this means that
  36. they cannot have ctors/dtors. */
  37. vnull vNULL;
  38. /* Store information about each particular vector. */
  39. struct vec_descriptor
  40. {
  41. const char *function;
  42. const char *file;
  43. int line;
  44. size_t allocated;
  45. size_t times;
  46. size_t peak;
  47. };
  48. /* Hashtable mapping vec addresses to descriptors. */
  49. static htab_t vec_desc_hash;
  50. /* Hashtable helpers. */
  51. static hashval_t
  52. hash_descriptor (const void *p)
  53. {
  54. const struct vec_descriptor *const d =
  55. (const struct vec_descriptor *) p;
  56. return htab_hash_pointer (d->file) + d->line;
  57. }
  58. static int
  59. eq_descriptor (const void *p1, const void *p2)
  60. {
  61. const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
  62. const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
  63. return d->file == l->file && d->function == l->function && d->line == l->line;
  64. }
  65. /* Hashtable converting address of allocated field to loc descriptor. */
  66. static htab_t ptr_hash;
  67. struct ptr_hash_entry
  68. {
  69. void *ptr;
  70. struct vec_descriptor *loc;
  71. size_t allocated;
  72. };
  73. /* Hash table helpers functions. */
  74. static hashval_t
  75. hash_ptr (const void *p)
  76. {
  77. const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
  78. return htab_hash_pointer (d->ptr);
  79. }
  80. static int
  81. eq_ptr (const void *p1, const void *p2)
  82. {
  83. const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
  84. return (p->ptr == p2);
  85. }
  86. /* Return descriptor for given call site, create new one if needed. */
  87. static struct vec_descriptor *
  88. vec_descriptor (const char *name, int line, const char *function)
  89. {
  90. struct vec_descriptor loc;
  91. struct vec_descriptor **slot;
  92. loc.file = name;
  93. loc.line = line;
  94. loc.function = function;
  95. if (!vec_desc_hash)
  96. vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
  97. slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc,
  98. INSERT);
  99. if (*slot)
  100. return *slot;
  101. *slot = XCNEW (struct vec_descriptor);
  102. (*slot)->file = name;
  103. (*slot)->line = line;
  104. (*slot)->function = function;
  105. (*slot)->allocated = 0;
  106. (*slot)->peak = 0;
  107. return *slot;
  108. }
  109. /* Account the overhead. */
  110. void
  111. vec_prefix::register_overhead (size_t size, const char *name, int line,
  112. const char *function)
  113. {
  114. struct vec_descriptor *loc = vec_descriptor (name, line, function);
  115. struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
  116. PTR *slot;
  117. p->ptr = this;
  118. p->loc = loc;
  119. p->allocated = size;
  120. if (!ptr_hash)
  121. ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
  122. slot = htab_find_slot_with_hash (ptr_hash, this, htab_hash_pointer (this),
  123. INSERT);
  124. gcc_assert (!*slot);
  125. *slot = p;
  126. loc->allocated += size;
  127. if (loc->peak < loc->allocated)
  128. loc->peak += loc->allocated;
  129. loc->times++;
  130. }
  131. /* Notice that the memory allocated for the vector has been freed. */
  132. void
  133. vec_prefix::release_overhead (void)
  134. {
  135. PTR *slot = htab_find_slot_with_hash (ptr_hash, this,
  136. htab_hash_pointer (this),
  137. NO_INSERT);
  138. struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
  139. p->loc->allocated -= p->allocated;
  140. htab_clear_slot (ptr_hash, slot);
  141. ::free (p);
  142. }
  143. /* Calculate the number of slots to reserve a vector, making sure that
  144. it is of at least DESIRED size by growing ALLOC exponentially. */
  145. unsigned
  146. vec_prefix::calculate_allocation_1 (unsigned alloc, unsigned desired)
  147. {
  148. /* We must have run out of room. */
  149. gcc_assert (alloc < desired);
  150. /* Exponential growth. */
  151. if (!alloc)
  152. alloc = 4;
  153. else if (alloc < 16)
  154. /* Double when small. */
  155. alloc = alloc * 2;
  156. else
  157. /* Grow slower when large. */
  158. alloc = (alloc * 3 / 2);
  159. /* If this is still too small, set it to the right size. */
  160. if (alloc < desired)
  161. alloc = desired;
  162. return alloc;
  163. }
  164. /* Helper for qsort; sort descriptors by amount of memory consumed. */
  165. static int
  166. cmp_statistic (const void *loc1, const void *loc2)
  167. {
  168. const struct vec_descriptor *const l1 =
  169. *(const struct vec_descriptor *const *) loc1;
  170. const struct vec_descriptor *const l2 =
  171. *(const struct vec_descriptor *const *) loc2;
  172. long diff;
  173. diff = l1->allocated - l2->allocated;
  174. if (!diff)
  175. diff = l1->peak - l2->peak;
  176. if (!diff)
  177. diff = l1->times - l2->times;
  178. return diff > 0 ? 1 : diff < 0 ? -1 : 0;
  179. }
  180. /* Collect array of the descriptors from hashtable. */
  181. static struct vec_descriptor **loc_array;
  182. static int
  183. add_statistics (void **slot, void *b)
  184. {
  185. int *n = (int *)b;
  186. loc_array[*n] = (struct vec_descriptor *) *slot;
  187. (*n)++;
  188. return 1;
  189. }
  190. /* Dump per-site memory statistics. */
  191. void
  192. dump_vec_loc_statistics (void)
  193. {
  194. int nentries = 0;
  195. char s[4096];
  196. size_t allocated = 0;
  197. size_t times = 0;
  198. int i;
  199. if (! GATHER_STATISTICS)
  200. return;
  201. loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
  202. fprintf (stderr, "Heap vectors:\n");
  203. fprintf (stderr, "\n%-48s %10s %10s %10s\n",
  204. "source location", "Leak", "Peak", "Times");
  205. fprintf (stderr, "-------------------------------------------------------\n");
  206. htab_traverse (vec_desc_hash, add_statistics, &nentries);
  207. qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
  208. for (i = 0; i < nentries; i++)
  209. {
  210. struct vec_descriptor *d = loc_array[i];
  211. allocated += d->allocated;
  212. times += d->times;
  213. }
  214. for (i = 0; i < nentries; i++)
  215. {
  216. struct vec_descriptor *d = loc_array[i];
  217. const char *s1 = d->file;
  218. const char *s2;
  219. while ((s2 = strstr (s1, "gcc/")))
  220. s1 = s2 + 4;
  221. sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
  222. s[48] = 0;
  223. fprintf (stderr, "%-48s %10li:%4.1f%% %10li %10li:%4.1f%% \n", s,
  224. (long)d->allocated,
  225. (d->allocated) * 100.0 / allocated,
  226. (long)d->peak,
  227. (long)d->times,
  228. (d->times) * 100.0 / times);
  229. }
  230. fprintf (stderr, "%-48s %10ld %10ld\n",
  231. "Total", (long)allocated, (long)times);
  232. fprintf (stderr, "\n%-48s %10s %10s %10s\n",
  233. "source location", "Leak", "Peak", "Times");
  234. fprintf (stderr, "-------------------------------------------------------\n");
  235. }