Join GitHub today
GitHub is home to over 36 million developers working together to host and review code, manage projects, and build software together.Sign up
runtime: timerproc does not get to run under load #15706
go version devel +64770f6 Mon May 16 18:28:38 2016 +0000 linux/amd64
Also reproduced on the linux-arm64-buildlet builder (while tracking down an unrelated problem).
The test should finish in under a second.
The test runs until you kill it.
The test is actively running and spinning around the main test loop, but the time.After that's supposed to fire after 0.2 seconds and stop the test never fires. Digging into the runtime state, it looks like timeproc was started, but never actually gets scheduled (timers.created is true, but timers.gp is 0), so the timer never fires. Most likely it's being starved by something. Possibly the test is tricking the scheduler into switching the one available P back and forth between the test goroutine and the GC mark worker and never getting to the rest of the run queue. The scheduler state is below:
We need a test for this (frequent GCs effect of fairness). We've already been here: #7126.
Execution alternates between a single user gorotuine and GC goroutine (and even a goroutine from globrunq runs episodically), but other goroutines are started.
FWIW, the following fixes this particular test:
referenced this issue
May 17, 2016
My concern with adding inheritTime = true there is that I think it could lead to a scheduler loop: suppose a user goroutine has very nearly run out the quantum when it blocks; the scheduler picks a mark worker to run; the mark worker inherits the quantum, quickly runs out what's left of it, and returns to the scheduler; since the worker didn't run for very long, the scheduler picks it again, and it again inherits the quantum; since its quantum is up it gets preempted again after just 20us; and the scheduler goes into a loop picking and preempting the mark worker.
You're right, of course, that the high-priority scheduling of the GC worker is the crux of the problem. In effect, by triggering GC and blocking in an assist, user code can control which goroutine runs next and which goroutine runs after that, without inheriting the quantum across these executions.
Another possible solution is for the GC to always add goroutines to the end of the run queue (either a local run queue or the global run queue). Then user code can't exploit it to skip the run queue without consuming quantum.