00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "config.h"
00025 #include "system.h"
00026 #include "rtl.h"
00027 #include "tree.h"
00028 #include "tm_p.h"
00029 #include "hashtab.h"
00030 #include "varray.h"
00031 #include "ggc.h"
00032 #include "langhooks.h"
00033 #include "params.h"
00034 #ifdef HAVE_SYS_RESOURCE_H
00035 # include <sys/resource.h>
00036 #endif
00037 #ifdef ENABLE_VALGRIND_CHECKING
00038 #include <valgrind.h>
00039 #else
00040
00041 #define VALGRIND_DISCARD(x)
00042 #endif
00043
00044
00045 static ggc_statistics *ggc_stats;
00046
00047 static int ggc_htab_delete PARAMS ((void **, void *));
00048 static double ggc_rlimit_bound PARAMS ((double));
00049
00050
00051
00052
00053
00054 struct ggc_root
00055 {
00056 struct ggc_root *next;
00057 void *base;
00058 int nelt;
00059 int size;
00060 void (*cb) PARAMS ((void *));
00061 };
00062
00063 static struct ggc_root *roots;
00064
00065
00066
00067
00068
00069
00070
00071 void
00072 ggc_add_root (base, nelt, size, cb)
00073 void *base;
00074 int nelt, size;
00075 void (*cb) PARAMS ((void *));
00076 {
00077 struct ggc_root *x = (struct ggc_root *) xmalloc (sizeof (*x));
00078
00079 x->next = roots;
00080 x->base = base;
00081 x->nelt = nelt;
00082 x->size = size;
00083 x->cb = cb;
00084
00085 roots = x;
00086 }
00087
00088
00089
00090 static int
00091 ggc_htab_delete (slot, info)
00092 void **slot;
00093 void *info;
00094 {
00095 const struct ggc_cache_tab *r = (const struct ggc_cache_tab *) info;
00096
00097 if (! (*r->marked_p) (*slot))
00098 htab_clear_slot (*r->base, slot);
00099 else
00100 (*r->cb) (*slot);
00101
00102 return 1;
00103 }
00104
00105
00106
00107 void
00108 ggc_mark_roots ()
00109 {
00110 struct ggc_root *x;
00111 const struct ggc_root_tab *const *rt;
00112 const struct ggc_root_tab *rti;
00113 const struct ggc_cache_tab *const *ct;
00114 const struct ggc_cache_tab *cti;
00115 size_t i;
00116
00117 for (rt = gt_ggc_deletable_rtab; *rt; rt++)
00118 for (rti = *rt; rti->base != NULL; rti++)
00119 memset (rti->base, 0, rti->stride);
00120
00121 for (rt = gt_ggc_rtab; *rt; rt++)
00122 for (rti = *rt; rti->base != NULL; rti++)
00123 for (i = 0; i < rti->nelt; i++)
00124 (*rti->cb)(*(void **)((char *)rti->base + rti->stride * i));
00125
00126 for (x = roots; x != NULL; x = x->next)
00127 {
00128 char *elt = x->base;
00129 int s = x->size, n = x->nelt;
00130 void (*cb) PARAMS ((void *)) = x->cb;
00131 int i;
00132
00133 for (i = 0; i < n; ++i, elt += s)
00134 (*cb)(elt);
00135 }
00136
00137
00138
00139 for (ct = gt_ggc_cache_rtab; *ct; ct++)
00140 for (cti = *ct; cti->base != NULL; cti++)
00141 if (*cti->base)
00142 htab_traverse (*cti->base, ggc_htab_delete, (PTR) cti);
00143 }
00144
00145
00146 void *
00147 ggc_alloc_cleared (size)
00148 size_t size;
00149 {
00150 void *buf = ggc_alloc (size);
00151 memset (buf, 0, size);
00152 return buf;
00153 }
00154
00155
00156 void *
00157 ggc_realloc (x, size)
00158 void *x;
00159 size_t size;
00160 {
00161 void *r;
00162 size_t old_size;
00163
00164 if (x == NULL)
00165 return ggc_alloc (size);
00166
00167 old_size = ggc_get_size (x);
00168 if (size <= old_size)
00169 {
00170
00171
00172
00173
00174
00175
00176
00177
00178
00179
00180 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS ((char *) x + size,
00181 old_size - size));
00182 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, size));
00183 return x;
00184 }
00185
00186 r = ggc_alloc (size);
00187
00188
00189
00190
00191
00192 VALGRIND_DISCARD (VALGRIND_MAKE_READABLE (x, old_size));
00193
00194 memcpy (r, x, old_size);
00195
00196
00197 VALGRIND_DISCARD (VALGRIND_MAKE_NOACCESS (x, old_size));
00198
00199 return r;
00200 }
00201
00202
00203 void *
00204 ggc_calloc (s1, s2)
00205 size_t s1, s2;
00206 {
00207 return ggc_alloc_cleared (s1 * s2);
00208 }
00209
00210
00211 #define SCALE(x) ((unsigned long) ((x) < 1024*10 \
00212 ? (x) \
00213 : ((x) < 1024*1024*10 \
00214 ? (x) / 1024 \
00215 : (x) / (1024*1024))))
00216 #define LABEL(x) ((x) < 1024*10 ? ' ' : ((x) < 1024*1024*10 ? 'k' : 'M'))
00217
00218 void
00219 ggc_print_common_statistics (stream, stats)
00220 FILE *stream;
00221 ggc_statistics *stats;
00222 {
00223 int code;
00224
00225
00226
00227 ggc_stats = stats;
00228
00229
00230 ggc_collect ();
00231
00232
00233 for (code = 0; code < MAX_TREE_CODES; ++code)
00234 {
00235 stats->total_num_trees += stats->num_trees[code];
00236 stats->total_size_trees += stats->size_trees[code];
00237 }
00238 for (code = 0; code < NUM_RTX_CODE; ++code)
00239 {
00240 stats->total_num_rtxs += stats->num_rtxs[code];
00241 stats->total_size_rtxs += stats->size_rtxs[code];
00242 }
00243
00244
00245 fprintf (stream, "\n%-17s%10s %16s %10s\n", "Tree",
00246 "Number", "Bytes", "% Total");
00247 for (code = 0; code < MAX_TREE_CODES; ++code)
00248 if (ggc_stats->num_trees[code])
00249 {
00250 fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
00251 tree_code_name[code],
00252 ggc_stats->num_trees[code],
00253 SCALE (ggc_stats->size_trees[code]),
00254 LABEL (ggc_stats->size_trees[code]),
00255 (100 * ((double) ggc_stats->size_trees[code])
00256 / ggc_stats->total_size_trees));
00257 }
00258 fprintf (stream,
00259 "%-17s%10u%16ld%c\n", "Total",
00260 ggc_stats->total_num_trees,
00261 SCALE (ggc_stats->total_size_trees),
00262 LABEL (ggc_stats->total_size_trees));
00263
00264
00265 fprintf (stream, "\n%-17s%10s %16s %10s\n", "RTX",
00266 "Number", "Bytes", "% Total");
00267 for (code = 0; code < NUM_RTX_CODE; ++code)
00268 if (ggc_stats->num_rtxs[code])
00269 {
00270 fprintf (stream, "%-17s%10u%16ld%c %10.3f\n",
00271 rtx_name[code],
00272 ggc_stats->num_rtxs[code],
00273 SCALE (ggc_stats->size_rtxs[code]),
00274 LABEL (ggc_stats->size_rtxs[code]),
00275 (100 * ((double) ggc_stats->size_rtxs[code])
00276 / ggc_stats->total_size_rtxs));
00277 }
00278 fprintf (stream,
00279 "%-17s%10u%16ld%c\n", "Total",
00280 ggc_stats->total_num_rtxs,
00281 SCALE (ggc_stats->total_size_rtxs),
00282 LABEL (ggc_stats->total_size_rtxs));
00283
00284
00285 ggc_stats = NULL;
00286 }
00287
00288
00289 static double
00290 ggc_rlimit_bound (limit)
00291 double limit;
00292 {
00293 #if defined(HAVE_GETRLIMIT)
00294 struct rlimit rlim;
00295 # ifdef RLIMIT_RSS
00296 if (getrlimit (RLIMIT_RSS, &rlim) == 0
00297 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
00298 && rlim.rlim_cur < limit)
00299 limit = rlim.rlim_cur;
00300 # endif
00301 # ifdef RLIMIT_DATA
00302 if (getrlimit (RLIMIT_DATA, &rlim) == 0
00303 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
00304 && rlim.rlim_cur < limit)
00305 limit = rlim.rlim_cur;
00306 # endif
00307 # ifdef RLIMIT_AS
00308 if (getrlimit (RLIMIT_AS, &rlim) == 0
00309 && rlim.rlim_cur != (rlim_t) RLIM_INFINITY
00310 && rlim.rlim_cur < limit)
00311 limit = rlim.rlim_cur;
00312 # endif
00313 #endif
00314
00315 return limit;
00316 }
00317
00318
00319 int
00320 ggc_min_expand_heuristic()
00321 {
00322 double min_expand = physmem_total();
00323
00324
00325 min_expand = ggc_rlimit_bound (min_expand);
00326
00327
00328
00329 min_expand /= 1024*1024*1024;
00330 min_expand *= 70;
00331 min_expand = MIN (min_expand, 70);
00332 min_expand += 30;
00333
00334 return min_expand;
00335 }
00336
00337
00338 int
00339 ggc_min_heapsize_heuristic()
00340 {
00341 double min_heap_kbytes = physmem_total();
00342
00343
00344 min_heap_kbytes = ggc_rlimit_bound (min_heap_kbytes);
00345
00346 min_heap_kbytes /= 1024;
00347
00348
00349
00350 min_heap_kbytes /= 8;
00351 min_heap_kbytes = MAX (min_heap_kbytes, 4 * 1024);
00352 min_heap_kbytes = MIN (min_heap_kbytes, 128 * 1024);
00353
00354 return min_heap_kbytes;
00355 }
00356
00357 void
00358 init_ggc_heuristics ()
00359 {
00360 #ifndef ENABLE_GC_ALWAYS_COLLECT
00361 set_param_value ("ggc-min-expand", ggc_min_expand_heuristic());
00362 set_param_value ("ggc-min-heapsize", ggc_min_heapsize_heuristic());
00363 #endif
00364 }