-
Notifications
You must be signed in to change notification settings - Fork 17.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
proposal: runtime/metrics: provide histogram of goroutines' on-CPU time #63341
Comments
CC @golang/runtime |
That proposal includes |
This would indeed be interesting. But, histograms have a downside: values are only added to the bucket count when the event has passed. In this case, the duration for which a specific goroutine was RUNNING can only be determined after it has transitioned to another state. On the edge, it's possible that goroutines rarely (or ever) transition to other states. It is also possible that the scheduler itself is having hiccups,
As @rhysh highlights, the instantaneous count of RUNNING/RUNNABLE/... goroutines would be interesting from a debugging point of view, but (I suspect) less useful from a runtime tuning/controller perspective than having a sum of the time spent in each state. In general cumulative values are better for this, as one create ones own deltas based on some polling period, and not lose data. A general strategy to make something cumulative is to add a time component, which naturally leads to something like
Does this make sense? What do others think? Should this go in a separate proposal? Implementation wise, this would be either a single atomic value (incremented when goroutines switch state), to which the current time-spent-in-RUNNABLE for all RUNNABLE goroutines is added at collection time. Alternatively, a per-thread counter that can be updated without atomics, and is summed when read. I would prefer the latter, so as to not introduce more possible contention points in the runtime. Metric reads are far less frequent than writes, and could take the hit. References:
|
The
/sched/latencies:seconds
metric is a sampled view into how long goroutines need to wait after becoming runnable before they receive on-CPU time. I propose adding another metric, tentatively named/sched/running:seconds
, showing how long goroutines spend in the running state before either cooperatively yielding or being successfully preempted. It would be sampled at the same rate (an undocumented 1 in 8) as the "latencies" metric.On the short end: Scheduling a goroutine onto a thread consumes resources, and applications that do very little of their own work each time aren't able to amortize that overhead very well. Putting that information in the same context as the metric for scheduling latency will help paint a more complete picture of the application's use of the scheduler (though of course not as complete as the
runtime/trace
package provides). It will allow easier comparison against general recommendations for sizing the units of work in concurrent programs (such as "split tasks into about 100µs") in a way that's accessible both at runtime and to test code.On the long end: Goroutines that stay in the running state for more than 2 scheduler quanta (20ms), when async preemption is enabled, indicate that part of the app (or its use of the runtime) operates with preemption disabled for too long. This can make it easier to notice and track down problems like #31222 where a long non-preemptible unit of work ends up delaying the entire app by delaying one of the GC's stop-the-worlds. (The
/gc/pauses:seconds
metric shows the non-preemptible regions, but only when they coincide with a GC phase transition. On top of that, maybe we should have a finer-grained measure of how long preemption remains disabled; 20ms is a very long time already.) It can also indicate when the Go scheduler assigned a goroutine to a software thread, but the OS didn't schedule that software thread onto a hardware thread.Throughout: Being able to calculate a continuously-updating (sampled) sum of on-CPU time allows comparisons against other perspectives such as
RUSAGE_SELF
orCLOCK_PROCESS_CPUTIME_ID
. This lets the application notice that it's exceeding the OS-provided resources.Existing:
Proposed addition:
The text was updated successfully, but these errors were encountered: