github.com/ice-blockchain/go/src@v0.0.0-20240403114104-1564d284e521/runtime/pprof/pprof.go (about) 1 // Copyright 2010 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // Package pprof writes runtime profiling data in the format expected 6 // by the pprof visualization tool. 7 // 8 // # Profiling a Go program 9 // 10 // The first step to profiling a Go program is to enable profiling. 11 // Support for profiling benchmarks built with the standard testing 12 // package is built into go test. For example, the following command 13 // runs benchmarks in the current directory and writes the CPU and 14 // memory profiles to cpu.prof and mem.prof: 15 // 16 // go test -cpuprofile cpu.prof -memprofile mem.prof -bench . 17 // 18 // To add equivalent profiling support to a standalone program, add 19 // code like the following to your main function: 20 // 21 // var cpuprofile = flag.String("cpuprofile", "", "write cpu profile to `file`") 22 // var memprofile = flag.String("memprofile", "", "write memory profile to `file`") 23 // 24 // func main() { 25 // flag.Parse() 26 // if *cpuprofile != "" { 27 // f, err := os.Create(*cpuprofile) 28 // if err != nil { 29 // log.Fatal("could not create CPU profile: ", err) 30 // } 31 // defer f.Close() // error handling omitted for example 32 // if err := pprof.StartCPUProfile(f); err != nil { 33 // log.Fatal("could not start CPU profile: ", err) 34 // } 35 // defer pprof.StopCPUProfile() 36 // } 37 // 38 // // ... rest of the program ... 39 // 40 // if *memprofile != "" { 41 // f, err := os.Create(*memprofile) 42 // if err != nil { 43 // log.Fatal("could not create memory profile: ", err) 44 // } 45 // defer f.Close() // error handling omitted for example 46 // runtime.GC() // get up-to-date statistics 47 // if err := pprof.WriteHeapProfile(f); err != nil { 48 // log.Fatal("could not write memory profile: ", err) 49 // } 50 // } 51 // } 52 // 53 // There is also a standard HTTP interface to profiling data. Adding 54 // the following line will install handlers under the /debug/pprof/ 55 // URL to download live profiles: 56 // 57 // import _ "net/http/pprof" 58 // 59 // See the net/http/pprof package for more details. 60 // 61 // Profiles can then be visualized with the pprof tool: 62 // 63 // go tool pprof cpu.prof 64 // 65 // There are many commands available from the pprof command line. 66 // Commonly used commands include "top", which prints a summary of the 67 // top program hot-spots, and "web", which opens an interactive graph 68 // of hot-spots and their call graphs. Use "help" for information on 69 // all pprof commands. 70 // 71 // For more information about pprof, see 72 // https://github.com/google/pprof/blob/main/doc/README.md. 73 package pprof 74 75 import ( 76 "bufio" 77 "fmt" 78 "internal/abi" 79 "io" 80 "runtime" 81 "sort" 82 "strings" 83 "sync" 84 "text/tabwriter" 85 "time" 86 "unsafe" 87 ) 88 89 // BUG(rsc): Profiles are only as good as the kernel support used to generate them. 90 // See https://golang.org/issue/13841 for details about known problems. 91 92 // A Profile is a collection of stack traces showing the call sequences 93 // that led to instances of a particular event, such as allocation. 94 // Packages can create and maintain their own profiles; the most common 95 // use is for tracking resources that must be explicitly closed, such as files 96 // or network connections. 97 // 98 // A Profile's methods can be called from multiple goroutines simultaneously. 99 // 100 // Each Profile has a unique name. A few profiles are predefined: 101 // 102 // goroutine - stack traces of all current goroutines 103 // heap - a sampling of memory allocations of live objects 104 // allocs - a sampling of all past memory allocations 105 // threadcreate - stack traces that led to the creation of new OS threads 106 // block - stack traces that led to blocking on synchronization primitives 107 // mutex - stack traces of holders of contended mutexes 108 // 109 // These predefined profiles maintain themselves and panic on an explicit 110 // [Profile.Add] or [Profile.Remove] method call. 111 // 112 // The CPU profile is not available as a Profile. It has a special API, 113 // the [StartCPUProfile] and [StopCPUProfile] functions, because it streams 114 // output to a writer during profiling. 115 // 116 // # Heap profile 117 // 118 // The heap profile reports statistics as of the most recently completed 119 // garbage collection; it elides more recent allocation to avoid skewing 120 // the profile away from live data and toward garbage. 121 // If there has been no garbage collection at all, the heap profile reports 122 // all known allocations. This exception helps mainly in programs running 123 // without garbage collection enabled, usually for debugging purposes. 124 // 125 // The heap profile tracks both the allocation sites for all live objects in 126 // the application memory and for all objects allocated since the program start. 127 // Pprof's -inuse_space, -inuse_objects, -alloc_space, and -alloc_objects 128 // flags select which to display, defaulting to -inuse_space (live objects, 129 // scaled by size). 130 // 131 // # Allocs profile 132 // 133 // The allocs profile is the same as the heap profile but changes the default 134 // pprof display to -alloc_space, the total number of bytes allocated since 135 // the program began (including garbage-collected bytes). 136 // 137 // # Block profile 138 // 139 // The block profile tracks time spent blocked on synchronization primitives, 140 // such as [sync.Mutex], [sync.RWMutex], [sync.WaitGroup], [sync.Cond], and 141 // channel send/receive/select. 142 // 143 // Stack traces correspond to the location that blocked (for example, 144 // [sync.Mutex.Lock]). 145 // 146 // Sample values correspond to cumulative time spent blocked at that stack 147 // trace, subject to time-based sampling specified by 148 // [runtime.SetBlockProfileRate]. 149 // 150 // # Mutex profile 151 // 152 // The mutex profile tracks contention on mutexes, such as [sync.Mutex], 153 // [sync.RWMutex], and runtime-internal locks. 154 // 155 // Stack traces correspond to the end of the critical section causing 156 // contention. For example, a lock held for a long time while other goroutines 157 // are waiting to acquire the lock will report contention when the lock is 158 // finally unlocked (that is, at [sync.Mutex.Unlock]). 159 // 160 // Sample values correspond to the approximate cumulative time other goroutines 161 // spent blocked waiting for the lock, subject to event-based sampling 162 // specified by [runtime.SetMutexProfileFraction]. For example, if a caller 163 // holds a lock for 1s while 5 other goroutines are waiting for the entire 164 // second to acquire the lock, its unlock call stack will report 5s of 165 // contention. 166 // 167 // Runtime-internal locks are always reported at the location 168 // "runtime._LostContendedRuntimeLock". More detailed stack traces for 169 // runtime-internal locks can be obtained by setting 170 // `GODEBUG=runtimecontentionstacks=1` (see package [runtime] docs for 171 // caveats). 172 type Profile struct { 173 name string 174 mu sync.Mutex 175 m map[any][]uintptr 176 count func() int 177 write func(io.Writer, int) error 178 } 179 180 // profiles records all registered profiles. 181 var profiles struct { 182 mu sync.Mutex 183 m map[string]*Profile 184 } 185 186 var goroutineProfile = &Profile{ 187 name: "goroutine", 188 count: countGoroutine, 189 write: writeGoroutine, 190 } 191 192 var threadcreateProfile = &Profile{ 193 name: "threadcreate", 194 count: countThreadCreate, 195 write: writeThreadCreate, 196 } 197 198 var heapProfile = &Profile{ 199 name: "heap", 200 count: countHeap, 201 write: writeHeap, 202 } 203 204 var allocsProfile = &Profile{ 205 name: "allocs", 206 count: countHeap, // identical to heap profile 207 write: writeAlloc, 208 } 209 210 var blockProfile = &Profile{ 211 name: "block", 212 count: countBlock, 213 write: writeBlock, 214 } 215 216 var mutexProfile = &Profile{ 217 name: "mutex", 218 count: countMutex, 219 write: writeMutex, 220 } 221 222 func lockProfiles() { 223 profiles.mu.Lock() 224 if profiles.m == nil { 225 // Initial built-in profiles. 226 profiles.m = map[string]*Profile{ 227 "goroutine": goroutineProfile, 228 "threadcreate": threadcreateProfile, 229 "heap": heapProfile, 230 "allocs": allocsProfile, 231 "block": blockProfile, 232 "mutex": mutexProfile, 233 } 234 } 235 } 236 237 func unlockProfiles() { 238 profiles.mu.Unlock() 239 } 240 241 // NewProfile creates a new profile with the given name. 242 // If a profile with that name already exists, NewProfile panics. 243 // The convention is to use a 'import/path.' prefix to create 244 // separate name spaces for each package. 245 // For compatibility with various tools that read pprof data, 246 // profile names should not contain spaces. 247 func NewProfile(name string) *Profile { 248 lockProfiles() 249 defer unlockProfiles() 250 if name == "" { 251 panic("pprof: NewProfile with empty name") 252 } 253 if profiles.m[name] != nil { 254 panic("pprof: NewProfile name already in use: " + name) 255 } 256 p := &Profile{ 257 name: name, 258 m: map[any][]uintptr{}, 259 } 260 profiles.m[name] = p 261 return p 262 } 263 264 // Lookup returns the profile with the given name, or nil if no such profile exists. 265 func Lookup(name string) *Profile { 266 lockProfiles() 267 defer unlockProfiles() 268 return profiles.m[name] 269 } 270 271 // Profiles returns a slice of all the known profiles, sorted by name. 272 func Profiles() []*Profile { 273 lockProfiles() 274 defer unlockProfiles() 275 276 all := make([]*Profile, 0, len(profiles.m)) 277 for _, p := range profiles.m { 278 all = append(all, p) 279 } 280 281 sort.Slice(all, func(i, j int) bool { return all[i].name < all[j].name }) 282 return all 283 } 284 285 // Name returns this profile's name, which can be passed to [Lookup] to reobtain the profile. 286 func (p *Profile) Name() string { 287 return p.name 288 } 289 290 // Count returns the number of execution stacks currently in the profile. 291 func (p *Profile) Count() int { 292 p.mu.Lock() 293 defer p.mu.Unlock() 294 if p.count != nil { 295 return p.count() 296 } 297 return len(p.m) 298 } 299 300 // Add adds the current execution stack to the profile, associated with value. 301 // Add stores value in an internal map, so value must be suitable for use as 302 // a map key and will not be garbage collected until the corresponding 303 // call to [Profile.Remove]. Add panics if the profile already contains a stack for value. 304 // 305 // The skip parameter has the same meaning as [runtime.Caller]'s skip 306 // and controls where the stack trace begins. Passing skip=0 begins the 307 // trace in the function calling Add. For example, given this 308 // execution stack: 309 // 310 // Add 311 // called from rpc.NewClient 312 // called from mypkg.Run 313 // called from main.main 314 // 315 // Passing skip=0 begins the stack trace at the call to Add inside rpc.NewClient. 316 // Passing skip=1 begins the stack trace at the call to NewClient inside mypkg.Run. 317 func (p *Profile) Add(value any, skip int) { 318 if p.name == "" { 319 panic("pprof: use of uninitialized Profile") 320 } 321 if p.write != nil { 322 panic("pprof: Add called on built-in Profile " + p.name) 323 } 324 325 stk := make([]uintptr, 32) 326 n := runtime.Callers(skip+1, stk[:]) 327 stk = stk[:n] 328 if len(stk) == 0 { 329 // The value for skip is too large, and there's no stack trace to record. 330 stk = []uintptr{abi.FuncPCABIInternal(lostProfileEvent)} 331 } 332 333 p.mu.Lock() 334 defer p.mu.Unlock() 335 if p.m[value] != nil { 336 panic("pprof: Profile.Add of duplicate value") 337 } 338 p.m[value] = stk 339 } 340 341 // Remove removes the execution stack associated with value from the profile. 342 // It is a no-op if the value is not in the profile. 343 func (p *Profile) Remove(value any) { 344 p.mu.Lock() 345 defer p.mu.Unlock() 346 delete(p.m, value) 347 } 348 349 // WriteTo writes a pprof-formatted snapshot of the profile to w. 350 // If a write to w returns an error, WriteTo returns that error. 351 // Otherwise, WriteTo returns nil. 352 // 353 // The debug parameter enables additional output. 354 // Passing debug=0 writes the gzip-compressed protocol buffer described 355 // in https://github.com/google/pprof/tree/main/proto#overview. 356 // Passing debug=1 writes the legacy text format with comments 357 // translating addresses to function names and line numbers, so that a 358 // programmer can read the profile without tools. 359 // 360 // The predefined profiles may assign meaning to other debug values; 361 // for example, when printing the "goroutine" profile, debug=2 means to 362 // print the goroutine stacks in the same form that a Go program uses 363 // when dying due to an unrecovered panic. 364 func (p *Profile) WriteTo(w io.Writer, debug int) error { 365 if p.name == "" { 366 panic("pprof: use of zero Profile") 367 } 368 if p.write != nil { 369 return p.write(w, debug) 370 } 371 372 // Obtain consistent snapshot under lock; then process without lock. 373 p.mu.Lock() 374 all := make([][]uintptr, 0, len(p.m)) 375 for _, stk := range p.m { 376 all = append(all, stk) 377 } 378 p.mu.Unlock() 379 380 // Map order is non-deterministic; make output deterministic. 381 sort.Slice(all, func(i, j int) bool { 382 t, u := all[i], all[j] 383 for k := 0; k < len(t) && k < len(u); k++ { 384 if t[k] != u[k] { 385 return t[k] < u[k] 386 } 387 } 388 return len(t) < len(u) 389 }) 390 391 return printCountProfile(w, debug, p.name, stackProfile(all)) 392 } 393 394 type stackProfile [][]uintptr 395 396 func (x stackProfile) Len() int { return len(x) } 397 func (x stackProfile) Stack(i int) []uintptr { return x[i] } 398 func (x stackProfile) Label(i int) *labelMap { return nil } 399 400 // A countProfile is a set of stack traces to be printed as counts 401 // grouped by stack trace. There are multiple implementations: 402 // all that matters is that we can find out how many traces there are 403 // and obtain each trace in turn. 404 type countProfile interface { 405 Len() int 406 Stack(i int) []uintptr 407 Label(i int) *labelMap 408 } 409 410 // printCountCycleProfile outputs block profile records (for block or mutex profiles) 411 // as the pprof-proto format output. Translations from cycle count to time duration 412 // are done because The proto expects count and time (nanoseconds) instead of count 413 // and the number of cycles for block, contention profiles. 414 func printCountCycleProfile(w io.Writer, countName, cycleName string, records []runtime.BlockProfileRecord) error { 415 // Output profile in protobuf form. 416 b := newProfileBuilder(w) 417 b.pbValueType(tagProfile_PeriodType, countName, "count") 418 b.pb.int64Opt(tagProfile_Period, 1) 419 b.pbValueType(tagProfile_SampleType, countName, "count") 420 b.pbValueType(tagProfile_SampleType, cycleName, "nanoseconds") 421 422 cpuGHz := float64(runtime_cyclesPerSecond()) / 1e9 423 424 values := []int64{0, 0} 425 var locs []uint64 426 for _, r := range records { 427 values[0] = r.Count 428 values[1] = int64(float64(r.Cycles) / cpuGHz) 429 // For count profiles, all stack addresses are 430 // return PCs, which is what appendLocsForStack expects. 431 locs = b.appendLocsForStack(locs[:0], r.Stack()) 432 b.pbSample(values, locs, nil) 433 } 434 b.build() 435 return nil 436 } 437 438 // printCountProfile prints a countProfile at the specified debug level. 439 // The profile will be in compressed proto format unless debug is nonzero. 440 func printCountProfile(w io.Writer, debug int, name string, p countProfile) error { 441 // Build count of each stack. 442 var buf strings.Builder 443 key := func(stk []uintptr, lbls *labelMap) string { 444 buf.Reset() 445 fmt.Fprintf(&buf, "@") 446 for _, pc := range stk { 447 fmt.Fprintf(&buf, " %#x", pc) 448 } 449 if lbls != nil { 450 buf.WriteString("\n# labels: ") 451 buf.WriteString(lbls.String()) 452 } 453 return buf.String() 454 } 455 count := map[string]int{} 456 index := map[string]int{} 457 var keys []string 458 n := p.Len() 459 for i := 0; i < n; i++ { 460 k := key(p.Stack(i), p.Label(i)) 461 if count[k] == 0 { 462 index[k] = i 463 keys = append(keys, k) 464 } 465 count[k]++ 466 } 467 468 sort.Sort(&keysByCount{keys, count}) 469 470 if debug > 0 { 471 // Print debug profile in legacy format 472 tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) 473 fmt.Fprintf(tw, "%s profile: total %d\n", name, p.Len()) 474 for _, k := range keys { 475 fmt.Fprintf(tw, "%d %s\n", count[k], k) 476 printStackRecord(tw, p.Stack(index[k]), false) 477 } 478 return tw.Flush() 479 } 480 481 // Output profile in protobuf form. 482 b := newProfileBuilder(w) 483 b.pbValueType(tagProfile_PeriodType, name, "count") 484 b.pb.int64Opt(tagProfile_Period, 1) 485 b.pbValueType(tagProfile_SampleType, name, "count") 486 487 values := []int64{0} 488 var locs []uint64 489 for _, k := range keys { 490 values[0] = int64(count[k]) 491 // For count profiles, all stack addresses are 492 // return PCs, which is what appendLocsForStack expects. 493 locs = b.appendLocsForStack(locs[:0], p.Stack(index[k])) 494 idx := index[k] 495 var labels func() 496 if p.Label(idx) != nil { 497 labels = func() { 498 for k, v := range *p.Label(idx) { 499 b.pbLabel(tagSample_Label, k, v, 0) 500 } 501 } 502 } 503 b.pbSample(values, locs, labels) 504 } 505 b.build() 506 return nil 507 } 508 509 // keysByCount sorts keys with higher counts first, breaking ties by key string order. 510 type keysByCount struct { 511 keys []string 512 count map[string]int 513 } 514 515 func (x *keysByCount) Len() int { return len(x.keys) } 516 func (x *keysByCount) Swap(i, j int) { x.keys[i], x.keys[j] = x.keys[j], x.keys[i] } 517 func (x *keysByCount) Less(i, j int) bool { 518 ki, kj := x.keys[i], x.keys[j] 519 ci, cj := x.count[ki], x.count[kj] 520 if ci != cj { 521 return ci > cj 522 } 523 return ki < kj 524 } 525 526 // printStackRecord prints the function + source line information 527 // for a single stack trace. 528 func printStackRecord(w io.Writer, stk []uintptr, allFrames bool) { 529 show := allFrames 530 frames := runtime.CallersFrames(stk) 531 for { 532 frame, more := frames.Next() 533 name := frame.Function 534 if name == "" { 535 show = true 536 fmt.Fprintf(w, "#\t%#x\n", frame.PC) 537 } else if name != "runtime.goexit" && (show || !strings.HasPrefix(name, "runtime.")) { 538 // Hide runtime.goexit and any runtime functions at the beginning. 539 // This is useful mainly for allocation traces. 540 show = true 541 fmt.Fprintf(w, "#\t%#x\t%s+%#x\t%s:%d\n", frame.PC, name, frame.PC-frame.Entry, frame.File, frame.Line) 542 } 543 if !more { 544 break 545 } 546 } 547 if !show { 548 // We didn't print anything; do it again, 549 // and this time include runtime functions. 550 printStackRecord(w, stk, true) 551 return 552 } 553 fmt.Fprintf(w, "\n") 554 } 555 556 // Interface to system profiles. 557 558 // WriteHeapProfile is shorthand for [Lookup]("heap").WriteTo(w, 0). 559 // It is preserved for backwards compatibility. 560 func WriteHeapProfile(w io.Writer) error { 561 return writeHeap(w, 0) 562 } 563 564 // countHeap returns the number of records in the heap profile. 565 func countHeap() int { 566 n, _ := runtime.MemProfile(nil, true) 567 return n 568 } 569 570 // writeHeap writes the current runtime heap profile to w. 571 func writeHeap(w io.Writer, debug int) error { 572 return writeHeapInternal(w, debug, "") 573 } 574 575 // writeAlloc writes the current runtime heap profile to w 576 // with the total allocation space as the default sample type. 577 func writeAlloc(w io.Writer, debug int) error { 578 return writeHeapInternal(w, debug, "alloc_space") 579 } 580 581 func writeHeapInternal(w io.Writer, debug int, defaultSampleType string) error { 582 var memStats *runtime.MemStats 583 if debug != 0 { 584 // Read mem stats first, so that our other allocations 585 // do not appear in the statistics. 586 memStats = new(runtime.MemStats) 587 runtime.ReadMemStats(memStats) 588 } 589 590 // Find out how many records there are (MemProfile(nil, true)), 591 // allocate that many records, and get the data. 592 // There's a race—more records might be added between 593 // the two calls—so allocate a few extra records for safety 594 // and also try again if we're very unlucky. 595 // The loop should only execute one iteration in the common case. 596 var p []runtime.MemProfileRecord 597 n, ok := runtime.MemProfile(nil, true) 598 for { 599 // Allocate room for a slightly bigger profile, 600 // in case a few more entries have been added 601 // since the call to MemProfile. 602 p = make([]runtime.MemProfileRecord, n+50) 603 n, ok = runtime.MemProfile(p, true) 604 if ok { 605 p = p[0:n] 606 break 607 } 608 // Profile grew; try again. 609 } 610 611 if debug == 0 { 612 return writeHeapProto(w, p, int64(runtime.MemProfileRate), defaultSampleType) 613 } 614 615 sort.Slice(p, func(i, j int) bool { return p[i].InUseBytes() > p[j].InUseBytes() }) 616 617 b := bufio.NewWriter(w) 618 tw := tabwriter.NewWriter(b, 1, 8, 1, '\t', 0) 619 w = tw 620 621 var total runtime.MemProfileRecord 622 for i := range p { 623 r := &p[i] 624 total.AllocBytes += r.AllocBytes 625 total.AllocObjects += r.AllocObjects 626 total.FreeBytes += r.FreeBytes 627 total.FreeObjects += r.FreeObjects 628 } 629 630 // Technically the rate is MemProfileRate not 2*MemProfileRate, 631 // but early versions of the C++ heap profiler reported 2*MemProfileRate, 632 // so that's what pprof has come to expect. 633 rate := 2 * runtime.MemProfileRate 634 635 // pprof reads a profile with alloc == inuse as being a "2-column" profile 636 // (objects and bytes, not distinguishing alloc from inuse), 637 // but then such a profile can't be merged using pprof *.prof with 638 // other 4-column profiles where alloc != inuse. 639 // The easiest way to avoid this bug is to adjust allocBytes so it's never == inuseBytes. 640 // pprof doesn't use these header values anymore except for checking equality. 641 inUseBytes := total.InUseBytes() 642 allocBytes := total.AllocBytes 643 if inUseBytes == allocBytes { 644 allocBytes++ 645 } 646 647 fmt.Fprintf(w, "heap profile: %d: %d [%d: %d] @ heap/%d\n", 648 total.InUseObjects(), inUseBytes, 649 total.AllocObjects, allocBytes, 650 rate) 651 652 for i := range p { 653 r := &p[i] 654 fmt.Fprintf(w, "%d: %d [%d: %d] @", 655 r.InUseObjects(), r.InUseBytes(), 656 r.AllocObjects, r.AllocBytes) 657 for _, pc := range r.Stack() { 658 fmt.Fprintf(w, " %#x", pc) 659 } 660 fmt.Fprintf(w, "\n") 661 printStackRecord(w, r.Stack(), false) 662 } 663 664 // Print memstats information too. 665 // Pprof will ignore, but useful for people 666 s := memStats 667 fmt.Fprintf(w, "\n# runtime.MemStats\n") 668 fmt.Fprintf(w, "# Alloc = %d\n", s.Alloc) 669 fmt.Fprintf(w, "# TotalAlloc = %d\n", s.TotalAlloc) 670 fmt.Fprintf(w, "# Sys = %d\n", s.Sys) 671 fmt.Fprintf(w, "# Lookups = %d\n", s.Lookups) 672 fmt.Fprintf(w, "# Mallocs = %d\n", s.Mallocs) 673 fmt.Fprintf(w, "# Frees = %d\n", s.Frees) 674 675 fmt.Fprintf(w, "# HeapAlloc = %d\n", s.HeapAlloc) 676 fmt.Fprintf(w, "# HeapSys = %d\n", s.HeapSys) 677 fmt.Fprintf(w, "# HeapIdle = %d\n", s.HeapIdle) 678 fmt.Fprintf(w, "# HeapInuse = %d\n", s.HeapInuse) 679 fmt.Fprintf(w, "# HeapReleased = %d\n", s.HeapReleased) 680 fmt.Fprintf(w, "# HeapObjects = %d\n", s.HeapObjects) 681 682 fmt.Fprintf(w, "# Stack = %d / %d\n", s.StackInuse, s.StackSys) 683 fmt.Fprintf(w, "# MSpan = %d / %d\n", s.MSpanInuse, s.MSpanSys) 684 fmt.Fprintf(w, "# MCache = %d / %d\n", s.MCacheInuse, s.MCacheSys) 685 fmt.Fprintf(w, "# BuckHashSys = %d\n", s.BuckHashSys) 686 fmt.Fprintf(w, "# GCSys = %d\n", s.GCSys) 687 fmt.Fprintf(w, "# OtherSys = %d\n", s.OtherSys) 688 689 fmt.Fprintf(w, "# NextGC = %d\n", s.NextGC) 690 fmt.Fprintf(w, "# LastGC = %d\n", s.LastGC) 691 fmt.Fprintf(w, "# PauseNs = %d\n", s.PauseNs) 692 fmt.Fprintf(w, "# PauseEnd = %d\n", s.PauseEnd) 693 fmt.Fprintf(w, "# NumGC = %d\n", s.NumGC) 694 fmt.Fprintf(w, "# NumForcedGC = %d\n", s.NumForcedGC) 695 fmt.Fprintf(w, "# GCCPUFraction = %v\n", s.GCCPUFraction) 696 fmt.Fprintf(w, "# DebugGC = %v\n", s.DebugGC) 697 698 // Also flush out MaxRSS on supported platforms. 699 addMaxRSS(w) 700 701 tw.Flush() 702 return b.Flush() 703 } 704 705 // countThreadCreate returns the size of the current ThreadCreateProfile. 706 func countThreadCreate() int { 707 n, _ := runtime.ThreadCreateProfile(nil) 708 return n 709 } 710 711 // writeThreadCreate writes the current runtime ThreadCreateProfile to w. 712 func writeThreadCreate(w io.Writer, debug int) error { 713 // Until https://golang.org/issues/6104 is addressed, wrap 714 // ThreadCreateProfile because there's no point in tracking labels when we 715 // don't get any stack-traces. 716 return writeRuntimeProfile(w, debug, "threadcreate", func(p []runtime.StackRecord, _ []unsafe.Pointer) (n int, ok bool) { 717 return runtime.ThreadCreateProfile(p) 718 }) 719 } 720 721 // countGoroutine returns the number of goroutines. 722 func countGoroutine() int { 723 return runtime.NumGoroutine() 724 } 725 726 // runtime_goroutineProfileWithLabels is defined in runtime/mprof.go 727 func runtime_goroutineProfileWithLabels(p []runtime.StackRecord, labels []unsafe.Pointer) (n int, ok bool) 728 729 // writeGoroutine writes the current runtime GoroutineProfile to w. 730 func writeGoroutine(w io.Writer, debug int) error { 731 if debug >= 2 { 732 return writeGoroutineStacks(w) 733 } 734 return writeRuntimeProfile(w, debug, "goroutine", runtime_goroutineProfileWithLabels) 735 } 736 737 func writeGoroutineStacks(w io.Writer) error { 738 // We don't know how big the buffer needs to be to collect 739 // all the goroutines. Start with 1 MB and try a few times, doubling each time. 740 // Give up and use a truncated trace if 64 MB is not enough. 741 buf := make([]byte, 1<<20) 742 for i := 0; ; i++ { 743 n := runtime.Stack(buf, true) 744 if n < len(buf) { 745 buf = buf[:n] 746 break 747 } 748 if len(buf) >= 64<<20 { 749 // Filled 64 MB - stop there. 750 break 751 } 752 buf = make([]byte, 2*len(buf)) 753 } 754 _, err := w.Write(buf) 755 return err 756 } 757 758 func writeRuntimeProfile(w io.Writer, debug int, name string, fetch func([]runtime.StackRecord, []unsafe.Pointer) (int, bool)) error { 759 // Find out how many records there are (fetch(nil)), 760 // allocate that many records, and get the data. 761 // There's a race—more records might be added between 762 // the two calls—so allocate a few extra records for safety 763 // and also try again if we're very unlucky. 764 // The loop should only execute one iteration in the common case. 765 var p []runtime.StackRecord 766 var labels []unsafe.Pointer 767 n, ok := fetch(nil, nil) 768 769 for { 770 // Allocate room for a slightly bigger profile, 771 // in case a few more entries have been added 772 // since the call to ThreadProfile. 773 p = make([]runtime.StackRecord, n+10) 774 labels = make([]unsafe.Pointer, n+10) 775 n, ok = fetch(p, labels) 776 if ok { 777 p = p[0:n] 778 break 779 } 780 // Profile grew; try again. 781 } 782 783 return printCountProfile(w, debug, name, &runtimeProfile{p, labels}) 784 } 785 786 type runtimeProfile struct { 787 stk []runtime.StackRecord 788 labels []unsafe.Pointer 789 } 790 791 func (p *runtimeProfile) Len() int { return len(p.stk) } 792 func (p *runtimeProfile) Stack(i int) []uintptr { return p.stk[i].Stack() } 793 func (p *runtimeProfile) Label(i int) *labelMap { return (*labelMap)(p.labels[i]) } 794 795 var cpu struct { 796 sync.Mutex 797 profiling bool 798 done chan bool 799 } 800 801 // StartCPUProfile enables CPU profiling for the current process. 802 // While profiling, the profile will be buffered and written to w. 803 // StartCPUProfile returns an error if profiling is already enabled. 804 // 805 // On Unix-like systems, StartCPUProfile does not work by default for 806 // Go code built with -buildmode=c-archive or -buildmode=c-shared. 807 // StartCPUProfile relies on the SIGPROF signal, but that signal will 808 // be delivered to the main program's SIGPROF signal handler (if any) 809 // not to the one used by Go. To make it work, call [os/signal.Notify] 810 // for [syscall.SIGPROF], but note that doing so may break any profiling 811 // being done by the main program. 812 func StartCPUProfile(w io.Writer) error { 813 // The runtime routines allow a variable profiling rate, 814 // but in practice operating systems cannot trigger signals 815 // at more than about 500 Hz, and our processing of the 816 // signal is not cheap (mostly getting the stack trace). 817 // 100 Hz is a reasonable choice: it is frequent enough to 818 // produce useful data, rare enough not to bog down the 819 // system, and a nice round number to make it easy to 820 // convert sample counts to seconds. Instead of requiring 821 // each client to specify the frequency, we hard code it. 822 const hz = 100 823 824 cpu.Lock() 825 defer cpu.Unlock() 826 if cpu.done == nil { 827 cpu.done = make(chan bool) 828 } 829 // Double-check. 830 if cpu.profiling { 831 return fmt.Errorf("cpu profiling already in use") 832 } 833 cpu.profiling = true 834 runtime.SetCPUProfileRate(hz) 835 go profileWriter(w) 836 return nil 837 } 838 839 // readProfile, provided by the runtime, returns the next chunk of 840 // binary CPU profiling stack trace data, blocking until data is available. 841 // If profiling is turned off and all the profile data accumulated while it was 842 // on has been returned, readProfile returns eof=true. 843 // The caller must save the returned data and tags before calling readProfile again. 844 func readProfile() (data []uint64, tags []unsafe.Pointer, eof bool) 845 846 func profileWriter(w io.Writer) { 847 b := newProfileBuilder(w) 848 var err error 849 for { 850 time.Sleep(100 * time.Millisecond) 851 data, tags, eof := readProfile() 852 if e := b.addCPUData(data, tags); e != nil && err == nil { 853 err = e 854 } 855 if eof { 856 break 857 } 858 } 859 if err != nil { 860 // The runtime should never produce an invalid or truncated profile. 861 // It drops records that can't fit into its log buffers. 862 panic("runtime/pprof: converting profile: " + err.Error()) 863 } 864 b.build() 865 cpu.done <- true 866 } 867 868 // StopCPUProfile stops the current CPU profile, if any. 869 // StopCPUProfile only returns after all the writes for the 870 // profile have completed. 871 func StopCPUProfile() { 872 cpu.Lock() 873 defer cpu.Unlock() 874 875 if !cpu.profiling { 876 return 877 } 878 cpu.profiling = false 879 runtime.SetCPUProfileRate(0) 880 <-cpu.done 881 } 882 883 // countBlock returns the number of records in the blocking profile. 884 func countBlock() int { 885 n, _ := runtime.BlockProfile(nil) 886 return n 887 } 888 889 // countMutex returns the number of records in the mutex profile. 890 func countMutex() int { 891 n, _ := runtime.MutexProfile(nil) 892 return n 893 } 894 895 // writeBlock writes the current blocking profile to w. 896 func writeBlock(w io.Writer, debug int) error { 897 return writeProfileInternal(w, debug, "contention", runtime.BlockProfile) 898 } 899 900 // writeMutex writes the current mutex profile to w. 901 func writeMutex(w io.Writer, debug int) error { 902 return writeProfileInternal(w, debug, "mutex", runtime.MutexProfile) 903 } 904 905 // writeProfileInternal writes the current blocking or mutex profile depending on the passed parameters. 906 func writeProfileInternal(w io.Writer, debug int, name string, runtimeProfile func([]runtime.BlockProfileRecord) (int, bool)) error { 907 var p []runtime.BlockProfileRecord 908 n, ok := runtimeProfile(nil) 909 for { 910 p = make([]runtime.BlockProfileRecord, n+50) 911 n, ok = runtimeProfile(p) 912 if ok { 913 p = p[:n] 914 break 915 } 916 } 917 918 sort.Slice(p, func(i, j int) bool { return p[i].Cycles > p[j].Cycles }) 919 920 if debug <= 0 { 921 return printCountCycleProfile(w, "contentions", "delay", p) 922 } 923 924 b := bufio.NewWriter(w) 925 tw := tabwriter.NewWriter(w, 1, 8, 1, '\t', 0) 926 w = tw 927 928 fmt.Fprintf(w, "--- %v:\n", name) 929 fmt.Fprintf(w, "cycles/second=%v\n", runtime_cyclesPerSecond()) 930 if name == "mutex" { 931 fmt.Fprintf(w, "sampling period=%d\n", runtime.SetMutexProfileFraction(-1)) 932 } 933 for i := range p { 934 r := &p[i] 935 fmt.Fprintf(w, "%v %v @", r.Cycles, r.Count) 936 for _, pc := range r.Stack() { 937 fmt.Fprintf(w, " %#x", pc) 938 } 939 fmt.Fprint(w, "\n") 940 if debug > 0 { 941 printStackRecord(w, r.Stack(), true) 942 } 943 } 944 945 if tw != nil { 946 tw.Flush() 947 } 948 return b.Flush() 949 } 950 951 func runtime_cyclesPerSecond() int64