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

Delta Between Two Patch Sets: src/pkg/runtime/mprof.goc

Issue 6443115: code review 6443115: pprof: add contention profiling (Closed)
Left Patch Set: Created 11 years, 7 months ago
Right Patch Set: diff -r 2aef5548a9cf https://go.googlecode.com/hg/ Created 11 years, 5 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:
Right: Side by side diff | Download
« no previous file with change/comment | « src/pkg/runtime/debug.go ('k') | src/pkg/runtime/pprof/pprof.go » ('j') | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
(no file at all)
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 // Malloc profiling. 5 // Malloc profiling.
6 // Patterned after tcmalloc's algorithms; shorter code. 6 // Patterned after tcmalloc's algorithms; shorter code.
7 7
8 package runtime 8 package runtime
9 #include "runtime.h" 9 #include "runtime.h"
10 #include "arch_GOARCH.h" 10 #include "arch_GOARCH.h"
11 #include "malloc.h" 11 #include "malloc.h"
12 #include "defs_GOOS_GOARCH.h" 12 #include "defs_GOOS_GOARCH.h"
13 #include "type.h" 13 #include "type.h"
14 14
15 // NOTE(rsc): Everything here could use cas if contention became an issue. 15 // NOTE(rsc): Everything here could use cas if contention became an issue.
16 static Lock proflock; 16 static Lock proflock;
17 17
18 // Per-call-stack allocation information. 18 enum { MProf, BProf }; // profile types
19
20 // Per-call-stack profiling information.
19 // Lookup by hashing call stack into a linked-list hash table. 21 // Lookup by hashing call stack into a linked-list hash table.
20 typedef struct Bucket Bucket; 22 typedef struct Bucket Bucket;
21 struct Bucket 23 struct Bucket
22 { 24 {
23 Bucket *next; // next in hash list 25 Bucket *next; // next in hash list
24 » Bucket» *allnext;» // next in list of all buckets 26 » Bucket» *allnext;» // next in list of all mbuckets/bbuckets
25 » uintptr»allocs; 27 » int32» typ;
26 » uintptr»frees; 28 » union
27 » uintptr»alloc_bytes; 29 » {
28 » uintptr»free_bytes; 30 » » struct // typ == MProf
29 » uintptr»recent_allocs; // since last gc 31 » » {
30 » uintptr»recent_frees; 32 » » » uintptr»allocs;
31 » uintptr»recent_alloc_bytes; 33 » » » uintptr»frees;
32 » uintptr»recent_free_bytes; 34 » » » uintptr»alloc_bytes;
35 » » » uintptr»free_bytes;
36 » » » uintptr»recent_allocs; // since last gc
37 » » » uintptr»recent_frees;
38 » » » uintptr»recent_alloc_bytes;
39 » » » uintptr»recent_free_bytes;
40 » » };
41 » » struct // typ == BProf
42 » » {
43 » » » int64» count;
44 » » » int64» cycles;
45 » » };
46 » };
33 uintptr hash; 47 uintptr hash;
34 uintptr nstk; 48 uintptr nstk;
35 uintptr stk[1]; 49 uintptr stk[1];
36 }; 50 };
37 enum { 51 enum {
38 BuckHashSize = 179999, 52 BuckHashSize = 179999,
39 }; 53 };
40 static Bucket **buckhash; 54 static Bucket **buckhash;
41 static Bucket *buckets; 55 static Bucket *mbuckets; // memory profile buckets
56 static Bucket *bbuckets; // blocking profile buckets
42 static uintptr bucketmem; 57 static uintptr bucketmem;
43 58
44 // Return the bucket for stk[0:nstk], allocating new bucket if needed. 59 // Return the bucket for stk[0:nstk], allocating new bucket if needed.
45 static Bucket* 60 static Bucket*
46 stkbucket(uintptr *stk, int32 nstk, bool alloc) 61 stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
47 { 62 {
48 int32 i; 63 int32 i;
49 uintptr h; 64 uintptr h;
50 Bucket *b; 65 Bucket *b;
51 66
52 if(buckhash == nil) { 67 if(buckhash == nil) {
53 buckhash = runtime·SysAlloc(BuckHashSize*sizeof buckhash[0]); 68 buckhash = runtime·SysAlloc(BuckHashSize*sizeof buckhash[0]);
54 mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0]; 69 mstats.buckhash_sys += BuckHashSize*sizeof buckhash[0];
55 } 70 }
56 71
57 // Hash stack. 72 // Hash stack.
58 h = 0; 73 h = 0;
59 for(i=0; i<nstk; i++) { 74 for(i=0; i<nstk; i++) {
60 h += stk[i]; 75 h += stk[i];
61 h += h<<10; 76 h += h<<10;
62 h ^= h>>6; 77 h ^= h>>6;
63 } 78 }
64 h += h<<3; 79 h += h<<3;
65 h ^= h>>11; 80 h ^= h>>11;
66 81
67 i = h%BuckHashSize; 82 i = h%BuckHashSize;
68 for(b = buckhash[i]; b; b=b->next) 83 for(b = buckhash[i]; b; b=b->next)
69 » » if(b->hash == h && b->nstk == nstk && 84 » » if(b->typ == typ && b->hash == h && b->nstk == nstk &&
70 runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) = = 0) 85 runtime·mcmp((byte*)b->stk, (byte*)stk, nstk*sizeof stk[0]) = = 0)
71 return b; 86 return b;
72 87
73 if(!alloc) 88 if(!alloc)
74 return nil; 89 return nil;
75 90
76 b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1); 91 b = runtime·mallocgc(sizeof *b + nstk*sizeof stk[0], FlagNoProfiling, 0, 1);
77 bucketmem += sizeof *b + nstk*sizeof stk[0]; 92 bucketmem += sizeof *b + nstk*sizeof stk[0];
78 runtime·memmove(b->stk, stk, nstk*sizeof stk[0]); 93 runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
94 b->typ = typ;
79 b->hash = h; 95 b->hash = h;
80 b->nstk = nstk; 96 b->nstk = nstk;
81 b->next = buckhash[i]; 97 b->next = buckhash[i];
82 buckhash[i] = b; 98 buckhash[i] = b;
83 » b->allnext = buckets; 99 » if(typ == MProf) {
84 » buckets = b; 100 » » b->allnext = mbuckets;
101 » » mbuckets = b;
102 » } else {
103 » » b->allnext = bbuckets;
104 » » bbuckets = b;
105 » }
85 return b; 106 return b;
86 } 107 }
87 108
88 // Record that a gc just happened: all the 'recent' statistics are now real. 109 // Record that a gc just happened: all the 'recent' statistics are now real.
89 void 110 void
90 runtime·MProf_GC(void) 111 runtime·MProf_GC(void)
91 { 112 {
92 Bucket *b; 113 Bucket *b;
93 ········ 114 ········
94 runtime·lock(&proflock); 115 runtime·lock(&proflock);
95 » for(b=buckets; b; b=b->allnext) { 116 » for(b=mbuckets; b; b=b->allnext) {
96 b->allocs += b->recent_allocs; 117 b->allocs += b->recent_allocs;
97 b->frees += b->recent_frees; 118 b->frees += b->recent_frees;
98 b->alloc_bytes += b->recent_alloc_bytes; 119 b->alloc_bytes += b->recent_alloc_bytes;
99 b->free_bytes += b->recent_free_bytes; 120 b->free_bytes += b->recent_free_bytes;
100 b->recent_allocs = 0; 121 b->recent_allocs = 0;
101 b->recent_frees = 0; 122 b->recent_frees = 0;
102 b->recent_alloc_bytes = 0; 123 b->recent_alloc_bytes = 0;
103 b->recent_free_bytes = 0; 124 b->recent_free_bytes = 0;
104 } 125 }
105 runtime·unlock(&proflock); 126 runtime·unlock(&proflock);
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after
221 int32 nstk; 242 int32 nstk;
222 uintptr stk[32]; 243 uintptr stk[32];
223 Bucket *b; 244 Bucket *b;
224 245
225 if(m->nomemprof > 0) 246 if(m->nomemprof > 0)
226 return; 247 return;
227 248
228 m->nomemprof++; 249 m->nomemprof++;
229 nstk = runtime·callers(1, stk, 32); 250 nstk = runtime·callers(1, stk, 32);
230 runtime·lock(&proflock); 251 runtime·lock(&proflock);
231 » b = stkbucket(stk, nstk, true); 252 » b = stkbucket(MProf, stk, nstk, true);
232 b->recent_allocs++; 253 b->recent_allocs++;
233 b->recent_alloc_bytes += size; 254 b->recent_alloc_bytes += size;
234 setaddrbucket((uintptr)p, b); 255 setaddrbucket((uintptr)p, b);
235 runtime·unlock(&proflock); 256 runtime·unlock(&proflock);
236 m->nomemprof--; 257 m->nomemprof--;
237 } 258 }
238 259
239 // Called when freeing a profiled block. 260 // Called when freeing a profiled block.
240 void 261 void
241 runtime·MProf_Free(void *p, uintptr size) 262 runtime·MProf_Free(void *p, uintptr size)
242 { 263 {
243 Bucket *b; 264 Bucket *b;
244 265
245 if(m->nomemprof > 0) 266 if(m->nomemprof > 0)
246 return; 267 return;
247 268
248 m->nomemprof++; 269 m->nomemprof++;
249 runtime·lock(&proflock); 270 runtime·lock(&proflock);
250 b = getaddrbucket((uintptr)p); 271 b = getaddrbucket((uintptr)p);
251 if(b != nil) { 272 if(b != nil) {
252 b->recent_frees++; 273 b->recent_frees++;
253 b->recent_free_bytes += size; 274 b->recent_free_bytes += size;
254 } 275 }
255 runtime·unlock(&proflock); 276 runtime·unlock(&proflock);
256 m->nomemprof--; 277 m->nomemprof--;
257 } 278 }
258 279
280 int64 runtime·blockprofilerate; // in CPU ticks
281
282 void
283 runtime·SetBlockProfileRate(intgo rate)
284 {
285 runtime·atomicstore64((uint64*)&runtime·blockprofilerate, rate * runtime ·tickspersecond() / (1000*1000*1000));
286 }
287
288 void
289 runtime·blockevent(int64 cycles, int32 skip)
290 {
291 int32 nstk;
292 int64 rate;
293 uintptr stk[32];
294 Bucket *b;
295
296 if(cycles <= 0)
297 return;
298 rate = runtime·atomicload64((uint64*)&runtime·blockprofilerate);
299 if(rate <= 0 || (rate > cycles && runtime·fastrand1()%rate > cycles))
300 return;
301
302 nstk = runtime·callers(skip, stk, 32);
303 runtime·lock(&proflock);
304 b = stkbucket(BProf, stk, nstk, true);
305 b->count++;
306 b->cycles += cycles;
307 runtime·unlock(&proflock);
308 }
259 309
260 // Go interface to profile data. (Declared in extern.go) 310 // Go interface to profile data. (Declared in extern.go)
261 // Assumes Go sizeof(int) == sizeof(int32) 311 // Assumes Go sizeof(int) == sizeof(int32)
262 312
263 // Must match MemProfileRecord in debug.go. 313 // Must match MemProfileRecord in debug.go.
264 typedef struct Record Record; 314 typedef struct Record Record;
265 struct Record { 315 struct Record {
266 int64 alloc_bytes, free_bytes; 316 int64 alloc_bytes, free_bytes;
267 int64 alloc_objects, free_objects; 317 int64 alloc_objects, free_objects;
268 uintptr stk[32]; 318 uintptr stk[32];
(...skipping 14 matching lines...) Expand all
283 for(; i<nelem(r->stk); i++) 333 for(; i<nelem(r->stk); i++)
284 r->stk[i] = 0; 334 r->stk[i] = 0;
285 } 335 }
286 336
287 func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) { 337 func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
288 Bucket *b; 338 Bucket *b;
289 Record *r; 339 Record *r;
290 340
291 runtime·lock(&proflock); 341 runtime·lock(&proflock);
292 n = 0; 342 n = 0;
293 » for(b=buckets; b; b=b->allnext) 343 » for(b=mbuckets; b; b=b->allnext)
294 if(include_inuse_zero || b->alloc_bytes != b->free_bytes) 344 if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
295 n++; 345 n++;
296 ok = false; 346 ok = false;
297 if(n <= p.len) { 347 if(n <= p.len) {
298 ok = true; 348 ok = true;
299 r = (Record*)p.array; 349 r = (Record*)p.array;
300 » » for(b=buckets; b; b=b->allnext) 350 » » for(b=mbuckets; b; b=b->allnext)
301 if(include_inuse_zero || b->alloc_bytes != b->free_bytes ) 351 if(include_inuse_zero || b->alloc_bytes != b->free_bytes )
302 record(r++, b); 352 record(r++, b);
353 }
354 runtime·unlock(&proflock);
355 }
356
357 // Must match BlockProfileRecord in debug.go.
358 typedef struct BRecord BRecord;
359 struct BRecord {
360 int64 count;
361 int64 cycles;
362 uintptr stk[32];
363 };
364
365 func BlockProfile(p Slice) (n int, ok bool) {
366 Bucket *b;
367 BRecord *r;
368 int32 i;
369
370 runtime·lock(&proflock);
371 n = 0;
372 for(b=bbuckets; b; b=b->allnext)
373 n++;
374 ok = false;
375 if(n <= p.len) {
376 ok = true;
377 r = (BRecord*)p.array;
378 for(b=bbuckets; b; b=b->allnext, r++) {
379 r->count = b->count;
380 r->cycles = b->cycles;
381 for(i=0; i<b->nstk && i<nelem(r->stk); i++)
382 r->stk[i] = b->stk[i];
383 for(; i<nelem(r->stk); i++)
384 r->stk[i] = 0;··················
385 }
303 } 386 }
304 runtime·unlock(&proflock); 387 runtime·unlock(&proflock);
305 } 388 }
306 389
307 // Must match StackRecord in debug.go. 390 // Must match StackRecord in debug.go.
308 typedef struct TRecord TRecord; 391 typedef struct TRecord TRecord;
309 struct TRecord { 392 struct TRecord {
310 uintptr stk[32]; 393 uintptr stk[32];
311 }; 394 };
312 395
(...skipping 85 matching lines...) Expand 10 before | Expand all | Expand 10 after
398 saveg(gp->sched.pc, (byte*)gp->sched.sp, gp, r++ ); 481 saveg(gp->sched.pc, (byte*)gp->sched.sp, gp, r++ );
399 } 482 }
400 } 483 }
401 ········ 484 ········
402 m->gcing = 0; 485 m->gcing = 0;
403 runtime·semrelease(&runtime·worldsema); 486 runtime·semrelease(&runtime·worldsema);
404 runtime·starttheworld(); 487 runtime·starttheworld();
405 } 488 }
406 } 489 }
407 490
LEFTRIGHT

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