Commit 6f7bb2ca authored by Michael Darakananda's avatar Michael Darakananda Committed by Ian Lance Taylor

time: optimize Sub

This is primarily achieved by checking for arithmetic overflow
instead of using Add and Equal.

It's a decent performance improvement even though
the function still isn't inlined.

name   old time/op  new time/op  delta
Sub-6   242ns ± 0%   122ns ± 0%  -49.59%  (p=0.002 n=8+10)

Updates #17858.

Change-Id: I1469b618183c83ea8ea54d5ce277eb15f2ec0f11
Reviewed-on: https://go-review.googlesource.com/c/go/+/131196
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: default avatarIan Lance Taylor <iant@golang.org>
parent 66b264d2
......@@ -906,16 +906,33 @@ func (t Time) Sub(u Time) Duration {
}
return d
}
d := Duration(t.sec()-u.sec())*Second + Duration(t.nsec()-u.nsec())
// Check for overflow or underflow.
switch {
case u.Add(d).Equal(t):
return d // d is correct
case t.Before(u):
ts, us := t.sec(), u.sec()
var sec, nsec, d int64
ssub := ts - us
if (ssub < ts) != (us > 0) {
goto overflow
}
if ssub < int64(minDuration/Second) || ssub > int64(maxDuration/Second) {
goto overflow
}
sec = ssub * int64(Second)
nsec = int64(t.nsec() - u.nsec())
d = sec + nsec
if (d > sec) != (nsec > 0) {
goto overflow
}
return Duration(d)
overflow:
if t.Before(u) {
return minDuration // t - u is negative out of range
default:
return maxDuration // t - u is positive out of range
}
return maxDuration // t - u is positive out of range
}
// Since returns the time elapsed since t.
......
......@@ -690,7 +690,7 @@ var gobTests = []Time{
Date(0, 1, 2, 3, 4, 5, 6, UTC),
Date(7, 8, 9, 10, 11, 12, 13, FixedZone("", 0)),
Unix(81985467080890095, 0x76543210), // Time.sec: 0x0123456789ABCDEF
{}, // nil location
{}, // nil location
Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", 32767*60)),
Date(1, 2, 3, 4, 5, 6, 7, FixedZone("", -32768*60)),
}
......@@ -1008,6 +1008,14 @@ func TestSub(t *testing.T) {
}
}
func BenchmarkSub(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, st := range subTests {
st.t.Sub(st.u)
}
}
}
var nsDurationTests = []struct {
d Duration
want int64
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment