aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorMichael Darakananda <pongad@gmail.com>2018-08-24 00:27:35 -0700
committerIan Lance Taylor <iant@golang.org>2019-03-19 04:10:33 +0000
commit6f7bb2cab6c9ac6b6ec530a87ffc854d19335a15 (patch)
treee4ed83c7ec05871cc8f1711865a165c905836c9f /src
parent66b264d2c1119ffefd7cd99def02b9f533651678 (diff)
downloadgo-6f7bb2cab6c9ac6b6ec530a87ffc854d19335a15.tar.xz
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: Ian Lance Taylor <iant@golang.org>
Diffstat (limited to 'src')
-rw-r--r--src/time/time.go33
-rw-r--r--src/time/time_test.go10
2 files changed, 34 insertions, 9 deletions
diff --git a/src/time/time.go b/src/time/time.go
index aacde0db2c..d9938861ac 100644
--- a/src/time/time.go
+++ b/src/time/time.go
@@ -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.
diff --git a/src/time/time_test.go b/src/time/time_test.go
index 0ac3c3a27f..dd3a8160cd 100644
--- a/src/time/time_test.go
+++ b/src/time/time_test.go
@@ -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