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

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

Issue 6443115: code review 6443115: pprof: add contention profiling (Closed)
Left Patch Set: diff -r 248e11862ed5 https://go.googlecode.com/hg/ Created 11 years, 6 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:
Left: Side by side diff | Download
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
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 enum { MProf, CProf }; // profile types 18 enum { MProf, BProf }; // profile types
19 19
20 // Per-call-stack profiling information. 20 // Per-call-stack profiling information.
21 // Lookup by hashing call stack into a linked-list hash table. 21 // Lookup by hashing call stack into a linked-list hash table.
22 typedef struct Bucket Bucket; 22 typedef struct Bucket Bucket;
23 struct Bucket 23 struct Bucket
24 { 24 {
25 Bucket *next; // next in hash list 25 Bucket *next; // next in hash list
26 » Bucket» *allnext;» // next in list of all mbuckets/cbuckets 26 » Bucket» *allnext;» // next in list of all mbuckets/bbuckets
27 int32 typ; 27 int32 typ;
28 union 28 union
29 { 29 {
30 struct // typ == MProf 30 struct // typ == MProf
31 { 31 {
32 uintptr allocs; 32 uintptr allocs;
33 uintptr frees; 33 uintptr frees;
34 uintptr alloc_bytes; 34 uintptr alloc_bytes;
35 uintptr free_bytes; 35 uintptr free_bytes;
36 uintptr recent_allocs; // since last gc 36 uintptr recent_allocs; // since last gc
37 uintptr recent_frees; 37 uintptr recent_frees;
38 uintptr recent_alloc_bytes; 38 uintptr recent_alloc_bytes;
39 uintptr recent_free_bytes; 39 uintptr recent_free_bytes;
40 }; 40 };
41 » » struct // typ == CProf 41 » » struct // typ == BProf
42 { 42 {
43 int64 count; 43 int64 count;
44 int64 cycles; 44 int64 cycles;
45 }; 45 };
46 }; 46 };
47 uintptr hash; 47 uintptr hash;
48 uintptr nstk; 48 uintptr nstk;
49 uintptr stk[1]; 49 uintptr stk[1];
50 }; 50 };
51 enum { 51 enum {
52 BuckHashSize = 179999, 52 BuckHashSize = 179999,
53 }; 53 };
54 static Bucket **buckhash; 54 static Bucket **buckhash;
55 static Bucket *mbuckets; 55 static Bucket *mbuckets; // memory profile buckets
56 static Bucket *cbuckets; 56 static Bucket *bbuckets; // blocking profile buckets
57 static uintptr bucketmem; 57 static uintptr bucketmem;
58 58
59 // 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.
60 static Bucket* 60 static Bucket*
61 stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc) 61 stkbucket(int32 typ, uintptr *stk, int32 nstk, bool alloc)
62 { 62 {
63 int32 i; 63 int32 i;
64 uintptr h; 64 uintptr h;
65 Bucket *b; 65 Bucket *b;
66 66
(...skipping 26 matching lines...) Expand all
93 runtime·memmove(b->stk, stk, nstk*sizeof stk[0]); 93 runtime·memmove(b->stk, stk, nstk*sizeof stk[0]);
94 b->typ = typ; 94 b->typ = typ;
95 b->hash = h; 95 b->hash = h;
96 b->nstk = nstk; 96 b->nstk = nstk;
97 b->next = buckhash[i]; 97 b->next = buckhash[i];
98 buckhash[i] = b; 98 buckhash[i] = b;
99 if(typ == MProf) { 99 if(typ == MProf) {
100 b->allnext = mbuckets; 100 b->allnext = mbuckets;
101 mbuckets = b; 101 mbuckets = b;
102 } else { 102 } else {
103 » » b->allnext = cbuckets; 103 » » b->allnext = bbuckets;
104 » » cbuckets = b; 104 » » bbuckets = b;
105 } 105 }
106 return b; 106 return b;
107 } 107 }
108 108
109 // 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.
110 void 110 void
111 runtime·MProf_GC(void) 111 runtime·MProf_GC(void)
112 { 112 {
113 Bucket *b; 113 Bucket *b;
114 ········ 114 ········
(...skipping 155 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 runtime·lock(&proflock); 270 runtime·lock(&proflock);
271 b = getaddrbucket((uintptr)p); 271 b = getaddrbucket((uintptr)p);
272 if(b != nil) { 272 if(b != nil) {
273 b->recent_frees++; 273 b->recent_frees++;
274 b->recent_free_bytes += size; 274 b->recent_free_bytes += size;
275 } 275 }
276 runtime·unlock(&proflock); 276 runtime·unlock(&proflock);
277 m->nomemprof--; 277 m->nomemprof--;
278 } 278 }
279 279
280 int64 runtime·blockprofilerate; // in CPU ticks
281
280 void 282 void
281 runtime·contentionevent(int64 cycles, int32 skip) 283 runtime·SetBlockProfileRate(intgo rate)
282 { 284 {
283 » int32 nstk, rate; 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;
284 uintptr stk[32]; 293 uintptr stk[32];
285 Bucket *b; 294 Bucket *b;
286 295
287 » rate = runtime·ContentionProfileRate; 296 » if(cycles <= 0)
288 » if(rate <= 0 || cycles <= 0)
289 return; 297 return;
290 » if(rate > cycles && runtime·fastrand1()%rate > cycles) 298 » rate = runtime·atomicload64((uint64*)&runtime·blockprofilerate);
299 » if(rate <= 0 || (rate > cycles && runtime·fastrand1()%rate > cycles))
291 return; 300 return;
292 301
293 nstk = runtime·callers(skip, stk, 32); 302 nstk = runtime·callers(skip, stk, 32);
294 runtime·lock(&proflock); 303 runtime·lock(&proflock);
295 » b = stkbucket(CProf, stk, nstk, true); 304 » b = stkbucket(BProf, stk, nstk, true);
296 b->count++; 305 b->count++;
297 b->cycles += cycles; 306 b->cycles += cycles;
298 runtime·unlock(&proflock); 307 runtime·unlock(&proflock);
299 } 308 }
300 309
301 // Go interface to profile data. (Declared in extern.go) 310 // Go interface to profile data. (Declared in extern.go)
302 // Assumes Go sizeof(int) == sizeof(int32) 311 // Assumes Go sizeof(int) == sizeof(int32)
303 312
304 // Must match MemProfileRecord in debug.go. 313 // Must match MemProfileRecord in debug.go.
305 typedef struct Record Record; 314 typedef struct Record Record;
(...skipping 12 matching lines...) Expand all
318 r->alloc_bytes = b->alloc_bytes; 327 r->alloc_bytes = b->alloc_bytes;
319 r->free_bytes = b->free_bytes; 328 r->free_bytes = b->free_bytes;
320 r->alloc_objects = b->allocs; 329 r->alloc_objects = b->allocs;
321 r->free_objects = b->frees; 330 r->free_objects = b->frees;
322 for(i=0; i<b->nstk && i<nelem(r->stk); i++) 331 for(i=0; i<b->nstk && i<nelem(r->stk); i++)
323 r->stk[i] = b->stk[i]; 332 r->stk[i] = b->stk[i];
324 for(; i<nelem(r->stk); i++) 333 for(; i<nelem(r->stk); i++)
325 r->stk[i] = 0; 334 r->stk[i] = 0;
326 } 335 }
327 336
328 func MemProfile(p Slice, include_inuse_zero bool) (n int32, ok bool) { 337 func MemProfile(p Slice, include_inuse_zero bool) (n int, ok bool) {
329 Bucket *b; 338 Bucket *b;
330 Record *r; 339 Record *r;
331 340
332 runtime·lock(&proflock); 341 runtime·lock(&proflock);
333 n = 0; 342 n = 0;
334 for(b=mbuckets; b; b=b->allnext) 343 for(b=mbuckets; b; b=b->allnext)
335 if(include_inuse_zero || b->alloc_bytes != b->free_bytes) 344 if(include_inuse_zero || b->alloc_bytes != b->free_bytes)
336 n++; 345 n++;
337 ok = false; 346 ok = false;
338 if(n <= p.len) { 347 if(n <= p.len) {
339 ok = true; 348 ok = true;
340 r = (Record*)p.array; 349 r = (Record*)p.array;
341 for(b=mbuckets; b; b=b->allnext) 350 for(b=mbuckets; b; b=b->allnext)
342 if(include_inuse_zero || b->alloc_bytes != b->free_bytes ) 351 if(include_inuse_zero || b->alloc_bytes != b->free_bytes )
343 record(r++, b); 352 record(r++, b);
344 } 353 }
345 runtime·unlock(&proflock); 354 runtime·unlock(&proflock);
346 } 355 }
347 356
348 // Must match ContentionProfileRecord in debug.go. 357 // Must match BlockProfileRecord in debug.go.
349 typedef struct CRecord CRecord; 358 typedef struct BRecord BRecord;
350 struct CRecord { 359 struct BRecord {
351 int64 count; 360 int64 count;
352 int64 cycles; 361 int64 cycles;
353 uintptr stk[32]; 362 uintptr stk[32];
354 }; 363 };
355 364
356 func ContentionProfile(p Slice) (n int32, ok bool) { 365 func BlockProfile(p Slice) (n int, ok bool) {
357 » Bucket *b; 366 » Bucket *b;
358 » CRecord *r; 367 » BRecord *r;
359 int32 i; 368 int32 i;
360 369
361 runtime·lock(&proflock); 370 runtime·lock(&proflock);
362 n = 0; 371 n = 0;
363 » for(b=cbuckets; b; b=b->allnext) 372 » for(b=bbuckets; b; b=b->allnext)
364 n++; 373 n++;
365 ok = false; 374 ok = false;
366 if(n <= p.len) { 375 if(n <= p.len) {
367 ok = true; 376 ok = true;
368 » » r = (CRecord*)p.array; 377 » » r = (BRecord*)p.array;
369 » » for(b=cbuckets; b; b=b->allnext, r++) { 378 » » for(b=bbuckets; b; b=b->allnext, r++) {
370 r->count = b->count; 379 r->count = b->count;
371 r->cycles = b->cycles; 380 r->cycles = b->cycles;
372 for(i=0; i<b->nstk && i<nelem(r->stk); i++) 381 for(i=0; i<b->nstk && i<nelem(r->stk); i++)
373 r->stk[i] = b->stk[i]; 382 r->stk[i] = b->stk[i];
374 for(; i<nelem(r->stk); i++) 383 for(; i<nelem(r->stk); i++)
375 r->stk[i] = 0;·················· 384 r->stk[i] = 0;··················
376 } 385 }
377 } 386 }
378 runtime·unlock(&proflock); 387 runtime·unlock(&proflock);
379 } 388 }
380 389
381 // Must match StackRecord in debug.go. 390 // Must match StackRecord in debug.go.
382 typedef struct TRecord TRecord; 391 typedef struct TRecord TRecord;
383 struct TRecord { 392 struct TRecord {
384 uintptr stk[32]; 393 uintptr stk[32];
385 }; 394 };
386 395
387 func ThreadCreateProfile(p Slice) (n int32, ok bool) { 396 func ThreadCreateProfile(p Slice) (n int, ok bool) {
388 TRecord *r; 397 TRecord *r;
389 M *first, *m; 398 M *first, *m;
390 ········ 399 ········
391 first = runtime·atomicloadp(&runtime·allm); 400 first = runtime·atomicloadp(&runtime·allm);
392 n = 0; 401 n = 0;
393 for(m=first; m; m=m->alllink) 402 for(m=first; m; m=m->alllink)
394 n++; 403 n++;
395 ok = false; 404 ok = false;
396 if(n <= p.len) { 405 if(n <= p.len) {
397 ok = true; 406 ok = true;
398 r = (TRecord*)p.array; 407 r = (TRecord*)p.array;
399 for(m=first; m; m=m->alllink) { 408 for(m=first; m; m=m->alllink) {
400 runtime·memmove(r->stk, m->createstack, sizeof r->stk); 409 runtime·memmove(r->stk, m->createstack, sizeof r->stk);
401 r++; 410 r++;
402 } 411 }
403 } 412 }
404 } 413 }
405 414
406 func Stack(b Slice, all bool) (n int32) { 415 func Stack(b Slice, all bool) (n int) {
407 byte *pc, *sp; 416 byte *pc, *sp;
408 ········ 417 ········
409 sp = runtime·getcallersp(&b); 418 sp = runtime·getcallersp(&b);
410 pc = runtime·getcallerpc(&b); 419 pc = runtime·getcallerpc(&b);
411 420
412 if(all) { 421 if(all) {
413 runtime·semacquire(&runtime·worldsema); 422 runtime·semacquire(&runtime·worldsema);
414 m->gcing = 1; 423 m->gcing = 1;
415 runtime·stoptheworld(); 424 runtime·stoptheworld();
416 } 425 }
(...skipping 22 matching lines...) Expand all
439 static void 448 static void
440 saveg(byte *pc, byte *sp, G *g, TRecord *r) 449 saveg(byte *pc, byte *sp, G *g, TRecord *r)
441 { 450 {
442 int32 n; 451 int32 n;
443 ········ 452 ········
444 n = runtime·gentraceback(pc, sp, 0, g, 0, r->stk, nelem(r->stk)); 453 n = runtime·gentraceback(pc, sp, 0, g, 0, r->stk, nelem(r->stk));
445 if(n < nelem(r->stk)) 454 if(n < nelem(r->stk))
446 r->stk[n] = 0; 455 r->stk[n] = 0;
447 } 456 }
448 457
449 func GoroutineProfile(b Slice) (n int32, ok bool) { 458 func GoroutineProfile(b Slice) (n int, ok bool) {
450 byte *pc, *sp; 459 byte *pc, *sp;
451 TRecord *r; 460 TRecord *r;
452 G *gp; 461 G *gp;
453 ········ 462 ········
454 sp = runtime·getcallersp(&b); 463 sp = runtime·getcallersp(&b);
455 pc = runtime·getcallerpc(&b); 464 pc = runtime·getcallerpc(&b);
456 ········ 465 ········
457 ok = false; 466 ok = false;
458 n = runtime·gcount(); 467 n = runtime·gcount();
459 if(n <= b.len) { 468 if(n <= b.len) {
(...skipping 12 matching lines...) Expand all
472 saveg(gp->sched.pc, (byte*)gp->sched.sp, gp, r++ ); 481 saveg(gp->sched.pc, (byte*)gp->sched.sp, gp, r++ );
473 } 482 }
474 } 483 }
475 ········ 484 ········
476 m->gcing = 0; 485 m->gcing = 0;
477 runtime·semrelease(&runtime·worldsema); 486 runtime·semrelease(&runtime·worldsema);
478 runtime·starttheworld(); 487 runtime·starttheworld();
479 } 488 }
480 } 489 }
481 490
LEFTRIGHT

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