Source file src/runtime/cpuprof.go
1 // Copyright 2011 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 // CPU profiling. 6 // 7 // The signal handler for the profiling clock tick adds a new stack trace 8 // to a log of recent traces. The log is read by a user goroutine that 9 // turns it into formatted profile data. If the reader does not keep up 10 // with the log, those writes will be recorded as a count of lost records. 11 // The actual profile buffer is in profbuf.go. 12 13 package runtime 14 15 import ( 16 "internal/abi" 17 "runtime/internal/atomic" 18 "runtime/internal/sys" 19 "unsafe" 20 ) 21 22 const maxCPUProfStack = 64 23 24 type cpuProfile struct { 25 lock mutex 26 on bool // profiling is on 27 log *profBuf // profile events written here 28 29 // extra holds extra stacks accumulated in addNonGo 30 // corresponding to profiling signals arriving on 31 // non-Go-created threads. Those stacks are written 32 // to log the next time a normal Go thread gets the 33 // signal handler. 34 // Assuming the stacks are 2 words each (we don't get 35 // a full traceback from those threads), plus one word 36 // size for framing, 100 Hz profiling would generate 37 // 300 words per second. 38 // Hopefully a normal Go thread will get the profiling 39 // signal at least once every few seconds. 40 extra [1000]uintptr 41 numExtra int 42 lostExtra uint64 // count of frames lost because extra is full 43 lostAtomic uint64 // count of frames lost because of being in atomic64 on mips/arm; updated racily 44 } 45 46 var cpuprof cpuProfile 47 48 // SetCPUProfileRate sets the CPU profiling rate to hz samples per second. 49 // If hz <= 0, SetCPUProfileRate turns off profiling. 50 // If the profiler is on, the rate cannot be changed without first turning it off. 51 // 52 // Most clients should use the runtime/pprof package or 53 // the testing package's -test.cpuprofile flag instead of calling 54 // SetCPUProfileRate directly. 55 func SetCPUProfileRate(hz int) { 56 // Clamp hz to something reasonable. 57 if hz < 0 { 58 hz = 0 59 } 60 if hz > 1000000 { 61 hz = 1000000 62 } 63 64 lock(&cpuprof.lock) 65 if hz > 0 { 66 if cpuprof.on || cpuprof.log != nil { 67 print("runtime: cannot set cpu profile rate until previous profile has finished.\n") 68 unlock(&cpuprof.lock) 69 return 70 } 71 72 cpuprof.on = true 73 cpuprof.log = newProfBuf(1, 1<<17, 1<<14) 74 hdr := [1]uint64{uint64(hz)} 75 cpuprof.log.write(nil, nanotime(), hdr[:], nil) 76 setcpuprofilerate(int32(hz)) 77 } else if cpuprof.on { 78 setcpuprofilerate(0) 79 cpuprof.on = false 80 cpuprof.addExtra() 81 cpuprof.log.close() 82 } 83 unlock(&cpuprof.lock) 84 } 85 86 // add adds the stack trace to the profile. 87 // It is called from signal handlers and other limited environments 88 // and cannot allocate memory or acquire locks that might be 89 // held at the time of the signal, nor can it use substantial amounts 90 // of stack. 91 //go:nowritebarrierrec 92 func (p *cpuProfile) add(tagPtr *unsafe.Pointer, stk []uintptr) { 93 // Simple cas-lock to coordinate with setcpuprofilerate. 94 for !atomic.Cas(&prof.signalLock, 0, 1) { 95 osyield() 96 } 97 98 if prof.hz != 0 { // implies cpuprof.log != nil 99 if p.numExtra > 0 || p.lostExtra > 0 || p.lostAtomic > 0 { 100 p.addExtra() 101 } 102 hdr := [1]uint64{1} 103 // Note: write "knows" that the argument is &gp.labels, 104 // because otherwise its write barrier behavior may not 105 // be correct. See the long comment there before 106 // changing the argument here. 107 cpuprof.log.write(tagPtr, nanotime(), hdr[:], stk) 108 } 109 110 atomic.Store(&prof.signalLock, 0) 111 } 112 113 // addNonGo adds the non-Go stack trace to the profile. 114 // It is called from a non-Go thread, so we cannot use much stack at all, 115 // nor do anything that needs a g or an m. 116 // In particular, we can't call cpuprof.log.write. 117 // Instead, we copy the stack into cpuprof.extra, 118 // which will be drained the next time a Go thread 119 // gets the signal handling event. 120 //go:nosplit 121 //go:nowritebarrierrec 122 func (p *cpuProfile) addNonGo(stk []uintptr) { 123 // Simple cas-lock to coordinate with SetCPUProfileRate. 124 // (Other calls to add or addNonGo should be blocked out 125 // by the fact that only one SIGPROF can be handled by the 126 // process at a time. If not, this lock will serialize those too.) 127 for !atomic.Cas(&prof.signalLock, 0, 1) { 128 osyield() 129 } 130 131 if cpuprof.numExtra+1+len(stk) < len(cpuprof.extra) { 132 i := cpuprof.numExtra 133 cpuprof.extra[i] = uintptr(1 + len(stk)) 134 copy(cpuprof.extra[i+1:], stk) 135 cpuprof.numExtra += 1 + len(stk) 136 } else { 137 cpuprof.lostExtra++ 138 } 139 140 atomic.Store(&prof.signalLock, 0) 141 } 142 143 // addExtra adds the "extra" profiling events, 144 // queued by addNonGo, to the profile log. 145 // addExtra is called either from a signal handler on a Go thread 146 // or from an ordinary goroutine; either way it can use stack 147 // and has a g. The world may be stopped, though. 148 func (p *cpuProfile) addExtra() { 149 // Copy accumulated non-Go profile events. 150 hdr := [1]uint64{1} 151 for i := 0; i < p.numExtra; { 152 p.log.write(nil, 0, hdr[:], p.extra[i+1:i+int(p.extra[i])]) 153 i += int(p.extra[i]) 154 } 155 p.numExtra = 0 156 157 // Report any lost events. 158 if p.lostExtra > 0 { 159 hdr := [1]uint64{p.lostExtra} 160 lostStk := [2]uintptr{ 161 abi.FuncPCABIInternal(_LostExternalCode) + sys.PCQuantum, 162 abi.FuncPCABIInternal(_ExternalCode) + sys.PCQuantum, 163 } 164 p.log.write(nil, 0, hdr[:], lostStk[:]) 165 p.lostExtra = 0 166 } 167 168 if p.lostAtomic > 0 { 169 hdr := [1]uint64{p.lostAtomic} 170 lostStk := [2]uintptr{ 171 abi.FuncPCABIInternal(_LostSIGPROFDuringAtomic64) + sys.PCQuantum, 172 abi.FuncPCABIInternal(_System) + sys.PCQuantum, 173 } 174 p.log.write(nil, 0, hdr[:], lostStk[:]) 175 p.lostAtomic = 0 176 } 177 178 } 179 180 // CPUProfile panics. 181 // It formerly provided raw access to chunks of 182 // a pprof-format profile generated by the runtime. 183 // The details of generating that format have changed, 184 // so this functionality has been removed. 185 // 186 // Deprecated: Use the runtime/pprof package, 187 // or the handlers in the net/http/pprof package, 188 // or the testing package's -test.cpuprofile flag instead. 189 func CPUProfile() []byte { 190 panic("CPUProfile no longer available") 191 } 192 193 //go:linkname runtime_pprof_runtime_cyclesPerSecond runtime/pprof.runtime_cyclesPerSecond 194 func runtime_pprof_runtime_cyclesPerSecond() int64 { 195 return tickspersecond() 196 } 197 198 // readProfile, provided to runtime/pprof, returns the next chunk of 199 // binary CPU profiling stack trace data, blocking until data is available. 200 // If profiling is turned off and all the profile data accumulated while it was 201 // on has been returned, readProfile returns eof=true. 202 // The caller must save the returned data and tags before calling readProfile again. 203 // The returned data contains a whole number of records, and tags contains 204 // exactly one entry per record. 205 // 206 //go:linkname runtime_pprof_readProfile runtime/pprof.readProfile 207 func runtime_pprof_readProfile() ([]uint64, []unsafe.Pointer, bool) { 208 lock(&cpuprof.lock) 209 log := cpuprof.log 210 unlock(&cpuprof.lock) 211 data, tags, eof := log.read(profBufBlocking) 212 if len(data) == 0 && eof { 213 lock(&cpuprof.lock) 214 cpuprof.log = nil 215 unlock(&cpuprof.lock) 216 } 217 return data, tags, eof 218 } 219