Add a statistic for tracking how many cells are marked conservatively.
[bpt/guile.git] / libguile / gc-segment.c
CommitLineData
2b829bbb 1/* Copyright (C) 1995,1996,1997,1998,1999,2000,2001, 2002, 2006 Free Software Foundation, Inc.
c7743d02 2 *
73be1d9e
MV
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 2.1 of the License, or (at your option) any later version.
c7743d02 7 *
73be1d9e 8 * This library is distributed in the hope that it will be useful,
c7743d02 9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
73be1d9e
MV
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
c7743d02 12 *
73be1d9e
MV
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, write to the Free Software
92205699 15 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
73be1d9e 16 */
c7743d02
HWN
17
18#include <assert.h>
19#include <stdio.h>
20#include <string.h>
21
22#include "libguile/_scm.h"
23#include "libguile/pairs.h"
24#include "libguile/gc.h"
25#include "libguile/private-gc.h"
26
c7743d02
HWN
27size_t scm_max_segment_size;
28
82ae1b8e
HWN
29/* Important entry point: try to grab some memory, and make it into a
30 segment; return the index of the segment. SWEEP_STATS should contain
31 global GC sweep statistics collected since the last full GC.
32
33 Returns the index of the segment. If error_policy !=
34 abort_on_error, we return -1 on failure.
35*/
36int
37scm_i_get_new_heap_segment (scm_t_cell_type_statistics *freelist,
38 size_t len,
39 policy_on_error error_policy)
40{
41 if (len > scm_max_segment_size)
42 len = scm_max_segment_size;
43
44 if (len < SCM_MIN_HEAP_SEG_SIZE)
45 len = SCM_MIN_HEAP_SEG_SIZE;
46
40945e5e 47 /* todo: consider having a more flexible lower bound. */
82ae1b8e
HWN
48 {
49 scm_t_heap_segment *seg = scm_i_make_empty_heap_segment (freelist);
50
51 /* Allocate with decaying ambition. */
52 while (len >= SCM_MIN_HEAP_SEG_SIZE)
53 {
54 if (scm_i_initialize_heap_segment_data (seg, len))
55 return scm_i_insert_segment (seg);
56
57 len /= 2;
58 }
59 }
60
61 if (error_policy == abort_on_error)
62 {
63 fprintf (stderr, "scm_i_get_new_heap_segment: Could not grow heap.\n");
64 abort ();
65 }
66 return -1;
67}
68
69
c7743d02
HWN
70scm_t_heap_segment *
71scm_i_make_empty_heap_segment (scm_t_cell_type_statistics *fl)
72{
82ae1b8e 73 scm_t_heap_segment *shs = calloc (1, sizeof (scm_t_heap_segment));
c7743d02
HWN
74
75 if (!shs)
76 {
77 fprintf (stderr, "scm_i_get_new_heap_segment: out of memory.\n");
78 abort ();
79 }
80
c7743d02
HWN
81 shs->span = fl->span;
82 shs->freelist = fl;
c7743d02
HWN
83
84 return shs;
85}
86
1367aa5e
HWN
87void
88scm_i_heap_segment_statistics (scm_t_heap_segment *seg, SCM tab)
89{
90 scm_t_cell *p = seg->bounds[0];
91 while (p < seg->bounds[1])
92 {
93 scm_i_card_statistics (p, tab, seg);
94 p += SCM_GC_CARD_N_CELLS;
95 }
96}
97
82ae1b8e
HWN
98/*
99 count number of marked bits, so we know how much cells are live.
100 */
101int
102scm_i_heap_segment_marked_count (scm_t_heap_segment *seg)
103{
104 scm_t_c_bvec_long *bvec = (scm_t_c_bvec_long *) seg->bounds[1];
105 scm_t_c_bvec_long *bvec_end =
106 (bvec +
107 scm_i_segment_card_count (seg) * SCM_GC_CARD_BVEC_SIZE_IN_LONGS);
108
109 int count = 0;
110 while (bvec < bvec_end) {
111 count += scm_i_uint_bit_count(*bvec);
112 bvec ++;
113 }
114 return count * seg->span;
115}
116
117int
118scm_i_segment_card_number (scm_t_heap_segment *seg,
119 scm_t_cell *card)
120{
121 return (card - seg->bounds[0]) / SCM_GC_CARD_N_CELLS;
122}
123
c7743d02
HWN
124/*
125 Fill SEGMENT with memory both for data and mark bits.
126
82ae1b8e 127 RETURN: 1 on success, 0 failure
c7743d02
HWN
128 */
129int
82ae1b8e 130scm_i_initialize_heap_segment_data (scm_t_heap_segment *segment, size_t requested)
c7743d02
HWN
131{
132 /*
133 round upwards
134 */
135 int card_data_cell_count = (SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS);
82ae1b8e 136 int card_count = 1 + (requested / sizeof (scm_t_cell)) / card_data_cell_count;
c7743d02
HWN
137
138 /*
139 one card extra due to alignment
140 */
82ae1b8e
HWN
141 size_t mem_needed = (1 + card_count) * SCM_GC_SIZEOF_CARD
142 + SCM_GC_CARD_BVEC_SIZE_IN_LONGS * card_count * SCM_SIZEOF_LONG;
143 scm_t_cell *memory = 0;
c7743d02
HWN
144
145 /*
82ae1b8e 146 We use calloc to alloc the heap, so it is nicely initialized.
c7743d02 147 */
82ae1b8e 148 SCM_SYSCALL (memory = (scm_t_cell *) calloc (1, mem_needed));
c7743d02
HWN
149
150 if (memory == NULL)
151 return 0;
152
153 segment->malloced = memory;
154 segment->bounds[0] = SCM_GC_CARD_UP (memory);
155 segment->bounds[1] = segment->bounds[0] + card_count * SCM_GC_CARD_N_CELLS;
82ae1b8e 156 segment->freelist->heap_total_cells += scm_i_segment_cell_count (segment);
c7743d02 157
1383773b
HWN
158 /*
159 Don't init the mem or the bitvector. This is handled by lazy
160 sweeping.
161 */
c7743d02
HWN
162 segment->next_free_card = segment->bounds[0];
163 segment->first_time = 1;
164 return 1;
165}
166
167int
82ae1b8e 168scm_i_segment_card_count (scm_t_heap_segment *seg)
c7743d02
HWN
169{
170 return (seg->bounds[1] - seg->bounds[0]) / SCM_GC_CARD_N_CELLS;
171}
172
173/*
174 Return the number of available single-cell data cells.
175 */
176int
82ae1b8e
HWN
177scm_i_segment_cell_count (scm_t_heap_segment *seg)
178{
179 return scm_i_segment_card_count (seg)
180 * scm_i_segment_cells_per_card (seg);
181}
182
183int
184scm_i_segment_cells_per_card (scm_t_heap_segment *seg)
c7743d02 185{
82ae1b8e
HWN
186 return (SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS
187 + ((seg->span == 2) ? -1 : 0));
c7743d02
HWN
188}
189
190void
191scm_i_clear_segment_mark_space (scm_t_heap_segment *seg)
192{
82ae1b8e 193 scm_t_cell *markspace = seg->bounds[1];
c7743d02
HWN
194
195 memset (markspace, 0x00,
82ae1b8e 196 scm_i_segment_card_count (seg) * SCM_GC_CARD_BVEC_SIZE_IN_LONGS * SCM_SIZEOF_LONG);
c7743d02
HWN
197}
198
82ae1b8e
HWN
199
200/*
201 Force a sweep of this entire segment.
202 */
203void
204scm_i_sweep_segment (scm_t_heap_segment *seg,
205 scm_t_sweep_statistics *sweep_stats)
206{
207 int infinity = 1 << 30;
208 scm_t_cell *remember = seg->next_free_card;
209 while (scm_i_sweep_some_cards (seg, sweep_stats, infinity) != SCM_EOL)
210 ;
211 seg->next_free_card = remember;
212}
213
214
215/* Sweep cards from SEG until we've gathered THRESHOLD cells. On
216 return, SWEEP_STATS, if non-NULL, contains the number of cells that
217 have been visited and collected. A freelist is returned,
218 potentially empty. */
c7743d02 219SCM
4c7016dc 220scm_i_sweep_some_cards (scm_t_heap_segment *seg,
82ae1b8e
HWN
221 scm_t_sweep_statistics *sweep_stats,
222 int threshold)
c7743d02
HWN
223{
224 SCM cells = SCM_EOL;
c7743d02 225 int collected = 0;
82ae1b8e 226 int (*sweeper) (scm_t_cell *, SCM *, scm_t_heap_segment *)
1383773b 227 = (seg->first_time) ? &scm_i_init_card_freelist : &scm_i_sweep_card;
c7743d02 228
82ae1b8e 229 scm_t_cell *next_free = seg->next_free_card;
c7743d02 230 int cards_swept = 0;
c7743d02
HWN
231 while (collected < threshold && next_free < seg->bounds[1])
232 {
1383773b 233 collected += (*sweeper) (next_free, &cells, seg);
c7743d02
HWN
234 next_free += SCM_GC_CARD_N_CELLS;
235 cards_swept ++;
236 }
237
82ae1b8e 238 if (sweep_stats != NULL)
4c7016dc 239 {
82ae1b8e
HWN
240 int swept = cards_swept
241 * ((SCM_GC_CARD_N_CELLS - SCM_GC_CARD_N_HEADER_CELLS)
242 - seg->span + 1);
243 int collected_cells = collected * seg->span;
244 sweep_stats->swept += swept;
245 sweep_stats->collected += collected_cells;
4c7016dc 246 }
82ae1b8e
HWN
247
248 if (next_free == seg->bounds[1])
c7743d02
HWN
249 {
250 seg->first_time = 0;
251 }
252
253 seg->next_free_card = next_free;
254 return cells;
255}
256
257
1367aa5e
HWN
258
259SCM
82ae1b8e 260scm_i_sweep_for_freelist (scm_t_cell_type_statistics *freelist)
c7743d02 261{
82ae1b8e
HWN
262 scm_t_sweep_statistics stats = { 0 };
263 SCM result = scm_i_sweep_some_segments (freelist, &stats);
c7743d02 264
82ae1b8e
HWN
265 scm_i_gc_sweep_stats.collected += stats.collected;
266 scm_i_gc_sweep_stats.swept += stats.swept;
c7743d02 267
82ae1b8e
HWN
268 freelist->collected += stats.collected;
269 freelist->swept += stats.swept;
270 return result;
c7743d02
HWN
271}
272