]> Cypherpunks repositories - gostls13.git/commitdiff
time: optimize Sub
authorMichael Darakananda <pongad@gmail.com>
Fri, 24 Aug 2018 07:27:35 +0000 (00:27 -0700)
committerIan Lance Taylor <iant@golang.org>
Tue, 19 Mar 2019 04:10:33 +0000 (04:10 +0000)
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>
src/time/time.go
src/time/time_test.go

index aacde0db2c39b17af623051d02a1c8af3226f38d..d9938861ac636326c8d413115763d8cd08aa70e6 100644 (file)
@@ -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.
index 0ac3c3a27fae338c61476ee7cd7c043efc039b70..dd3a8160cd86d7c706d9ad5d462c0db210c08f4c 100644 (file)
@@ -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