1 #define COLLECTOR_C
2 #include "Collector.h"
3 #undef COLLECTOR_C
4
5 #include <assert.h>
6 #include <time.h>
7
8 #ifdef COLLECTOR_TIMER_ON
9 #define BEGIN_TIMER self->clocksUsed -= clock();
10 #define END_TIMER self->clocksUsed += clock();
11 #else
12 #define BEGIN_TIMER
13 #define END_TIMER
14 #endif
15
Collector_new(void)16 Collector *Collector_new(void)
17 {
18 Collector *self = (Collector *)io_calloc(1, sizeof(Collector));
19
20 self->retainedValues = List_new();
21
22 self->whites = CollectorMarker_new();
23 self->grays = CollectorMarker_new();
24 self->blacks = CollectorMarker_new();
25 self->freed = CollectorMarker_new();
26
27 CollectorMarker_loop(self->whites);
28 CollectorMarker_removeIfNeededAndInsertAfter_(self->grays, self->whites);
29 CollectorMarker_removeIfNeededAndInsertAfter_(self->blacks, self->grays);
30 CollectorMarker_removeIfNeededAndInsertAfter_(self->freed, self->blacks);
31
32 // important to set colors *after* inserts, since inserts set colors
33 CollectorMarker_setColor_(self->whites, COLLECTOR_INITIAL_WHITE);
34 CollectorMarker_setColor_(self->blacks, COLLECTOR_INITIAL_BLACK);
35 CollectorMarker_setColor_(self->grays, COLLECTOR_GRAY);
36 CollectorMarker_setColor_(self->freed, COLLECTOR_FREE);
37
38 Collector_setSafeModeOn_(self, 1);
39 self->allocated = 0;
40
41 self->allocatedSweepLevel = 3000;
42 self->allocatedStep = 1.1f;
43 self->marksPerAlloc = 2;
44
45 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
46 self->allocsPerSweep = 10000;
47 #endif
48
49 self->clocksUsed = 0;
50
51 Collector_check(self);
52
53 return self;
54 }
55
Collector_check(Collector * self)56 void Collector_check(Collector *self)
57 {
58 CollectorMarker *w = self->whites;
59 CollectorMarker *g = self->grays;
60 CollectorMarker *b = self->blacks;
61
62 // colors are different
63 assert(w->color != g->color);
64 assert(w->color != b->color);
65 assert(g->color != b->color);
66
67 // prev color is different
68 assert(w->prev->color != w->color);
69 assert(g->prev->color != g->color);
70 assert(b->prev->color != b->color);
71
72 CollectorMarker_check(w);
73 }
74
CollectorMarker_checkObjectPointer(CollectorMarker * marker)75 size_t CollectorMarker_checkObjectPointer(CollectorMarker *marker)
76 {
77 if (marker->object == NULL)
78 {
79 printf("WARNING: Collector found a null object pointer on marker %p! Memory is likely hosed.\n", (void *)marker);
80 exit(-1);
81 return 1;
82 }
83 else
84 {
85 // read a word of memory to check for bad pointers
86 uintptr_t p = *(uintptr_t *)(marker->object);
87 return p-p; // so compiler doesn't complain about unused variable
88 }
89
90 return 0;
91 }
92
Collector_checkObjectPointers(Collector * self)93 void Collector_checkObjectPointers(Collector *self)
94 {
95 COLLECTMARKER_FOREACH(self->blacks, v, CollectorMarker_checkObjectPointer(v); );
96 COLLECTMARKER_FOREACH(self->grays, v, CollectorMarker_checkObjectPointer(v); );
97 COLLECTMARKER_FOREACH(self->whites, v, CollectorMarker_checkObjectPointer(v); );
98 }
99
Collector_checkObjectsWith_(Collector * self,CollectorCheckFunc * func)100 void Collector_checkObjectsWith_(Collector *self, CollectorCheckFunc *func)
101 {
102 COLLECTMARKER_FOREACH(self->blacks, v, func(v); );
103 COLLECTMARKER_FOREACH(self->grays, v, func(v); );
104 COLLECTMARKER_FOREACH(self->whites, v, func(v); );
105 }
106
Collector_free(Collector * self)107 void Collector_free(Collector *self)
108 {
109 List_free(self->retainedValues);
110 CollectorMarker_free(self->whites);
111 CollectorMarker_free(self->grays);
112 CollectorMarker_free(self->blacks);
113 CollectorMarker_free(self->freed);
114 io_free(self);
115 }
116
Collector_setMarkBeforeSweepValue_(Collector * self,void * v)117 void Collector_setMarkBeforeSweepValue_(Collector *self, void *v)
118 {
119 self->markBeforeSweepValue = v;
120 }
121
122 // callbacks
123
Collector_setFreeFunc_(Collector * self,CollectorFreeFunc * func)124 void Collector_setFreeFunc_(Collector *self, CollectorFreeFunc *func)
125 {
126 self->freeFunc = func;
127 }
128
Collector_setWillFreeFunc_(Collector * self,CollectorWillFreeFunc * func)129 void Collector_setWillFreeFunc_(Collector *self, CollectorWillFreeFunc *func)
130 {
131 self->willFreeFunc = func;
132 }
133
Collector_setMarkFunc_(Collector * self,CollectorMarkFunc * func)134 void Collector_setMarkFunc_(Collector *self, CollectorMarkFunc *func)
135 {
136 self->markFunc = func;
137 }
138
139 // marks per alloc
140
Collector_setMarksPerAlloc_(Collector * self,float n)141 void Collector_setMarksPerAlloc_(Collector *self, float n)
142 {
143 self->marksPerAlloc = n;
144 }
145
Collector_marksPerAlloc(Collector * self)146 float Collector_marksPerAlloc(Collector *self)
147 {
148 return self->marksPerAlloc;
149 }
150
151 // allocated step
152
Collector_setAllocatedStep_(Collector * self,float n)153 void Collector_setAllocatedStep_(Collector *self, float n)
154 {
155 self->allocatedStep = n;
156 }
157
Collector_allocatedStep(Collector * self)158 float Collector_allocatedStep(Collector *self)
159 {
160 return self->allocatedStep;
161 }
162
Collector_setDebug_(Collector * self,int b)163 void Collector_setDebug_(Collector *self, int b)
164 {
165 self->debugOn = b ? 1 : 0;
166 }
167
Collector_setSafeModeOn_(Collector * self,int b)168 void Collector_setSafeModeOn_(Collector *self, int b)
169 {
170 self->safeMode = b ? 1 : 0;
171 }
172
173
174 // retain/release --------------------------------------------
175
Collector_retain_(Collector * self,void * v)176 void *Collector_retain_(Collector *self, void *v)
177 {
178 List_append_(self->retainedValues, v);
179 CollectorMarker_removeIfNeededAndInsertAfter_(v, self->grays);
180 return v;
181 }
182
Collector_stopRetaining_(Collector * self,void * v)183 void Collector_stopRetaining_(Collector *self, void *v)
184 {
185 List_removeLast_(self->retainedValues, v);
186 }
187
Collector_removeAllRetainedValues(Collector * self)188 void Collector_removeAllRetainedValues(Collector *self)
189 {
190 List_removeAll(self->retainedValues);
191 }
192
193 // pausing -------------------------------------------------------------------
194
Collector_isPaused(Collector * self)195 int Collector_isPaused(Collector *self)
196 {
197 return (self->pauseCount != 0);
198 }
199
Collector_pushPause(Collector * self)200 void Collector_pushPause(Collector *self)
201 {
202 self->pauseCount ++;
203 }
204
Collector_popPause(Collector * self)205 void Collector_popPause(Collector *self)
206 {
207 assert(self->pauseCount > 0);
208
209 self->pauseCount --;
210
211 //printf("collect newMarkerCount %i\n", self->newMarkerCount);
212 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
213 if (self->pauseCount == 0 && self->newMarkerCount > self->allocsPerSweep)
214 {
215 //printf("collect newMarkerCount %i\n", self->newMarkerCount);
216 if(self->debugOn)
217 {
218 printf("\n newMarkerCount %i\n", (int)self->newMarkerCount);
219 }
220
221 self->newMarkerCount = 0;
222 Collector_collect(self);
223 }
224 #else
225 if (self->pauseCount == 0 && self->queuedMarks > 1.0)
226 {
227 Collector_markPhase(self);
228 }
229 #endif
230 }
231
232 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
233
Collector_setAllocsPerSweep_(Collector * self,int n)234 void Collector_setAllocsPerSweep_(Collector *self, int n)
235 {
236 self->allocsPerSweep = n;
237 }
238
Collector_allocsPerSweep(Collector * self)239 float Collector_allocsPerSweep(Collector *self)
240 {
241 return self->allocsPerSweep;
242 }
243
244 #endif
245
246 // adding ------------------------------------------------
247
Collector_newMarker(Collector * self)248 CollectorMarker *Collector_newMarker(Collector *self)
249 {
250 CollectorMarker *m;
251 BEGIN_TIMER
252 m = self->freed->next;
253
254 if (m->color != self->freed->color)
255 {
256 m = CollectorMarker_new();
257 //printf("new marker\n");
258 }
259 else
260 {
261 //printf("using recycled marker\n");
262 }
263
264 self->allocated ++;
265
266 Collector_addValue_(self, m);
267 END_TIMER
268 return m;
269 }
270
Collector_addValue_(Collector * self,void * v)271 void Collector_addValue_(Collector *self, void *v)
272 {
273 CollectorMarker_removeIfNeededAndInsertAfter_(v, self->whites);
274
275 self->queuedMarks += self->marksPerAlloc;
276 #ifdef COLLECTOR_USE_NONINCREMENTAL_MARK_SWEEP
277 self->newMarkerCount ++;
278 #endif
279 // pauseCount is never zero here...
280 /*
281 if (self->pauseCount == 0)
282 {
283 if(self->allocated > self->allocatedSweepLevel)
284 {
285 Collector_sweep(self);
286 }
287 else if (self->queuedMarks > 1.0)
288 {
289 Collector_markPhase(self);
290 }
291 }
292 */
293 }
294
295 // collection ------------------------------------------------
296
Collector_markGrays(Collector * self)297 void Collector_markGrays(Collector *self)
298 {
299 CollectorMarkFunc *markFunc = self->markFunc;
300
301 COLLECTMARKER_FOREACH(self->grays, v,
302 //(*markFunc)(v); Collector_makeBlack_(self, v);
303 if ((*markFunc)(v)) Collector_makeBlack_(self, v);
304 //count ++;
305 );
306 self->queuedMarks = 0;
307 }
308
Collector_markGraysMax_(Collector * self,size_t max)309 void Collector_markGraysMax_(Collector *self, size_t max)
310 {
311 CollectorMarkFunc *markFunc = self->markFunc;
312
313 if (!max) return;
314
315 COLLECTMARKER_FOREACH(self->grays, v,
316 //(*markFunc)(v); Collector_makeBlack_(self, v);
317 if ((*markFunc)(v)) Collector_makeBlack_(self, v);
318 max --;
319 if(0 == max) break;
320 );
321
322 self->queuedMarks = 0;
323 }
324
Collector_sendWillFreeCallbacks(Collector * self)325 void Collector_sendWillFreeCallbacks(Collector *self)
326 {
327 CollectorWillFreeFunc *willFreeFunc = self->willFreeFunc;
328
329 if (willFreeFunc)
330 {
331 Collector_pushPause(self); // since the callback may create new objects
332 COLLECTMARKER_FOREACH(self->whites, v, (*willFreeFunc)(v));
333 Collector_popPause(self);
334 }
335 }
336
Collector_freeWhites(Collector * self)337 size_t Collector_freeWhites(Collector *self)
338 {
339 size_t count = 0;
340 CollectorFreeFunc *freeFunc = self->freeFunc;
341
342 COLLECTMARKER_FOREACH(self->whites, v,
343 (*freeFunc)(v);
344 //v->object = 0x0;
345 Collector_makeFree_(self, v);
346 count ++;
347 );
348
349 self->allocated -= count;
350
351 return count;
352 }
353
354 // ---------------------
355
Collector_initPhase(Collector * self)356 void Collector_initPhase(Collector *self)
357 {
358 LIST_FOREACH(self->retainedValues, i, v, Collector_makeGray_(self, v));
359 }
360
Collector_markForTimePeriod_(Collector * self,double seconds)361 void Collector_markForTimePeriod_(Collector *self, double seconds)
362 {
363 clock_t until = clock() + seconds * CLOCKS_PER_SEC;
364
365 for (;;)
366 {
367 if (until < clock()) return;
368
369 if (CollectorMarker_colorSetIsEmpty(self->grays))
370 {
371 Collector_sweep(self);
372 return;
373 }
374
375 Collector_markGrays(self);
376 }
377 }
378
Collector_markPhase(Collector * self)379 void Collector_markPhase(Collector *self)
380 {
381 if(self->allocated > self->allocatedSweepLevel)
382 {
383 Collector_sweep(self);
384 }
385 else
386 {
387 Collector_markGraysMax_(self, self->queuedMarks);
388 }
389
390 if (CollectorMarker_isEmpty(self->grays))
391 {
392 Collector_freeWhites(self);
393 //Collector_sweepPhase(self);
394 }
395 }
396
Collector_sweep(Collector * self)397 size_t Collector_sweep(Collector *self)
398 {
399 size_t freedCount = Collector_sweepPhase(self);
400
401 /*
402 if (self->debugOn)
403 {
404 size_t freedCount2 = Collector_sweepPhase(self);
405 return freedCount + freedCount2;
406 }
407 */
408
409 return freedCount;
410 }
411
Collector_sweepPhase(Collector * self)412 size_t Collector_sweepPhase(Collector *self)
413 {
414 size_t freedCount = 0;
415
416 self->newMarkerCount = 0;
417
418 if (self->debugOn)
419 {
420 printf("Collector_sweepPhase()\n");
421 //printf(" newMarkerCount %i\n", (int)self->newMarkerCount);
422 printf(" allocsPerSweep %i\n", (int)self->allocsPerSweep);
423 printf(" allocated %i\n", (int)self->allocated);
424 printf(" allocatedSweepLevel %i\n", (int)self->allocatedSweepLevel);
425 }
426
427 if (self->markBeforeSweepValue)
428 {
429 Collector_makeGray_(self, self->markBeforeSweepValue);
430 }
431
432 while (!CollectorMarker_isEmpty(self->grays))
433 {
434 do
435 {
436 Collector_markGrays(self);
437 } while (!CollectorMarker_isEmpty(self->grays));
438
439 Collector_sendWillFreeCallbacks(self);
440 }
441
442 freedCount = Collector_freeWhites(self);
443 self->sweepCount ++;
444 //printf("whites freed %i\n", (int)freedCount);
445
446 {
447 CollectorMarker *b = self->blacks;
448 self->blacks = self->whites;
449 self->whites = b;
450 }
451
452 Collector_initPhase(self);
453
454 self->allocatedSweepLevel = self->allocated * self->allocatedStep;
455 //printf("allocatedSweepLevel = %i\n", self->allocatedSweepLevel);
456
457 return freedCount;
458 }
459
Collector_collect(Collector * self)460 size_t Collector_collect(Collector *self)
461 {
462 size_t result;
463
464 BEGIN_TIMER
465 if (self->pauseCount)
466 {
467 printf("Collector warning: attempt to force collection while pause count = %i\n", self->pauseCount);
468 result = 0;
469 }
470 else
471 {
472 // collect twice to ensure that any now unreachable blacks get collected
473 result = Collector_sweepPhase(self) + Collector_sweepPhase(self);
474 }
475 END_TIMER
476 return result;
477 }
478
Collector_freeAllValues(Collector * self)479 size_t Collector_freeAllValues(Collector *self)
480 {
481 size_t count = 0;
482 CollectorFreeFunc *freeFunc = self->freeFunc;
483 COLLECTOR_FOREACH(self, v, (*freeFunc)(v); CollectorMarker_free(v); count ++;);
484 self->allocated -= count;
485 COLLECTMARKER_FOREACH(self->freed, v, CollectorMarker_free(v); count ++;);
486 return count;
487 }
488
489 // helpers ----------------------------------------------------------------------------
490
Collector_show(Collector * self)491 void Collector_show(Collector *self)
492 {
493 printf("black: %i\n", (int)CollectorMarker_count(self->blacks));
494 printf("gray: %i\n", (int)CollectorMarker_count(self->grays));
495 printf("white: %i\n", (int)CollectorMarker_count(self->whites));
496 }
497
Collector_colorNameFor_(Collector * self,void * v)498 char *Collector_colorNameFor_(Collector *self, void *v)
499 {
500 if (self->whites->color == MARKER(v)->color) return "white";
501 if (self->grays->color == MARKER(v)->color) return "gray";
502 if (self->blacks->color == MARKER(v)->color) return "black";
503 return "off-white";
504 }
505
Collector_timeUsed(Collector * self)506 double Collector_timeUsed(Collector *self)
507 {
508 return (double)self->clocksUsed / (double)CLOCKS_PER_SEC;
509 }
510
511