Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(5)

Delta Between Two Patch Sets: src/pkg/runtime/mheap.c

Issue 5279048: code review 5279048: runtime: faster and more scalable GC (Closed)
Left Patch Set: diff -r da9e7548e6ef https://go.googlecode.com/hg/ Created 13 years, 4 months ago
Right Patch Set: diff -r f44057cc01b2 https://go.googlecode.com/hg/ Created 12 years, 11 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/runtime/mgc0.c ('k') | src/pkg/runtime/mprof.goc » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 // Copyright 2009 The Go Authors. All rights reserved. 1 // Copyright 2009 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style 2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file. 3 // license that can be found in the LICENSE file.
4 4
5 // Page heap. 5 // Page heap.
6 // 6 //
7 // See malloc.h for overview. 7 // See malloc.h for overview.
8 // 8 //
9 // When a MSpan is in the heap free list, state == MSpanFree 9 // When a MSpan is in the heap free list, state == MSpanFree
10 // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span. 10 // and heapmap(s->start) == span, heapmap(s->start+s->npages-1) == span.
11 // 11 //
12 // When a MSpan is allocated, state == MSpanInUse 12 // When a MSpan is allocated, state == MSpanInUse
13 // and heapmap(i) == span for all s->start <= i < s->start+s->npages. 13 // and heapmap(i) == span for all s->start <= i < s->start+s->npages.
14 14
15 #include "runtime.h" 15 #include "runtime.h"
16 #include "arch.h" 16 #include "arch_GOARCH.h"
17 #include "malloc.h" 17 #include "malloc.h"
18 18
19 static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32); 19 static MSpan *MHeap_AllocLocked(MHeap*, uintptr, int32);
20 static bool MHeap_Grow(MHeap*, uintptr); 20 static bool MHeap_Grow(MHeap*, uintptr);
21 static void MHeap_FreeLocked(MHeap*, MSpan*); 21 static void MHeap_FreeLocked(MHeap*, MSpan*);
22 static MSpan *MHeap_AllocLarge(MHeap*, uintptr); 22 static MSpan *MHeap_AllocLarge(MHeap*, uintptr);
23 static MSpan *BestFit(MSpan*, uintptr, MSpan*); 23 static MSpan *BestFit(MSpan*, uintptr, MSpan*);
24 24
25 static void 25 static void
26 RecordSpan(void *vh, byte *p) 26 RecordSpan(void *vh, byte *p)
27 { 27 {
28 MHeap *h; 28 MHeap *h;
29 MSpan *s; 29 MSpan *s;
30 30 » MSpan **all;
31 » uintptr cap;
32 »·······
31 h = vh; 33 h = vh;
32 s = (MSpan*)p; 34 s = (MSpan*)p;
33 » //s->allnext = h->allspans; 35 » if(h->nspan >= h->nspancap) {
34 » //h->allspans = s; 36 » » cap = 64*1024/sizeof(MSpan*);
35 » if(h->nspan == nelem(h->allspans)) 37 » » if(cap < h->nspancap*3/2)
36 » » runtime·throw("span overflow"); 38 » » » cap = h->nspancap*3/2;
37 » h->allspans[h->nspan] = s; 39 » » all = (MSpan**)runtime·SysAlloc(cap*sizeof(MSpan*));
38 » h->nspan++; 40 » » if(h->allspans) {
41 » » » runtime·memmove(all, h->allspans, h->nspancap*sizeof(MSp an*));
42 » » » runtime·SysFree(h->allspans, h->nspancap*sizeof(MSpan*)) ;
43 » » }
44 » » h->allspans = all;
45 » » h->nspancap = cap;
46 » }
47 » h->allspans[h->nspan++] = s;
39 } 48 }
40 49
41 // Initialize the heap; fetch memory using alloc. 50 // Initialize the heap; fetch memory using alloc.
42 void 51 void
43 runtime·MHeap_Init(MHeap *h, void *(*alloc)(uintptr)) 52 runtime·MHeap_Init(MHeap *h, void *(*alloc)(uintptr))
44 { 53 {
45 uint32 i; 54 uint32 i;
46 55
47 runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h ); 56 runtime·FixAlloc_Init(&h->spanalloc, sizeof(MSpan), alloc, RecordSpan, h );
48 runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil); 57 runtime·FixAlloc_Init(&h->cachealloc, sizeof(MCache), alloc, nil, nil);
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
100 109
101 HaveSpan: 110 HaveSpan:
102 // Mark span in use. 111 // Mark span in use.
103 if(s->state != MSpanFree) 112 if(s->state != MSpanFree)
104 runtime·throw("MHeap_AllocLocked - MSpan not free"); 113 runtime·throw("MHeap_AllocLocked - MSpan not free");
105 if(s->npages < npage) 114 if(s->npages < npage)
106 runtime·throw("MHeap_AllocLocked - bad npages"); 115 runtime·throw("MHeap_AllocLocked - bad npages");
107 runtime·MSpanList_Remove(s); 116 runtime·MSpanList_Remove(s);
108 s->state = MSpanInUse; 117 s->state = MSpanInUse;
109 mstats.heap_idle -= s->npages<<PageShift; 118 mstats.heap_idle -= s->npages<<PageShift;
119 mstats.heap_released -= s->npreleased<<PageShift;
120 s->npreleased = 0;
110 121
111 if(s->npages > npage) { 122 if(s->npages > npage) {
112 // Trim extra and put it back in the heap. 123 // Trim extra and put it back in the heap.
113 t = runtime·FixAlloc_Alloc(&h->spanalloc); 124 t = runtime·FixAlloc_Alloc(&h->spanalloc);
114 mstats.mspan_inuse = h->spanalloc.inuse; 125 mstats.mspan_inuse = h->spanalloc.inuse;
115 mstats.mspan_sys = h->spanalloc.sys; 126 mstats.mspan_sys = h->spanalloc.sys;
116 runtime·MSpan_Init(t, s->start + npage, s->npages - npage); 127 runtime·MSpan_Init(t, s->start + npage, s->npages - npage);
117 s->npages = npage; 128 s->npages = npage;
118 p = t->start; 129 p = t->start;
119 if(sizeof(void*) == 8) 130 if(sizeof(void*) == 8)
(...skipping 157 matching lines...) Expand 10 before | Expand all | Expand 10 after
277 uintptr *sp, *tp; 288 uintptr *sp, *tp;
278 MSpan *t; 289 MSpan *t;
279 PageID p; 290 PageID p;
280 291
281 if(s->state != MSpanInUse || s->ref != 0) { 292 if(s->state != MSpanInUse || s->ref != 0) {
282 runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref % d\n", s, s->start<<PageShift, s->state, s->ref); 293 runtime·printf("MHeap_FreeLocked - span %p ptr %p state %d ref % d\n", s, s->start<<PageShift, s->state, s->ref);
283 runtime·throw("MHeap_FreeLocked - invalid free"); 294 runtime·throw("MHeap_FreeLocked - invalid free");
284 } 295 }
285 mstats.heap_idle += s->npages<<PageShift; 296 mstats.heap_idle += s->npages<<PageShift;
286 s->state = MSpanFree; 297 s->state = MSpanFree;
298 s->unusedsince = 0;
299 s->npreleased = 0;
287 runtime·MSpanList_Remove(s); 300 runtime·MSpanList_Remove(s);
288 sp = (uintptr*)(s->start<<PageShift); 301 sp = (uintptr*)(s->start<<PageShift);
289 302
290 // Coalesce with earlier, later spans. 303 // Coalesce with earlier, later spans.
291 p = s->start; 304 p = s->start;
292 if(sizeof(void*) == 8) 305 if(sizeof(void*) == 8)
293 p -= (uintptr)h->arena_start >> PageShift; 306 p -= (uintptr)h->arena_start >> PageShift;
294 if(p > 0 && (t = h->map[p-1]) != nil && t->state != MSpanInUse) { 307 if(p > 0 && (t = h->map[p-1]) != nil && t->state != MSpanInUse) {
295 tp = (uintptr*)(t->start<<PageShift); 308 tp = (uintptr*)(t->start<<PageShift);
296 *tp |= *sp; // propagate "needs zeroing" mark 309 *tp |= *sp; // propagate "needs zeroing" mark
297 s->start = t->start; 310 s->start = t->start;
298 s->npages += t->npages; 311 s->npages += t->npages;
312 s->npreleased = t->npreleased; // absorb released pages
299 p -= t->npages; 313 p -= t->npages;
300 h->map[p] = s; 314 h->map[p] = s;
301 runtime·MSpanList_Remove(t); 315 runtime·MSpanList_Remove(t);
302 t->state = MSpanDead; 316 t->state = MSpanDead;
303 runtime·FixAlloc_Free(&h->spanalloc, t); 317 runtime·FixAlloc_Free(&h->spanalloc, t);
304 mstats.mspan_inuse = h->spanalloc.inuse; 318 mstats.mspan_inuse = h->spanalloc.inuse;
305 mstats.mspan_sys = h->spanalloc.sys; 319 mstats.mspan_sys = h->spanalloc.sys;
306 } 320 }
307 if(p+s->npages < nelem(h->map) && (t = h->map[p+s->npages]) != nil && t- >state != MSpanInUse) { 321 if(p+s->npages < nelem(h->map) && (t = h->map[p+s->npages]) != nil && t- >state != MSpanInUse) {
308 tp = (uintptr*)(t->start<<PageShift); 322 tp = (uintptr*)(t->start<<PageShift);
309 *sp |= *tp; // propagate "needs zeroing" mark 323 *sp |= *tp; // propagate "needs zeroing" mark
310 s->npages += t->npages; 324 s->npages += t->npages;
325 s->npreleased += t->npreleased;
311 h->map[p + s->npages - 1] = s; 326 h->map[p + s->npages - 1] = s;
312 runtime·MSpanList_Remove(t); 327 runtime·MSpanList_Remove(t);
313 t->state = MSpanDead; 328 t->state = MSpanDead;
314 runtime·FixAlloc_Free(&h->spanalloc, t); 329 runtime·FixAlloc_Free(&h->spanalloc, t);
315 mstats.mspan_inuse = h->spanalloc.inuse; 330 mstats.mspan_inuse = h->spanalloc.inuse;
316 mstats.mspan_sys = h->spanalloc.sys; 331 mstats.mspan_sys = h->spanalloc.sys;
317 } 332 }
318 333
319 // Insert s into appropriate list. 334 // Insert s into appropriate list.
320 if(s->npages < nelem(h->free)) 335 if(s->npages < nelem(h->free))
321 runtime·MSpanList_Insert(&h->free[s->npages], s); 336 runtime·MSpanList_Insert(&h->free[s->npages], s);
322 else 337 else
323 runtime·MSpanList_Insert(&h->large, s); 338 runtime·MSpanList_Insert(&h->large, s);
324 339 }
325 » // TODO(rsc): IncrementalScavenge() to return memory to OS. 340
341 // Release (part of) unused memory to OS.
342 // Goroutine created at startup.
343 // Loop forever.
344 void
345 runtime·MHeap_Scavenger(void)
346 {
347 » MHeap *h;
348 » MSpan *s, *list;
349 » uint64 tick, now, forcegc, limit;
350 » uint32 k, i;
351 » uintptr released, sumreleased;
352 » byte *env;
353 » bool trace;
354 » Note note;
355
356 » // If we go two minutes without a garbage collection, force one to run.
357 » forcegc = 2*60*1e9;
358 » // If a span goes unused for 5 minutes after a garbage collection,
359 » // we hand it back to the operating system.
360 » limit = 5*60*1e9;
361 » // Make wake-up period small enough for the sampling to be correct.
362 » if(forcegc < limit)
363 » » tick = forcegc/2;
364 » else
365 » » tick = limit/2;
366
367 » trace = false;
368 » env = runtime·getenv("GOGCTRACE");
369 » if(env != nil)
370 » » trace = runtime·atoi(env) > 0;
371
372 » h = &runtime·mheap;
373 » for(k=0;; k++) {
374 » » runtime·noteclear(&note);
375 » » runtime·entersyscall();
376 » » runtime·notetsleep(&note, tick);
377 » » runtime·exitsyscall();
378
379 » » runtime·lock(h);
380 » » now = runtime·nanotime();
381 » » if(now - mstats.last_gc > forcegc) {
382 » » » runtime·unlock(h);
383 » » » runtime·gc(1);
384 » » » runtime·lock(h);
385 » » » now = runtime·nanotime();
386 » » » if (trace)
387 » » » » runtime·printf("scvg%d: GC forced\n", k);
388 » » }
389 » » sumreleased = 0;
390 » » for(i=0; i < nelem(h->free)+1; i++) {
391 » » » if(i < nelem(h->free))
392 » » » » list = &h->free[i];
393 » » » else
394 » » » » list = &h->large;
395 » » » if(runtime·MSpanList_IsEmpty(list))
396 » » » » continue;
397 » » » for(s=list->next; s != list; s=s->next) {
398 » » » » if(s->unusedsince != 0 && (now - s->unusedsince) > limit) {
399 » » » » » released = (s->npages - s->npreleased) < < PageShift;
400 » » » » » mstats.heap_released += released;
401 » » » » » sumreleased += released;
402 » » » » » s->npreleased = s->npages;
403 » » » » » runtime·SysUnused((void*)(s->start << Pa geShift), s->npages << PageShift);
404 » » » » }
405 » » » }
406 » » }
407 » » runtime·unlock(h);
408
409 » » if(trace) {
410 » » » if(sumreleased > 0)
411 » » » » runtime·printf("scvg%d: %p MB released\n", k, su mreleased>>20);
412 » » » runtime·printf("scvg%d: inuse: %D, idle: %D, sys: %D, re leased: %D, consumed: %D (MB)\n",
413 » » » » k, mstats.heap_inuse>>20, mstats.heap_idle>>20, mstats.heap_sys>>20,
414 » » » » mstats.heap_released>>20, (mstats.heap_sys - mst ats.heap_released)>>20);
415 » » }
416 » }
326 } 417 }
327 418
328 // Initialize a new span with the given start and npages. 419 // Initialize a new span with the given start and npages.
329 void 420 void
330 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages) 421 runtime·MSpan_Init(MSpan *span, PageID start, uintptr npages)
331 { 422 {
332 span->next = nil; 423 span->next = nil;
333 span->prev = nil; 424 span->prev = nil;
334 span->start = start; 425 span->start = start;
335 span->npages = npages; 426 span->npages = npages;
336 span->freelist = nil; 427 span->freelist = nil;
337 span->ref = 0; 428 span->ref = 0;
338 span->sizeclass = 0; 429 span->sizeclass = 0;
339 span->state = 0; 430 span->state = 0;
431 span->unusedsince = 0;
432 span->npreleased = 0;
340 } 433 }
341 434
342 // Initialize an empty doubly-linked list. 435 // Initialize an empty doubly-linked list.
343 void 436 void
344 runtime·MSpanList_Init(MSpan *list) 437 runtime·MSpanList_Init(MSpan *list)
345 { 438 {
346 list->state = MSpanListHead; 439 list->state = MSpanListHead;
347 list->next = list; 440 list->next = list;
348 list->prev = list; 441 list->prev = list;
349 } 442 }
(...skipping 22 matching lines...) Expand all
372 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev); 465 runtime·printf("failed MSpanList_Insert %p %p %p\n", span, span- >next, span->prev);
373 runtime·throw("MSpanList_Insert"); 466 runtime·throw("MSpanList_Insert");
374 } 467 }
375 span->next = list->next; 468 span->next = list->next;
376 span->prev = list; 469 span->prev = list;
377 span->next->prev = span; 470 span->next->prev = span;
378 span->prev->next = span; 471 span->prev->next = span;
379 } 472 }
380 473
381 474
LEFTRIGHT

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld f62528b