This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

VEC memory statistics


Hi,
this patch adds statistics to our vector datastrutures.  Implementation is
about the same as for garbage collected memory: there is hashtable of source
level locations collecting memory allocation for each call and hashtable for
every vector recording where it was allocated so freeing it updates first
table.

We collect memory leaks and peak memory usage per vector.
Bootstrapped/regtested x86_64-linux, OK?

Honza

	* toplev.c (dump_memory_report): Call dump_vec_loc_statistics.
	* vec.c: Include hashtab.h
	(vec_descriptor, ptr_hash_entry): New structures.
	(vec_desc_hash, vec_ptr_map): New static variables.
	(hash_descriptor, eq_descriptor, hash_ptr, eq_ptr, vec_descriptor,
	register_overhead, free_overhead, vec_heap_free): New functions.
	(vec_gc_o_reserve_1): ggc_free when resizing to 0.
	(vec_heap_o_reserve_1): free when resizing to 0; add statistics.
	(cmp_statistic, add_statistics, dump_vec_loc_statistics): New functions.
Index: toplev.c
===================================================================
*** toplev.c	(revision 140271)
--- toplev.c	(working copy)
*************** dump_memory_report (bool final)
*** 2120,2125 ****
--- 2120,2126 ----
    dump_varray_statistics ();
    dump_alloc_pool_statistics ();
    dump_bitmap_statistics ();
+   dump_vec_loc_statistics ();
    dump_ggc_loc_statistics (final);
  }
  
Index: vec.c
===================================================================
*** vec.c	(revision 140271)
--- vec.c	(working copy)
*************** along with GCC; see the file COPYING3.  
*** 31,36 ****
--- 31,37 ----
  #include "vec.h"
  #include "coretypes.h"
  #include "toplev.h"
+ #include "hashtab.h"
  
  struct vec_prefix 
  {
*************** struct vec_prefix 
*** 39,44 ****
--- 40,174 ----
    void *vec[1];
  };
  
+ 
+ #ifdef GATHER_STATISTICS
+ 
+ /* Store information about each particular bitmap.  */
+ struct vec_descriptor
+ {
+   const char *function;
+   const char *file;
+   int line;
+   size_t allocated;
+   size_t times;
+   size_t peak;
+ };
+ 
+ 
+ /* Hashtable mapping vec addresses to descriptors.  */
+ static htab_t vec_desc_hash;
+ 
+ /* Hashtable helpers.  */
+ static hashval_t
+ hash_descriptor (const void *p)
+ {
+   const struct vec_descriptor *const d =
+     (const struct vec_descriptor *) p;
+   return htab_hash_pointer (d->file) + d->line;
+ }
+ static int
+ eq_descriptor (const void *p1, const void *p2)
+ {
+   const struct vec_descriptor *const d = (const struct vec_descriptor *) p1;
+   const struct vec_descriptor *const l = (const struct vec_descriptor *) p2;
+   return d->file == l->file && d->function == l->function && d->line == l->line;
+ }
+ 
+ /* Hashtable converting address of allocated field to loc descriptor.  */
+ static htab_t ptr_hash;
+ struct ptr_hash_entry
+ {
+   void *ptr;
+   struct vec_descriptor *loc;
+   size_t allocated;
+ };
+ 
+ /* Hash table helpers functions.  */
+ static hashval_t
+ hash_ptr (const void *p)
+ {
+   const struct ptr_hash_entry *const d = (const struct ptr_hash_entry *) p;
+ 
+   return htab_hash_pointer (d->ptr);
+ }
+ 
+ static int
+ eq_ptr (const void *p1, const void *p2)
+ {
+   const struct ptr_hash_entry *const p = (const struct ptr_hash_entry *) p1;
+ 
+   return (p->ptr == p2);
+ }
+ 
+ /* Return descriptor for given call site, create new one if needed.  */
+ static struct vec_descriptor *
+ vec_descriptor (const char *name, int line, const char *function)
+ {
+   struct vec_descriptor loc;
+   struct vec_descriptor **slot;
+ 
+   loc.file = name;
+   loc.line = line;
+   loc.function = function;
+   if (!vec_desc_hash)
+     vec_desc_hash = htab_create (10, hash_descriptor, eq_descriptor, NULL);
+ 
+   slot = (struct vec_descriptor **) htab_find_slot (vec_desc_hash, &loc, 1);
+   if (*slot)
+     return *slot;
+   *slot = XCNEW (struct vec_descriptor);
+   (*slot)->file = name;
+   (*slot)->line = line;
+   (*slot)->function = function;
+   (*slot)->allocated = 0;
+   (*slot)->peak = 0;
+   return *slot;
+ }
+ 
+ /* Account the overhead.  */
+ static void
+ register_overhead (struct vec_prefix *ptr, size_t size,
+ 		   const char *name, int line, const char *function)
+ {
+   struct vec_descriptor *loc = vec_descriptor (name, line, function);
+   struct ptr_hash_entry *p = XNEW (struct ptr_hash_entry);
+   PTR *slot;
+ 
+   p->ptr = ptr;
+   p->loc = loc;
+   p->allocated = size;
+   if (!ptr_hash)
+     ptr_hash = htab_create (10, hash_ptr, eq_ptr, NULL);
+   slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr), INSERT);
+   gcc_assert (!*slot);
+   *slot = p;
+ 
+   loc->allocated += size;
+   if (loc->peak < loc->allocated)
+     loc->peak += loc->allocated;
+   loc->times++;
+ }
+ 
+ /* Notice that the pointer has been freed.  */
+ static void
+ free_overhead (struct vec_prefix *ptr)
+ {
+   PTR *slot = htab_find_slot_with_hash (ptr_hash, ptr, htab_hash_pointer (ptr),
+ 					NO_INSERT);
+   struct ptr_hash_entry *p = (struct ptr_hash_entry *) *slot;
+   p->loc->allocated -= p->allocated;
+   htab_clear_slot (ptr_hash, slot);
+   free (p);
+ }
+ 
+ void
+ vec_heap_free (void *ptr)
+ {
+   free_overhead ((struct vec_prefix *)ptr);
+   free (ptr);
+ }
+ #endif
+ 
  /* Calculate the new ALLOC value, making sure that RESERVE slots are
     free.  If EXACT grow exactly, otherwise grow exponentially.  */
  
*************** vec_gc_o_reserve_1 (void *vec, int reser
*** 99,105 ****
    unsigned alloc = alloc = calculate_allocation (pfx, reserve, exact);
    
    if (!alloc)
!     return NULL;
    
    vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
    ((struct vec_prefix *)vec)->alloc = alloc;
--- 230,240 ----
    unsigned alloc = alloc = calculate_allocation (pfx, reserve, exact);
    
    if (!alloc)
!     {
!       if (pfx)
!         ggc_free (pfx);
!       return NULL;
!     }
    
    vec = ggc_realloc_stat (vec, vec_offset + alloc * elt_size PASS_MEM_STAT);
    ((struct vec_prefix *)vec)->alloc = alloc;
*************** vec_heap_o_reserve_1 (void *vec, int res
*** 171,182 ****
    unsigned alloc = calculate_allocation (pfx, reserve, exact);
  
    if (!alloc)
!     return NULL;
    
    vec = xrealloc (vec, vec_offset + alloc * elt_size);
    ((struct vec_prefix *)vec)->alloc = alloc;
    if (!pfx)
      ((struct vec_prefix *)vec)->num = 0;
    
    return vec;
  }
--- 306,331 ----
    unsigned alloc = calculate_allocation (pfx, reserve, exact);
  
    if (!alloc)
!     {
!       if (pfx)
!         vec_heap_free (pfx);
!       return NULL;
!     }
! 
! #ifdef GATHER_STATISTICS
!   if (vec)
!     free_overhead (pfx);
! #endif
    
    vec = xrealloc (vec, vec_offset + alloc * elt_size);
    ((struct vec_prefix *)vec)->alloc = alloc;
    if (!pfx)
      ((struct vec_prefix *)vec)->num = 0;
+ #ifdef GATHER_STATISTICS
+   if (vec)
+     register_overhead ((struct vec_prefix *)vec,
+     		       vec_offset + alloc * elt_size PASS_MEM_STAT);
+ #endif
    
    return vec;
  }
*************** vec_assert_fail (const char *op, const c
*** 234,236 ****
--- 383,462 ----
  		  struct_name, op, function, trim_filename (file), line);
  }
  #endif
+ 
+ #ifdef GATHER_STATISTICS
+ /* Helper for qsort; sort descriptors by amount of memory consumed.  */
+ static int
+ cmp_statistic (const void *loc1, const void *loc2)
+ {
+   const struct vec_descriptor *const l1 =
+     *(const struct vec_descriptor *const *) loc1;
+   const struct vec_descriptor *const l2 =
+     *(const struct vec_descriptor *const *) loc2;
+   long diff;
+   diff = l1->allocated - l2->allocated;
+   if (!diff)
+     diff = l1->peak - l2->peak;
+   if (!diff)
+     diff = l1->times - l2->times;
+   return diff > 0 ? 1 : diff < 0 ? -1 : 0;
+ }
+ /* Collect array of the descriptors from hashtable.  */
+ static struct vec_descriptor **loc_array;
+ static int
+ add_statistics (void **slot, void *b)
+ {
+   int *n = (int *)b;
+   loc_array[*n] = (struct vec_descriptor *) *slot;
+   (*n)++;
+   return 1;
+ }
+ 
+ /* Dump per-site memory statistics.  */
+ #endif
+ void
+ dump_vec_loc_statistics (void)
+ {
+ #ifdef GATHER_STATISTICS
+   int nentries = 0;
+   char s[4096];
+   size_t allocated = 0;
+   size_t times = 0;
+   int i;
+ 
+   loc_array = XCNEWVEC (struct vec_descriptor *, vec_desc_hash->n_elements);
+   fprintf (stderr, "Heap vectors:\n");
+   fprintf (stderr, "\n%-48s %10s       %10s       %10s\n",
+ 	   "source location", "Leak", "Peak", "Times");
+   fprintf (stderr, "-------------------------------------------------------\n");
+   htab_traverse (vec_desc_hash, add_statistics, &nentries);
+   qsort (loc_array, nentries, sizeof (*loc_array), cmp_statistic);
+   for (i = 0; i < nentries; i++)
+     {
+       struct vec_descriptor *d = loc_array[i];
+       allocated += d->allocated;
+       times += d->times;
+     }
+   for (i = 0; i < nentries; i++)
+     {
+       struct vec_descriptor *d = loc_array[i];
+       const char *s1 = d->file;
+       const char *s2;
+       while ((s2 = strstr (s1, "gcc/")))
+ 	s1 = s2 + 4;
+       sprintf (s, "%s:%i (%s)", s1, d->line, d->function);
+       s[48] = 0;
+       fprintf (stderr, "%-48s %10li:%4.1f%% %10li      %10li:%4.1f%% \n", s,
+ 	       (long)d->allocated,
+ 	       (d->allocated) * 100.0 / allocated,
+ 	       (long)d->peak,
+ 	       (long)d->times,
+ 	       (d->times) * 100.0 / times);
+     }
+   fprintf (stderr, "%-48s %10ld                        %10ld\n",
+ 	   "Total", (long)allocated, (long)times);
+   fprintf (stderr, "\n%-48s %10s       %10s       %10s\n",
+ 	   "source location", "Leak", "Peak", "Times");
+   fprintf (stderr, "-------------------------------------------------------\n");
+ #endif
+ }
Index: vec.h
===================================================================
*** vec.h	(revision 140271)
--- vec.h	(working copy)
*************** extern void *vec_heap_p_reserve_exact (v
*** 429,435 ****
--- 429,440 ----
  extern void *vec_heap_o_reserve (void *, int, size_t, size_t MEM_STAT_DECL);
  extern void *vec_heap_o_reserve_exact (void *, int, size_t, size_t
  				       MEM_STAT_DECL);
+ extern void dump_vec_loc_statistics (void);
+ #ifdef GATHER_STATISTICS
+ void vec_heap_free (void *);
+ #else
  #define vec_heap_free(V) free (V)
+ #endif
  
  #if ENABLE_CHECKING
  #define VEC_CHECK_INFO ,__FILE__,__LINE__,__FUNCTION__


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]