@@ -2681,85 +2681,40 @@ top:
2681
2681
}
2682
2682
}
2683
2683
2684
- // Steal work from other P's.
2684
+ // Spinning Ms: steal work from other Ps.
2685
+ //
2686
+ // Limit the number of spinning Ms to half the number of busy Ps.
2687
+ // This is necessary to prevent excessive CPU consumption when
2688
+ // GOMAXPROCS>>1 but the program parallelism is low.
2685
2689
procs := uint32 (gomaxprocs )
2686
- ranTimer := false
2687
- // If number of spinning M's >= number of busy P's, block.
2688
- // This is necessary to prevent excessive CPU consumption
2689
- // when GOMAXPROCS>>1 but the program parallelism is low.
2690
- if ! _g_ .m .spinning && 2 * atomic .Load (& sched .nmspinning ) >= procs - atomic .Load (& sched .npidle ) {
2691
- goto stop
2692
- }
2693
- if ! _g_ .m .spinning {
2694
- _g_ .m .spinning = true
2695
- atomic .Xadd (& sched .nmspinning , 1 )
2696
- }
2697
- const stealTries = 4
2698
- for i := 0 ; i < stealTries ; i ++ {
2699
- stealTimersOrRunNextG := i == stealTries - 1
2700
-
2701
- for enum := stealOrder .start (fastrand ()); ! enum .done (); enum .next () {
2702
- if sched .gcwaiting != 0 {
2703
- goto top
2704
- }
2705
- p2 := allp [enum .position ()]
2706
- if _p_ == p2 {
2707
- continue
2708
- }
2709
-
2710
- // Steal timers from p2. This call to checkTimers is the only place
2711
- // where we might hold a lock on a different P's timers. We do this
2712
- // once on the last pass before checking runnext because stealing
2713
- // from the other P's runnext should be the last resort, so if there
2714
- // are timers to steal do that first.
2715
- //
2716
- // We only check timers on one of the stealing iterations because
2717
- // the time stored in now doesn't change in this loop and checking
2718
- // the timers for each P more than once with the same value of now
2719
- // is probably a waste of time.
2720
- //
2721
- // timerpMask tells us whether the P may have timers at all. If it
2722
- // can't, no need to check at all.
2723
- if stealTimersOrRunNextG && timerpMask .read (enum .position ()) {
2724
- tnow , w , ran := checkTimers (p2 , now )
2725
- now = tnow
2726
- if w != 0 && (pollUntil == 0 || w < pollUntil ) {
2727
- pollUntil = w
2728
- }
2729
- if ran {
2730
- // Running the timers may have
2731
- // made an arbitrary number of G's
2732
- // ready and added them to this P's
2733
- // local run queue. That invalidates
2734
- // the assumption of runqsteal
2735
- // that is always has room to add
2736
- // stolen G's. So check now if there
2737
- // is a local G to run.
2738
- if gp , inheritTime := runqget (_p_ ); gp != nil {
2739
- return gp , inheritTime
2740
- }
2741
- ranTimer = true
2742
- }
2743
- }
2690
+ if _g_ .m .spinning || 2 * atomic .Load (& sched .nmspinning ) < procs - atomic .Load (& sched .npidle ) {
2691
+ if ! _g_ .m .spinning {
2692
+ _g_ .m .spinning = true
2693
+ atomic .Xadd (& sched .nmspinning , 1 )
2694
+ }
2744
2695
2745
- // Don't bother to attempt to steal if p2 is idle.
2746
- if ! idlepMask .read (enum .position ()) {
2747
- if gp := runqsteal (_p_ , p2 , stealTimersOrRunNextG ); gp != nil {
2748
- return gp , false
2749
- }
2750
- }
2696
+ gp , inheritTime , tnow , w , newWork := stealWork (now )
2697
+ now = tnow
2698
+ if gp != nil {
2699
+ // Successfully stole.
2700
+ return gp , inheritTime
2701
+ }
2702
+ if newWork {
2703
+ // There may be new timer or GC work; restart to
2704
+ // discover.
2705
+ goto top
2706
+ }
2707
+ if w != 0 && (pollUntil == 0 || w < pollUntil ) {
2708
+ // Earlier timer to wait for.
2709
+ pollUntil = w
2751
2710
}
2752
2711
}
2753
- if ranTimer {
2754
- // Running a timer may have made some goroutine ready.
2755
- goto top
2756
- }
2757
-
2758
- stop:
2759
2712
2760
- // We have nothing to do. If we're in the GC mark phase, can
2761
- // safely scan and blacken objects, and have work to do, run
2762
- // idle-time marking rather than give up the P.
2713
+ // We have nothing to do.
2714
+ //
2715
+ // If we're in the GC mark phase, can safely scan and blacken objects,
2716
+ // and have work to do, run idle-time marking rather than give up the
2717
+ // P.
2763
2718
if gcBlackenEnabled != 0 && gcMarkWorkAvailable (_p_ ) {
2764
2719
node := (* gcBgMarkWorkerNode )(gcBgMarkWorkerPool .pop ())
2765
2720
if node != nil {
@@ -3008,6 +2963,81 @@ func pollWork() bool {
3008
2963
return false
3009
2964
}
3010
2965
2966
+ // stealWork attempts to steal a runnable goroutine or timer from any P.
2967
+ //
2968
+ // If newWork is true, new work may have been readied.
2969
+ //
2970
+ // If now is not 0 it is the current time. stealWork returns the passed time or
2971
+ // the current time if now was passed as 0.
2972
+ func stealWork (now int64 ) (gp * g , inheritTime bool , rnow , pollUntil int64 , newWork bool ) {
2973
+ pp := getg ().m .p .ptr ()
2974
+
2975
+ ranTimer := false
2976
+
2977
+ const stealTries = 4
2978
+ for i := 0 ; i < stealTries ; i ++ {
2979
+ stealTimersOrRunNextG := i == stealTries - 1
2980
+
2981
+ for enum := stealOrder .start (fastrand ()); ! enum .done (); enum .next () {
2982
+ if sched .gcwaiting != 0 {
2983
+ // GC work may be available.
2984
+ return nil , false , now , pollUntil , true
2985
+ }
2986
+ p2 := allp [enum .position ()]
2987
+ if pp == p2 {
2988
+ continue
2989
+ }
2990
+
2991
+ // Steal timers from p2. This call to checkTimers is the only place
2992
+ // where we might hold a lock on a different P's timers. We do this
2993
+ // once on the last pass before checking runnext because stealing
2994
+ // from the other P's runnext should be the last resort, so if there
2995
+ // are timers to steal do that first.
2996
+ //
2997
+ // We only check timers on one of the stealing iterations because
2998
+ // the time stored in now doesn't change in this loop and checking
2999
+ // the timers for each P more than once with the same value of now
3000
+ // is probably a waste of time.
3001
+ //
3002
+ // timerpMask tells us whether the P may have timers at all. If it
3003
+ // can't, no need to check at all.
3004
+ if stealTimersOrRunNextG && timerpMask .read (enum .position ()) {
3005
+ tnow , w , ran := checkTimers (p2 , now )
3006
+ now = tnow
3007
+ if w != 0 && (pollUntil == 0 || w < pollUntil ) {
3008
+ pollUntil = w
3009
+ }
3010
+ if ran {
3011
+ // Running the timers may have
3012
+ // made an arbitrary number of G's
3013
+ // ready and added them to this P's
3014
+ // local run queue. That invalidates
3015
+ // the assumption of runqsteal
3016
+ // that it always has room to add
3017
+ // stolen G's. So check now if there
3018
+ // is a local G to run.
3019
+ if gp , inheritTime := runqget (pp ); gp != nil {
3020
+ return gp , inheritTime , now , pollUntil , ranTimer
3021
+ }
3022
+ ranTimer = true
3023
+ }
3024
+ }
3025
+
3026
+ // Don't bother to attempt to steal if p2 is idle.
3027
+ if ! idlepMask .read (enum .position ()) {
3028
+ if gp := runqsteal (pp , p2 , stealTimersOrRunNextG ); gp != nil {
3029
+ return gp , false , now , pollUntil , ranTimer
3030
+ }
3031
+ }
3032
+ }
3033
+ }
3034
+
3035
+ // No goroutines found to steal. Regardless, running a timer may have
3036
+ // made some goroutine ready that we missed. Indicate the next timer to
3037
+ // wait for.
3038
+ return nil , false , now , pollUntil , ranTimer
3039
+ }
3040
+
3011
3041
// wakeNetPoller wakes up the thread sleeping in the network poller if it isn't
3012
3042
// going to wake up before the when argument; or it wakes an idle P to service
3013
3043
// timers and the network poller if there isn't one already.
@@ -3252,7 +3282,7 @@ func dropg() {
3252
3282
3253
3283
// checkTimers runs any timers for the P that are ready.
3254
3284
// If now is not 0 it is the current time.
3255
- // It returns the current time or 0 if it is not known,
3285
+ // It returns the passed time or the current time if now was passed as 0.
3256
3286
// and the time when the next timer should run or 0 if there is no next timer,
3257
3287
// and reports whether it ran any timers.
3258
3288
// If the time when the next timer should run is not 0,
0 commit comments