Skip to content

Instantly share code, notes, and snippets.

@ivankelly
Created November 10, 2021 10:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ivankelly/883ad764614c195bba0f5d8895e480aa to your computer and use it in GitHub Desktop.
Save ivankelly/883ad764614c195bba0f5d8895e480aa to your computer and use it in GitHub Desktop.
package main
import (
"context"
"fmt"
"runtime/pprof"
"sync/atomic"
"time"
"unsafe"
)
func main() {
ctx := pprof.WithLabels(context.TODO(), pprof.Labels("test", "foobar"))
pprof.SetGoroutineLabels(ctx)
ptr := runtime_getProfLabel()
var status *uint32
status = nil
forEachGRace(func(g *g) {
if ptr == g.labels {
fmt.Printf("status %d - %x %v\n", g.goid, g.atomicstatus, g.labels)
status = &g.atomicstatus
}
})
var running uint64
ticker := time.NewTicker(time.Second / 100)
go func() {
for {
<-ticker.C
status_value := atomic.LoadUint32(status)
if (status_value & 0xFFF) == 2 {
atomic.AddUint64(&running, 1)
}
}
}()
outticker := time.NewTicker(time.Second)
go func() {
previous := uint64(0)
for {
<-outticker.C
current := atomic.LoadUint64(&running)
fmt.Printf("Running: total(%d) delta(%d)\n", current, current-previous)
previous = current
}
}()
for {
sleep := time.Second / 4
run := time.Second - sleep
start := time.Now()
for {
if time.Since(start) > run {
break
}
}
time.Sleep(sleep)
}
}
func getg() interface{} {
return nil
}
type stack struct {
lo uintptr
hi uintptr
}
type gobuf struct {
// The offsets of sp, pc, and g are known to (hard-coded in) libmach.
//
// ctxt is unusual with respect to GC: it may be a
// heap-allocated funcval, so GC needs to track it, but it
// needs to be set and cleared from assembly, where it's
// difficult to have write barriers. However, ctxt is really a
// saved, live register, and we only ever exchange it between
// the real register and the gobuf. Hence, we treat it as a
// root during stack scanning, which means assembly that saves
// and restores it doesn't need write barriers. It's still
// typed as a pointer so that any other writes from Go get
// write barriers.
sp uintptr
pc uintptr
g uintptr
ctxt unsafe.Pointer
ret uintptr
lr uintptr
bp uintptr // for framepointer-enabled architectures
}
type g struct {
// Stack parameters.
// stack describes the actual stack memory: [stack.lo, stack.hi).
// stackguard0 is the stack pointer compared in the Go stack growth prologue.
// It is stack.lo+StackGuard normally, but can be StackPreempt to trigger a preemption.
// stackguard1 is the stack pointer compared in the C stack growth prologue.
// It is stack.lo+StackGuard on g0 and gsignal stacks.
// It is ~0 on other goroutine stacks, to trigger a call to morestackc (and crash).
stack stack // offset known to runtime/cgo
stackguard0 uintptr // offset known to liblink
stackguard1 uintptr // offset known to liblink
_panic uintptr // innermost panic - offset known to liblink
_defer uintptr // innermost defer
m uintptr // current m; offset known to arm liblink
sched gobuf
syscallsp uintptr // if status==Gsyscall, syscallsp = sched.sp to use during gc
syscallpc uintptr // if status==Gsyscall, syscallpc = sched.pc to use during gc
stktopsp uintptr // expected sp at top of stack, to check in traceback
// param is a generic pointer parameter field used to pass
// values in particular contexts where other storage for the
// parameter would be difficult to find. It is currently used
// in three ways:
// 1. When a channel operation wakes up a blocked goroutine, it sets param to
// point to the sudog of the completed blocking operation.
// 2. By gcAssistAlloc1 to signal back to its caller that the goroutine completed
// the GC cycle. It is unsafe to do so in any other way, because the goroutine's
// stack may have moved in the meantime.
// 3. By debugCallWrap to pass parameters to a new goroutine because allocating a
// closure in the runtime is forbidden.
param unsafe.Pointer
atomicstatus uint32
stackLock uint32 // sigprof/scang lock; TODO: fold in to atomicstatus
goid int64
schedlink uintptr
waitsince int64 // approx time when the g become blocked
waitreason uint8 // if status==Gwaiting
preempt bool // preemption signal, duplicates stackguard0 = stackpreempt
preemptStop bool // transition to _Gpreempted on preemption; otherwise, just deschedule
preemptShrink bool // shrink stack at synchronous safe point
// asyncSafePoint is set if g is stopped at an asynchronous
// safe point. This means there are frames on the stack
// without precise pointer information.
asyncSafePoint bool
paniconfault bool // panic (instead of crash) on unexpected fault address
gcscandone bool // g has scanned stack; protected by _Gscan bit in status
throwsplit bool // must not split stack
// activeStackChans indicates that there are unlocked channels
// pointing into this goroutine's stack. If true, stack
// copying needs to acquire channel locks to protect these
// areas of the stack.
activeStackChans bool
// parkingOnChan indicates that the goroutine is about to
// park on a chansend or chanrecv. Used to signal an unsafe point
// for stack shrinking. It's a boolean value, but is updated atomically.
parkingOnChan uint8
raceignore int8 // ignore race detection events
sysblocktraced bool // StartTrace has emitted EvGoInSyscall about this goroutine
tracking bool // whether we're tracking this G for sched latency statistics
trackingSeq uint8 // used to decide whether to track this G
runnableStamp int64 // timestamp of when the G last became runnable, only used when tracking
runnableTime int64 // the amount of time spent runnable, cleared when running, only used when tracking
sysexitticks int64 // cputicks when syscall has returned (for tracing)
traceseq uint64 // trace event sequencer
tracelastp uintptr // last P emitted an event for this goroutine
lockedm uintptr
sig uint32
writebuf []byte
sigcode0 uintptr
sigcode1 uintptr
sigpc uintptr
gopc uintptr // pc of go statement that created this goroutine
ancestors uintptr // ancestor information goroutine(s) that created this goroutine (only used if debug.tracebackancestors)
startpc uintptr // pc of goroutine function
racectx uintptr
waiting uintptr // sudog structures this g is waiting on (that have a valid elem ptr); in lock order
cgoCtxt []uintptr // cgo traceback context
labels unsafe.Pointer // profiler labels
}
//go:linkname forEachGRace runtime.forEachGRace
func forEachGRace(fn func(gp *g))
//go:linkname runtime_getProfLabel runtime/pprof.runtime_getProfLabel
func runtime_getProfLabel() unsafe.Pointer
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment