@@ -396,23 +396,18 @@ type gcControllerState struct {
396
396
assistBytesPerWork float64
397
397
398
398
// fractionalUtilizationGoal is the fraction of wall clock
399
- // time that should be spent in the fractional mark worker.
400
- // For example, if the overall mark utilization goal is 25%
401
- // and GOMAXPROCS is 6, one P will be a dedicated mark worker
402
- // and this will be set to 0.5 so that 50% of the time some P
403
- // is in a fractional mark worker. This is computed at the
404
- // beginning of each cycle.
399
+ // time that should be spent in the fractional mark worker on
400
+ // each P that isn't running a dedicated worker.
401
+ //
402
+ // For example, if the utilization goal is 25% and there are
403
+ // no dedicated workers, this will be 0.25. If there goal is
404
+ // 25%, there is one dedicated worker, and GOMAXPROCS is 5,
405
+ // this will be 0.05 to make up the missing 5%.
406
+ //
407
+ // If this is zero, no fractional workers are needed.
405
408
fractionalUtilizationGoal float64
406
409
407
410
_ [sys .CacheLineSize ]byte
408
-
409
- // fractionalMarkWorkersNeeded is the number of fractional
410
- // mark workers that need to be started. This is either 0 or
411
- // 1. This is potentially updated atomically at every
412
- // scheduling point (hence it gets its own cache line).
413
- fractionalMarkWorkersNeeded int64
414
-
415
- _ [sys .CacheLineSize ]byte
416
411
}
417
412
418
413
// startCycle resets the GC controller's state and computes estimates
@@ -471,19 +466,15 @@ func (c *gcControllerState) startCycle() {
471
466
// Too many dedicated workers.
472
467
c .dedicatedMarkWorkersNeeded --
473
468
}
474
- c .fractionalUtilizationGoal = totalUtilizationGoal - float64 (c .dedicatedMarkWorkersNeeded )
469
+ c .fractionalUtilizationGoal = ( totalUtilizationGoal - float64 (c .dedicatedMarkWorkersNeeded )) / float64 ( gomaxprocs )
475
470
} else {
476
471
c .fractionalUtilizationGoal = 0
477
472
}
478
- if c .fractionalUtilizationGoal > 0 {
479
- c .fractionalMarkWorkersNeeded = 1
480
- } else {
481
- c .fractionalMarkWorkersNeeded = 0
482
- }
483
473
484
474
// Clear per-P state
485
475
for _ , p := range allp {
486
476
p .gcAssistTime = 0
477
+ p .gcFractionalMarkTime = 0
487
478
}
488
479
489
480
// Compute initial values for controls that are updated
@@ -496,7 +487,7 @@ func (c *gcControllerState) startCycle() {
496
487
work .initialHeapLive >> 20 , "->" ,
497
488
memstats .next_gc >> 20 , " MB)" ,
498
489
" workers=" , c .dedicatedMarkWorkersNeeded ,
499
- "+" , c .fractionalMarkWorkersNeeded , "\n " )
490
+ "+" , c .fractionalUtilizationGoal , "\n " )
500
491
}
501
492
}
502
493
@@ -702,31 +693,20 @@ func (c *gcControllerState) findRunnableGCWorker(_p_ *p) *g {
702
693
// This P is now dedicated to marking until the end of
703
694
// the concurrent mark phase.
704
695
_p_ .gcMarkWorkerMode = gcMarkWorkerDedicatedMode
696
+ } else if c .fractionalUtilizationGoal == 0 {
697
+ // No need for fractional workers.
698
+ return nil
705
699
} else {
706
- if ! decIfPositive (& c .fractionalMarkWorkersNeeded ) {
707
- // No more workers are need right now.
708
- return nil
709
- }
710
-
711
- // This P has picked the token for the fractional worker.
712
- // Is the GC currently under or at the utilization goal?
713
- // If so, do more work.
700
+ // Is this P behind on the fractional utilization
701
+ // goal?
714
702
//
715
703
// This should be kept in sync with pollFractionalWorkerExit.
716
-
717
- // TODO(austin): We could fast path this and basically
718
- // eliminate contention on c.fractionalMarkWorkersNeeded by
719
- // precomputing the minimum time at which it's worth
720
- // next scheduling the fractional worker. Then Ps
721
- // don't have to fight in the window where we've
722
- // passed that deadline and no one has started the
723
- // worker yet.
724
- delta := nanotime () - c .markStartTime
725
- if delta > 0 && float64 (c .fractionalMarkTime )/ float64 (delta ) > c .fractionalUtilizationGoal {
726
- // Nope, we'd overshoot the utilization goal
727
- atomic .Xaddint64 (& c .fractionalMarkWorkersNeeded , + 1 )
704
+ delta := nanotime () - gcController .markStartTime
705
+ if delta > 0 && float64 (_p_ .gcFractionalMarkTime )/ float64 (delta ) > c .fractionalUtilizationGoal {
706
+ // Nope. No need to run a fractional worker.
728
707
return nil
729
708
}
709
+ // Run a fractional worker.
730
710
_p_ .gcMarkWorkerMode = gcMarkWorkerFractionalMode
731
711
}
732
712
@@ -751,8 +731,7 @@ func pollFractionalWorkerExit() bool {
751
731
return true
752
732
}
753
733
p := getg ().m .p .ptr ()
754
- // Account for time since starting this worker.
755
- selfTime := gcController .fractionalMarkTime + (now - p .gcMarkWorkerStartTime )
734
+ selfTime := p .gcFractionalMarkTime + (now - p .gcMarkWorkerStartTime )
756
735
// Add some slack to the utilization goal so that the
757
736
// fractional worker isn't behind again the instant it exits.
758
737
return float64 (selfTime )/ float64 (delta ) > 1.2 * gcController .fractionalUtilizationGoal
@@ -1387,7 +1366,8 @@ top:
1387
1366
// TODO(austin): Should dedicated workers keep an eye on this
1388
1367
// and exit gcDrain promptly?
1389
1368
atomic .Xaddint64 (& gcController .dedicatedMarkWorkersNeeded , - 0xffffffff )
1390
- atomic .Xaddint64 (& gcController .fractionalMarkWorkersNeeded , - 0xffffffff )
1369
+ prevFractionalGoal := gcController .fractionalUtilizationGoal
1370
+ gcController .fractionalUtilizationGoal = 0
1391
1371
1392
1372
if ! gcBlackenPromptly {
1393
1373
// Transition from mark 1 to mark 2.
@@ -1430,7 +1410,7 @@ top:
1430
1410
1431
1411
// Now we can start up mark 2 workers.
1432
1412
atomic .Xaddint64 (& gcController .dedicatedMarkWorkersNeeded , 0xffffffff )
1433
- atomic . Xaddint64 ( & gcController .fractionalMarkWorkersNeeded , 0xffffffff )
1413
+ gcController .fractionalUtilizationGoal = prevFractionalGoal
1434
1414
1435
1415
incnwait := atomic .Xadd (& work .nwait , + 1 )
1436
1416
if incnwait == work .nproc && ! gcMarkWorkAvailable (nil ) {
@@ -1849,7 +1829,7 @@ func gcBgMarkWorker(_p_ *p) {
1849
1829
atomic .Xaddint64 (& gcController .dedicatedMarkWorkersNeeded , 1 )
1850
1830
case gcMarkWorkerFractionalMode :
1851
1831
atomic .Xaddint64 (& gcController .fractionalMarkTime , duration )
1852
- atomic .Xaddint64 (& gcController . fractionalMarkWorkersNeeded , 1 )
1832
+ atomic .Xaddint64 (& _p_ . gcFractionalMarkTime , duration )
1853
1833
case gcMarkWorkerIdleMode :
1854
1834
atomic .Xaddint64 (& gcController .idleMarkTime , duration )
1855
1835
}
0 commit comments