How long does a goroutine could run successively before being preempted? 10ms or 20ms?

256 views
Skip to first unread message

Hans Allen

unread,
Feb 28, 2022, 8:10:06 AM2/28/22
to golang-nuts

Since go1.14,  cpu busy goroutine will not occupy a P indefinitely any more. This is done by a cool feature: asynchronously preemption.
There is one extra NoP thread(sysmon) runs time to time.  It checks if current goroutine has run 10+ms. If so,  signal the M runs this goroutine to switch to another goroutine.  The function calling graph looks like this:
sysmon() {
    for {
          usleep(delay)
          retake() {
                 if  schedwhen + 10ms <= now {
                       preemptone()
                 }
          }
    }
}
schedwhen is the time when the goroutine was scheduled to use cpu.  So I conclude that Go prevents  goroutine from running more than 10ms.  However,  My local cpu-bound test shows almost all goroutine run 10+ms successively. It seems avg 20ms. See attachments for test code and trace.

The reason is usleep(delay). Preemption checking happens every 10ms. this is a less frequent sampling rate. To achieve 10ms time slice, the checking should happens less than every 5ms.  For example, background forcegc goroutine  does check gcTrigger every forcegcperiod/2 to guarantee that GC happens at least once every forcegcperiod.

How long a goroutine could run by design?
If its 10ms,  sysmon should sleep less than 5ms.
If its 20ms,  forecePreemptNs should be doubled.

trace.out
preempt_test.go
Message has been deleted

Hans Allen

unread,
Mar 2, 2022, 10:46:20 AM3/2/22
to golang-nuts

It seems 10ms.

Introduced originally in go1.2

Hans Allen

unread,
Mar 3, 2022, 8:49:17 AM3/3/22
to golang-nuts
Just for curiosity, why 10ms?

Author told a answer.
Reply all
Reply to author
Forward
0 new messages