1 /* Vector API for GNU compiler. 2 Copyright (C) 2004-2016 Free Software Foundation, Inc. 3 Contributed by Nathan Sidwell <nathan@codesourcery.com> 4 Re-implemented in C++ by Diego Novillo <dnovillo@google.com> 5 6 This file is part of GCC. 7 8 GCC is free software; you can redistribute it and/or modify it under 9 the terms of the GNU General Public License as published by the Free 10 Software Foundation; either version 3, or (at your option) any later 11 version. 12 13 GCC is distributed in the hope that it will be useful, but WITHOUT ANY 14 WARRANTY; without even the implied warranty of MERCHANTABILITY or 15 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 16 for more details. 17 18 You should have received a copy of the GNU General Public License 19 along with GCC; see the file COPYING3. If not see 20 <http://www.gnu.org/licenses/>. */ 21 22 /* This file is compiled twice: once for the generator programs 23 once for the compiler. */ 24 #ifdef GENERATOR_FILE 25 #include "bconfig.h" 26 #else 27 #include "config.h" 28 #endif 29 30 #include "system.h" 31 #include "coretypes.h" 32 #include "hash-table.h" 33 34 /* vNULL is an empty type with a template cast operation that returns 35 a zero-initialized vec<T, A, L> instance. Use this when you want 36 to assign nil values to new vec instances or pass a nil vector as 37 a function call argument. 38 39 We use this technique because vec<T, A, L> must be PODs (they are 40 stored in unions and passed in vararg functions), this means that 41 they cannot have ctors/dtors. */ 42 vnull vNULL; 43 44 /* Vector memory usage. */ 45 struct vec_usage: public mem_usage 46 { 47 /* Default constructor. */ 48 vec_usage (): m_items (0), m_items_peak (0) {} 49 50 /* Constructor. */ 51 vec_usage (size_t allocated, size_t times, size_t peak, 52 size_t items, size_t items_peak) 53 : mem_usage (allocated, times, peak), 54 m_items (items), m_items_peak (items_peak) {} 55 56 /* Comparison operator. */ 57 inline bool 58 operator< (const vec_usage &second) const 59 { 60 return (m_allocated == second.m_allocated ? 61 (m_peak == second.m_peak ? m_times < second.m_times 62 : m_peak < second.m_peak) : m_allocated < second.m_allocated); 63 } 64 65 /* Sum the usage with SECOND usage. */ 66 vec_usage 67 operator+ (const vec_usage &second) 68 { 69 return vec_usage (m_allocated + second.m_allocated, 70 m_times + second.m_times, 71 m_peak + second.m_peak, 72 m_items + second.m_items, 73 m_items_peak + second.m_items_peak); 74 } 75 76 /* Dump usage coupled to LOC location, where TOTAL is sum of all rows. */ 77 inline void 78 dump (mem_location *loc, mem_usage &total) const 79 { 80 char s[4096]; 81 sprintf (s, "%s:%i (%s)", loc->get_trimmed_filename (), 82 loc->m_line, loc->m_function); 83 84 s[48] = '\0'; 85 86 fprintf (stderr, "%-48s %10li:%4.1f%%%10li%10li:%4.1f%%%11li%11li\n", s, 87 (long)m_allocated, m_allocated * 100.0 / total.m_allocated, 88 (long)m_peak, (long)m_times, m_times * 100.0 / total.m_times, 89 (long)m_items, (long)m_items_peak); 90 } 91 92 /* Dump footer. */ 93 inline void 94 dump_footer () 95 { 96 print_dash_line (); 97 fprintf (stderr, "%s%55li%25li%17li\n", "Total", (long)m_allocated, 98 (long)m_times, (long)m_items); 99 print_dash_line (); 100 } 101 102 /* Dump header with NAME. */ 103 static inline void 104 dump_header (const char *name) 105 { 106 fprintf (stderr, "%-48s %11s%15s%10s%17s%11s\n", name, "Leak", "Peak", 107 "Times", "Leak items", "Peak items"); 108 print_dash_line (); 109 } 110 111 /* Compare wrapper used by qsort method. */ 112 static int 113 compare (const void *first, const void *second) 114 { 115 typedef std::pair<mem_location *, vec_usage *> mem_pair_t; 116 117 const mem_pair_t f = *(const mem_pair_t *)first; 118 const mem_pair_t s = *(const mem_pair_t *)second; 119 120 return (*f.second) < (*s.second); 121 } 122 123 /* Current number of items allocated. */ 124 size_t m_items; 125 /* Peak value of number of allocated items. */ 126 size_t m_items_peak; 127 }; 128 129 /* Vector memory description. */ 130 static mem_alloc_description <vec_usage> vec_mem_desc; 131 132 /* Account the overhead. */ 133 134 void 135 vec_prefix::register_overhead (void *ptr, size_t size, size_t elements 136 MEM_STAT_DECL) 137 { 138 vec_mem_desc.register_descriptor (ptr, VEC_ORIGIN, false 139 FINAL_PASS_MEM_STAT); 140 vec_usage *usage = vec_mem_desc.register_instance_overhead (size, ptr); 141 usage->m_items += elements; 142 if (usage->m_items_peak < usage->m_items) 143 usage->m_items_peak = usage->m_items; 144 } 145 146 /* Notice that the memory allocated for the vector has been freed. */ 147 148 void 149 vec_prefix::release_overhead (void *ptr, size_t size, bool in_dtor 150 MEM_STAT_DECL) 151 { 152 if (!vec_mem_desc.contains_descriptor_for_instance (ptr)) 153 vec_mem_desc.register_descriptor (ptr, VEC_ORIGIN, 154 false FINAL_PASS_MEM_STAT); 155 vec_mem_desc.release_instance_overhead (ptr, size, in_dtor); 156 } 157 158 159 /* Calculate the number of slots to reserve a vector, making sure that 160 it is of at least DESIRED size by growing ALLOC exponentially. */ 161 162 unsigned 163 vec_prefix::calculate_allocation_1 (unsigned alloc, unsigned desired) 164 { 165 /* We must have run out of room. */ 166 gcc_assert (alloc < desired); 167 168 /* Exponential growth. */ 169 if (!alloc) 170 alloc = 4; 171 else if (alloc < 16) 172 /* Double when small. */ 173 alloc = alloc * 2; 174 else 175 /* Grow slower when large. */ 176 alloc = (alloc * 3 / 2); 177 178 /* If this is still too small, set it to the right size. */ 179 if (alloc < desired) 180 alloc = desired; 181 return alloc; 182 } 183 184 /* Dump per-site memory statistics. */ 185 186 void 187 dump_vec_loc_statistics (void) 188 { 189 vec_mem_desc.dump (VEC_ORIGIN); 190 } 191