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.

-- 
You received this message because you are subscribed to the Google Groups 
"golang-nuts" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to golang-nuts+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/golang-nuts/1c9d3998-173c-44fa-b69f-32650186d139n%40googlegroups.com.

Attachment: trace.out
Description: Binary data

Attachment: preempt_test.go
Description: Binary data

Reply via email to