aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Aliaksandr Valialkin <valyala@gmail.com> 2017-02-10 15:45:14 +0200
committerGravatar Aliaksandr Valialkin <valyala@gmail.com> 2017-02-10 15:45:14 +0200
commit32c72cde80f0c591604f825586d6a4bbbb39d9c5 (patch)
tree2fd80906166fb4b6ff21233fb7e07df7f24532db
parentoptimization: substitute time.Now() calls with coarse-grained time in hot paths (diff)
downloadfasthttp-32c72cde80f0c591604f825586d6a4bbbb39d9c5.tar.gz
fasthttp-32c72cde80f0c591604f825586d6a4bbbb39d9c5.tar.bz2
fasthttp-32c72cde80f0c591604f825586d6a4bbbb39d9c5.zip
Export CoarseTimeNow and clarify that RequestCtx.Time() and RequestCtx.ConnTime() return time truncated to a second
-rw-r--r--client.go14
-rw-r--r--coarseTime.go9
-rw-r--r--coarseTime_test.go2
-rw-r--r--server.go21
-rw-r--r--workerpool.go2
5 files changed, 28 insertions, 20 deletions
diff --git a/client.go b/client.go
index 5c25f55..3f49e9e 100644
--- a/client.go
+++ b/client.go
@@ -1041,7 +1041,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error)
panic("BUG: resp cannot be nil")
}
- atomic.StoreUint32(&c.lastUseTime, uint32(coarseTimeNow().Unix()-startTimeUnix))
+ atomic.StoreUint32(&c.lastUseTime, uint32(CoarseTimeNow().Unix()-startTimeUnix))
// Free up resources occupied by response before sending the request,
// so the GC may reclaim these resources (e.g. response body).
@@ -1057,7 +1057,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error)
// Optimization: update write deadline only if more than 25%
// of the last write deadline exceeded.
// See https://github.com/golang/go/issues/15133 for details.
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
if currentTime.Sub(cc.lastWriteDeadlineTime) > (c.WriteTimeout >> 2) {
if err = conn.SetWriteDeadline(currentTime.Add(c.WriteTimeout)); err != nil {
c.closeConn(cc)
@@ -1101,7 +1101,7 @@ func (c *HostClient) doNonNilReqResp(req *Request, resp *Response) (bool, error)
// Optimization: update read deadline only if more than 25%
// of the last read deadline exceeded.
// See https://github.com/golang/go/issues/15133 for details.
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
if currentTime.Sub(cc.lastReadDeadlineTime) > (c.ReadTimeout >> 2) {
if err = conn.SetReadDeadline(currentTime.Add(c.ReadTimeout)); err != nil {
c.closeConn(cc)
@@ -1276,7 +1276,7 @@ func acquireClientConn(conn net.Conn) *clientConn {
}
cc := v.(*clientConn)
cc.c = conn
- cc.createdTime = coarseTimeNow()
+ cc.createdTime = CoarseTimeNow()
return cc
}
@@ -1288,7 +1288,7 @@ func releaseClientConn(cc *clientConn) {
var clientConnPool sync.Pool
func (c *HostClient) releaseConn(cc *clientConn) {
- cc.lastUseTime = coarseTimeNow()
+ cc.lastUseTime = CoarseTimeNow()
c.connsLock.Lock()
c.conns = append(c.conns, cc)
c.connsLock.Unlock()
@@ -1988,7 +1988,7 @@ func (c *pipelineConnClient) writer(conn net.Conn, stopCh <-chan struct{}) error
// Optimization: update write deadline only if more than 25%
// of the last write deadline exceeded.
// See https://github.com/golang/go/issues/15133 for details.
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
if currentTime.Sub(lastWriteDeadlineTime) > (writeTimeout >> 2) {
if err = conn.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil {
w.err = err
@@ -2069,7 +2069,7 @@ func (c *pipelineConnClient) reader(conn net.Conn, stopCh <-chan struct{}) error
// Optimization: update read deadline only if more than 25%
// of the last read deadline exceeded.
// See https://github.com/golang/go/issues/15133 for details.
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
if currentTime.Sub(lastReadDeadlineTime) > (readTimeout >> 2) {
if err = conn.SetReadDeadline(currentTime.Add(readTimeout)); err != nil {
w.err = err
diff --git a/coarseTime.go b/coarseTime.go
index cb3f598..03c14f3 100644
--- a/coarseTime.go
+++ b/coarseTime.go
@@ -5,18 +5,21 @@ import (
"time"
)
-func coarseTimeNow() time.Time {
+// CoarseTimeNow returns the current time truncated to the nearest second.
+//
+// This is a faster alternative to time.Now().
+func CoarseTimeNow() time.Time {
tp := coarseTime.Load().(*time.Time)
return *tp
}
func init() {
- t := time.Now()
+ t := time.Now().Truncate(time.Second)
coarseTime.Store(&t)
go func() {
for {
time.Sleep(time.Second)
- t := time.Now()
+ t := time.Now().Truncate(time.Second)
coarseTime.Store(&t)
}
}()
diff --git a/coarseTime_test.go b/coarseTime_test.go
index 15715c5..b2f2334 100644
--- a/coarseTime_test.go
+++ b/coarseTime_test.go
@@ -10,7 +10,7 @@ func BenchmarkCoarseTimeNow(b *testing.B) {
var zeroTimeCount uint64
b.RunParallel(func(pb *testing.PB) {
for pb.Next() {
- t := coarseTimeNow()
+ t := CoarseTimeNow()
if t.IsZero() {
atomic.AddUint64(&zeroTimeCount, 1)
}
diff --git a/server.go b/server.go
index e893cc3..edf646d 100644
--- a/server.go
+++ b/server.go
@@ -592,13 +592,18 @@ func (ctx *RequestCtx) ConnID() uint64 {
return ctx.connID
}
-// Time returns RequestHandler call time.
+// Time returns RequestHandler call time truncated to the nearest second.
+//
+// Call time.Now() at the beginning of RequestHandler in order to obtain
+// percise RequestHandler call time.
func (ctx *RequestCtx) Time() time.Time {
return ctx.time
}
// ConnTime returns the time server starts serving the connection
// the current request came from.
+//
+// The returned time is truncated to the nearest second.
func (ctx *RequestCtx) ConnTime() time.Time {
return ctx.connTime
}
@@ -1280,7 +1285,7 @@ func (s *Server) Serve(ln net.Listener) error {
if time.Since(lastOverflowErrorTime) > time.Minute {
s.logger().Printf("The incoming connection cannot be served, because %d concurrent connections are served. "+
"Try increasing Server.Concurrency", maxWorkersCount)
- lastOverflowErrorTime = coarseTimeNow()
+ lastOverflowErrorTime = CoarseTimeNow()
}
// The current server reached concurrency limit,
@@ -1322,7 +1327,7 @@ func acceptConn(s *Server, ln net.Listener, lastPerIPErrorTime *time.Time) (net.
if time.Since(*lastPerIPErrorTime) > time.Minute {
s.logger().Printf("The number of connections from %s exceeds MaxConnsPerIP=%d",
getConnIP4(c), s.MaxConnsPerIP)
- *lastPerIPErrorTime = coarseTimeNow()
+ *lastPerIPErrorTime = CoarseTimeNow()
}
continue
}
@@ -1437,7 +1442,7 @@ func (s *Server) serveConn(c net.Conn) error {
serverName := s.getServerName()
connRequestNum := uint64(0)
connID := nextConnID()
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
connTime := currentTime
maxRequestBodySize := s.MaxRequestBodySize
if maxRequestBodySize <= 0 {
@@ -1494,7 +1499,7 @@ func (s *Server) serveConn(c net.Conn) error {
}
}
- currentTime = coarseTimeNow()
+ currentTime = CoarseTimeNow()
ctx.lastReadDuration = currentTime.Sub(ctx.time)
if err != nil {
@@ -1635,7 +1640,7 @@ func (s *Server) serveConn(c net.Conn) error {
break
}
- currentTime = coarseTimeNow()
+ currentTime = CoarseTimeNow()
}
if br != nil {
@@ -1691,7 +1696,7 @@ func (s *Server) updateWriteDeadline(c net.Conn, ctx *RequestCtx, lastDeadlineTi
// Optimization: update write deadline only if more than 25%
// of the last write deadline exceeded.
// See https://github.com/golang/go/issues/15133 for details.
- currentTime := coarseTimeNow()
+ currentTime := CoarseTimeNow()
if currentTime.Sub(lastDeadlineTime) > (writeTimeout >> 2) {
if err := c.SetWriteDeadline(currentTime.Add(writeTimeout)); err != nil {
panic(fmt.Sprintf("BUG: error in SetWriteDeadline(%s): %s", writeTimeout, err))
@@ -1874,7 +1879,7 @@ func (ctx *RequestCtx) Init2(conn net.Conn, logger Logger, reduceMemoryUsage boo
ctx.connID = nextConnID()
ctx.s = fakeServer
ctx.connRequestNum = 0
- ctx.connTime = coarseTimeNow()
+ ctx.connTime = CoarseTimeNow()
ctx.time = ctx.connTime
keepBodyBuffer := !reduceMemoryUsage
diff --git a/workerpool.go b/workerpool.go
index 1faee33..cf602e0 100644
--- a/workerpool.go
+++ b/workerpool.go
@@ -187,7 +187,7 @@ func (wp *workerPool) getCh() *workerChan {
}
func (wp *workerPool) release(ch *workerChan) bool {
- ch.lastUseTime = coarseTimeNow()
+ ch.lastUseTime = CoarseTimeNow()
wp.lock.Lock()
if wp.mustStop {
wp.lock.Unlock()