forked from domodwyer/mgo
-
Notifications
You must be signed in to change notification settings - Fork 230
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
socket: amortise cost of querying OS time counter (#149)
#116 adds a much needed ability to shrink the connection pool, but requires tracking the last-used timestamp for each socket after every operation. Frequent calls to time.Now() in the hot-path reduced read throughput by ~6% and increased the latency (and variance) of socket operations as a whole. This PR adds a periodically updated time value to amortise the cost of the last- used bookkeeping, restoring the original throughput at the cost of approximate last-used values (configured to be ~25ms of potential skew). On some systems (currently including FreeBSD) querying the time counter also requires a syscall/context switch. Fixes #142.
- Loading branch information
Showing
3 changed files
with
98 additions
and
1 deletion.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package mgo | ||
|
||
import ( | ||
"sync" | ||
"sync/atomic" | ||
"time" | ||
) | ||
|
||
// coarseTimeProvider provides a periodically updated (approximate) time value to | ||
// amortise the cost of frequent calls to time.Now. | ||
// | ||
// A read throughput increase of ~6% was measured when using coarseTimeProvider with the | ||
// high-precision event timer (HPET) on FreeBSD 11.1 and Go 1.10.1 after merging | ||
// #116. | ||
// | ||
// Calling Now returns a time.Time that is updated at the configured interval, | ||
// however due to scheduling the value may be marginally older than expected. | ||
// | ||
// coarseTimeProvider is safe for concurrent use. | ||
type coarseTimeProvider struct { | ||
once sync.Once | ||
stop chan struct{} | ||
last atomic.Value | ||
} | ||
|
||
// Now returns the most recently acquired time.Time value. | ||
func (t *coarseTimeProvider) Now() time.Time { | ||
return t.last.Load().(time.Time) | ||
} | ||
|
||
// Close stops the periodic update of t. | ||
// | ||
// Any subsequent calls to Now will return the same value forever. | ||
func (t *coarseTimeProvider) Close() { | ||
t.once.Do(func() { | ||
close(t.stop) | ||
}) | ||
} | ||
|
||
// newcoarseTimeProvider returns a coarseTimeProvider configured to update at granularity. | ||
func newcoarseTimeProvider(granularity time.Duration) *coarseTimeProvider { | ||
t := &coarseTimeProvider{ | ||
stop: make(chan struct{}), | ||
} | ||
|
||
t.last.Store(time.Now()) | ||
|
||
go func() { | ||
ticker := time.NewTicker(granularity) | ||
for { | ||
select { | ||
case <-t.stop: | ||
ticker.Stop() | ||
return | ||
case <-ticker.C: | ||
t.last.Store(time.Now()) | ||
} | ||
} | ||
}() | ||
|
||
return t | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
package mgo | ||
|
||
import ( | ||
"testing" | ||
"time" | ||
) | ||
|
||
func TestCoarseTimeProvider(t *testing.T) { | ||
t.Parallel() | ||
|
||
const granularity = 50 * time.Millisecond | ||
|
||
ct := newcoarseTimeProvider(granularity) | ||
defer ct.Close() | ||
|
||
start := ct.Now().Unix() | ||
time.Sleep(time.Second) | ||
|
||
got := ct.Now().Unix() | ||
if got <= start { | ||
t.Fatalf("got %d, expected at least %d", got, start) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters