@@ -590,7 +590,7 @@ func saveblockevent(cycles, rate int64, skip int, which bucketType) {
590
590
// mutex.
591
591
//
592
592
// Having found the head and tail nodes and a correct waiters count, the
593
- // unlocking M can read and update those two nodes' acquireTicks field and thus
593
+ // unlocking M can read and update those two nodes' acquireTimes fields and thus
594
594
// take responsibility for (an estimate of) the entire list's delay since the
595
595
// last unlock call.
596
596
//
@@ -603,16 +603,21 @@ func saveblockevent(cycles, rate int64, skip int, which bucketType) {
603
603
// runtime controls the order of thread wakeups (it's a LIFO stack), but with
604
604
// lock_futex.go the OS can wake an arbitrary thread.
605
605
type mWaitList struct {
606
- acquireTicks int64 // start of current wait (set by us, updated by others during unlock)
606
+ acquireTimes timePair // start of current wait (set by us, updated by others during unlock)
607
607
next muintptr // next m waiting for lock (set by us, cleared by another during unlock)
608
608
prev muintptr // previous m waiting for lock (an amortized hint, set by another during unlock)
609
609
tail muintptr // final m waiting for lock (an amortized hint, set by others during unlock)
610
610
waiters int32 // length of waiting m list (an amortized hint, set by another during unlock)
611
611
}
612
612
613
+ type timePair struct {
614
+ nanotime int64
615
+ cputicks int64
616
+ }
617
+
613
618
// clearLinks resets the fields related to the M's position in the list of Ms
614
- // waiting for a mutex. It leaves acquireTicks intact, since this M may still be
615
- // waiting and may have had its acquireTicks updated by an unlock2 call.
619
+ // waiting for a mutex. It leaves acquireTimes intact, since this M may still be
620
+ // waiting and may have had its acquireTimes updated by an unlock2 call.
616
621
//
617
622
// In lock_sema.go, the previous owner of the mutex dequeues an M and then wakes
618
623
// it; with semaphore-based sleep, it's important that each M receives only one
@@ -731,8 +736,8 @@ func removeMutexWaitList(head muintptr, mp *m) muintptr {
731
736
hp := head .ptr ()
732
737
tail := hp .mWaitList .tail
733
738
waiters := hp .mWaitList .waiters
734
- headTicks := hp .mWaitList .acquireTicks
735
- tailTicks := hp .mWaitList .tail .ptr ().mWaitList .acquireTicks
739
+ headTimes := hp .mWaitList .acquireTimes
740
+ tailTimes := hp .mWaitList .tail .ptr ().mWaitList .acquireTimes
736
741
737
742
mp .mWaitList .tail = 0
738
743
@@ -768,40 +773,42 @@ func removeMutexWaitList(head muintptr, mp *m) muintptr {
768
773
hp .mWaitList .prev = 0
769
774
hp .mWaitList .tail = tail
770
775
hp .mWaitList .waiters = waiters - 1
771
- hp .mWaitList .acquireTicks = headTicks
776
+ hp .mWaitList .acquireTimes = headTimes
772
777
}
773
778
if tp := tail .ptr (); tp != nil {
774
- tp .mWaitList .acquireTicks = tailTicks
779
+ tp .mWaitList .acquireTimes = tailTimes
775
780
}
776
781
return head
777
782
}
778
783
779
- // claimMutexWaitTime advances the acquireTicks of the list of waiting Ms at
784
+ // claimMutexWaitTime advances the acquireTimes of the list of waiting Ms at
780
785
// head to now, returning an estimate of the total wait time claimed by that
781
786
// action.
782
- func claimMutexWaitTime (nowTicks int64 , head muintptr ) int64 {
787
+ func claimMutexWaitTime (now timePair , head muintptr ) timePair {
783
788
fixMutexWaitList (head )
784
789
hp := head .ptr ()
785
790
if hp == nil {
786
- return 0
791
+ return timePair {}
787
792
}
788
793
tp := hp .mWaitList .tail .ptr ()
789
794
waiters := hp .mWaitList .waiters
790
- headTicks := hp .mWaitList .acquireTicks
791
- tailTicks := tp .mWaitList .acquireTicks
795
+ headTimes := hp .mWaitList .acquireTimes
796
+ tailTimes := tp .mWaitList .acquireTimes
792
797
793
- var cycles int64
794
- cycles = nowTicks - headTicks
798
+ var dt timePair
799
+ dt .nanotime = now .nanotime - headTimes .nanotime
800
+ dt .cputicks = now .cputicks - headTimes .cputicks
795
801
if waiters > 1 {
796
- cycles = int64 (waiters ) * (cycles + nowTicks - tailTicks ) / 2
802
+ dt .nanotime = int64 (waiters ) * (dt .nanotime + now .nanotime - tailTimes .nanotime ) / 2
803
+ dt .cputicks = int64 (waiters ) * (dt .cputicks + now .cputicks - tailTimes .cputicks ) / 2
797
804
}
798
805
799
806
// When removeMutexWaitList removes a head or tail node, it's responsible
800
807
// for applying these changes to the new head or tail.
801
- hp .mWaitList .acquireTicks = nowTicks
802
- tp .mWaitList .acquireTicks = nowTicks
808
+ hp .mWaitList .acquireTimes = now
809
+ tp .mWaitList .acquireTimes = now
803
810
804
- return cycles
811
+ return dt
805
812
}
806
813
807
814
// mLockProfile is part of the M struct to hold information relating to mutex
@@ -832,21 +839,26 @@ type mLockProfile struct {
832
839
// From unlock2, we might not be holding a p in this code.
833
840
//
834
841
//go:nowritebarrierrec
835
- func (prof * mLockProfile ) recordUnlock (cycles int64 ) {
836
- if cycles != 0 {
842
+ func (prof * mLockProfile ) recordUnlock (dt timePair ) {
843
+ if dt != ( timePair {}) {
837
844
// We could make a point of clearing out the local storage right before
838
845
// this, to have a slightly better chance of being able to see the call
839
846
// stack if the program has several (nested) contended locks. If apps
840
847
// are seeing a lot of _LostContendedRuntimeLock samples, maybe that'll
841
848
// be a worthwhile change.
842
- prof .proposeUnlock (cycles )
849
+ prof .proposeUnlock (dt )
843
850
}
844
851
if getg ().m .locks == 1 && prof .cycles != 0 {
845
852
prof .store ()
846
853
}
847
854
}
848
855
849
- func (prof * mLockProfile ) proposeUnlock (cycles int64 ) {
856
+ func (prof * mLockProfile ) proposeUnlock (dt timePair ) {
857
+ if nanos := dt .nanotime ; nanos > 0 {
858
+ prof .waitTime .Add (nanos )
859
+ }
860
+
861
+ cycles := dt .cputicks
850
862
if cycles <= 0 {
851
863
return
852
864
}
0 commit comments