diff --git a/.circleci/config.yml b/.circleci/config.yml index d17c666..e260db5 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -1,17 +1,15 @@ alias: default: &default - working_directory: /go/src/github.com/kpango/fastime docker: - image: cimg/go:1.20.2 environment: - GOPATH: "/go" GO111MODULE: "on" REPO_NAME: "kpango" IMAGE_NAME: "fastime" GITHUB_API: "https://api.github.com/" DOCKER_USER: "kpango" setup_remote_docker: &setup_remote_docker - version: 18.06.0-ce + version: 20.10.18 docker_layer_caching: true version: 2 diff --git a/Makefile b/Makefile index 2f3b653..fc32c59 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,9 @@ GO_VERSION:=$(shell go version) .PHONY: all clean bench bench-all profile lint test contributors update install +GOPATH := $(eval GOPATH := $(shell go env GOPATH))$(GOPATH) +GOLINES_MAX_WIDTH ?= 200 + all: clean install lint test bench clean: @@ -27,34 +30,49 @@ profile: clean go test -count=10 -run=NONE -bench=BenchmarkFastime -benchmem -o pprof/fastime-test.bin -cpuprofile pprof/cpu-fastime.out -memprofile pprof/mem-fastime.out go tool pprof --svg pprof/fastime-test.bin pprof/cpu-fastime.out > cpu-fastime.svg go tool pprof --svg pprof/fastime-test.bin pprof/mem-fastime.out > mem-fastime.svg - go-torch -f bench/cpu-fastime-graph.svg pprof/fastime-test.bin pprof/cpu-fastime.out - go-torch --alloc_objects -f bench/mem-fastime-graph.svg pprof/fastime-test.bin pprof/mem-fastime.out \ go test -count=10 -run=NONE -bench=BenchmarkTime -benchmem -o pprof/default-test.bin -cpuprofile pprof/cpu-default.out -memprofile pprof/mem-default.out go tool pprof --svg pprof/default-test.bin pprof/mem-default.out > mem-default.svg go tool pprof --svg pprof/default-test.bin pprof/cpu-default.out > cpu-default.svg - go-torch -f bench/cpu-default-graph.svg pprof/default-test.bin pprof/cpu-default.out - go-torch --alloc_objects -f bench/mem-default-graph.svg pprof/default-test.bin pprof/mem-default.out \ mv ./*.svg bench/ -cpu: - go tool pprof pprof/fastime-test.bin pprof/cpu-fastime.out +profile-web-cpu: + go tool pprof -http=":6061" \ + pprof/fastime-test.bin \ + pprof/cpu-fastime.out + +profile-web-mem: + go tool pprof -http=":6062" \ + pprof/fastime-test.bin \ + pprof/mem-fastime.out + +profile-web-cpu-default: + go tool pprof -http=":6063" \ + pprof/default-test.bin \ + pprof/cpu-default.out + +profile-web-mem-default: + go tool pprof -http=":6064" \ + pprof/default-test.bin \ + pprof/mem-default.out + -mem: - go tool pprof --alloc_space pprof/fastime-test.bin pprof/mem-fastime.out lint: gometalinter --enable-all . | rg -v comment -format: - find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs golines -w -m 200 - find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs gofumpt -w - find ./ -type d -name .git -prune -o -type f -regex '.*\.go' -print | xargs strictgoimports -w - find ./ -type d -name .git -prune -o -type f -regex '.*\.go' -print | xargs goimports -w - test: clean GO111MODULE=on go test --race -v $(go list ./... | rg -v vendor) contributors: git log --format='%aN <%aE>' | sort -fu > CONTRIBUTORS + +run: + go run example/main.go + +format: + find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs $(GOPATH)/bin/golines -w -m $(GOLINES_MAX_WIDTH) + find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs $(GOPATH)/bin/gofumpt -w + find ./ -type d -name .git -prune -o -type f -regex '.*[^\.pb]\.go' -print | xargs $(GOPATH)/bin/strictgoimports -w + find ./ -type d -name .git -prune -o -type f -regex '.*\.go' -print | xargs $(GOPATH)/bin/goimports -w diff --git a/fastime.go b/fastime.go index 818947f..9030472 100644 --- a/fastime.go +++ b/fastime.go @@ -45,50 +45,52 @@ type fastime struct { location atomic.Pointer[time.Location] } -const bufSize = 64 +const ( + bufSize = 64 + bufMargin = 10 +) // New returns Fastime -func New() Fastime { +func New() (f Fastime) { return newFastime() } -func newFastime() *fastime { - f := &fastime{ - ut: math.MaxInt64, - unt: math.MaxInt64, - uut: math.MaxUint32, - uunt: math.MaxUint32, +func newFastime() (f *fastime) { + f = &fastime{ + ut: math.MaxInt64, + unt: math.MaxInt64, + uut: math.MaxUint32, + uunt: math.MaxUint32, correctionDur: time.Millisecond * 100, } form := time.RFC3339 f.format.Store(&form) loc := func() (loc *time.Location) { - tz, ok := syscall.Getenv("TZ") - if ok && tz != "" { - var err error - loc, err = time.LoadLocation(tz) - if err == nil { - return loc - } + tz, ok := syscall.Getenv("TZ") + if ok && tz != "" { + var err error + loc, err = time.LoadLocation(tz) + if err == nil { + return loc } - return new(time.Location) - }() + } + return new(time.Location) + }() f.location.Store(loc) - - buf := f.newBuffer(len(f.GetFormat()) + 10) + buf := f.newBuffer(len(form) + bufMargin) f.ft.Store(&buf) return f.refresh() } -func (f *fastime) update() *fastime { +func (f *fastime) update() (ft *fastime) { return f.store(f.Now().Add(time.Duration(atomic.LoadInt64(&f.dur)))) } -func (f *fastime) refresh() *fastime { +func (f *fastime) refresh() (ft *fastime) { return f.store(f.now()) } @@ -102,7 +104,7 @@ func (f *fastime) newBuffer(max int) (b []byte) { return b } -func (f *fastime) store(t time.Time) *fastime { +func (f *fastime) store(t time.Time) (ft *fastime) { f.t.Store(&t) f.formatValid.Store(false) ut := t.Unix() @@ -114,34 +116,34 @@ func (f *fastime) store(t time.Time) *fastime { return f } -func (f *fastime) IsDaemonRunning() bool { +func (f *fastime) IsDaemonRunning() (running bool) { return f.running.Load() } -func (f *fastime) GetLocation() *time.Location { - loc := f.location.Load() +func (f *fastime) GetLocation() (loc *time.Location) { + loc = f.location.Load() if loc == nil { return nil } return loc } -func (f *fastime) GetFormat() string { +func (f *fastime) GetFormat() (form string) { return *f.format.Load() } // SetLocation replaces time location -func (f *fastime) SetLocation(location *time.Location) Fastime { - if location == nil { +func (f *fastime) SetLocation(loc *time.Location) (ft Fastime) { + if loc == nil { return f } - f.location.Store(location) + f.location.Store(loc) f.refresh() return f } // SetFormat replaces time format -func (f *fastime) SetFormat(format string) Fastime { +func (f *fastime) SetFormat(format string) (ft Fastime) { f.format.Store(&format) f.formatValid.Store(false) f.refresh() @@ -149,7 +151,7 @@ func (f *fastime) SetFormat(format string) Fastime { } // Now returns current time -func (f *fastime) Now() time.Time { +func (f *fastime) Now() (t time.Time) { return *f.t.Load() } @@ -167,43 +169,43 @@ func (f *fastime) stop() { f.wg.Wait() } -func (f *fastime) Since(t time.Time) time.Duration { +func (f *fastime) Since(t time.Time) (dur time.Duration) { return f.Now().Sub(t) } // UnixNow returns current unix time -func (f *fastime) UnixNow() int64 { +func (f *fastime) UnixNow() (now int64) { return atomic.LoadInt64(&f.ut) } // UnixNow returns current unix time -func (f *fastime) UnixUNow() uint32 { +func (f *fastime) UnixUNow() (now uint32) { return atomic.LoadUint32(&f.uut) } // UnixNanoNow returns current unix nano time -func (f *fastime) UnixNanoNow() int64 { +func (f *fastime) UnixNanoNow() (now int64) { return atomic.LoadInt64(&f.unt) } // UnixNanoNow returns current unix nano time -func (f *fastime) UnixUNanoNow() uint32 { +func (f *fastime) UnixUNanoNow() (now uint32) { return atomic.LoadUint32(&f.uunt) } // FormattedNow returns formatted byte time -func (f *fastime) FormattedNow() []byte { +func (f *fastime) FormattedNow() (now []byte) { // only update formatted value on swap if f.formatValid.CompareAndSwap(false, true) { form := f.GetFormat() - buf := f.Now().AppendFormat(f.newBuffer(len(form)+10), form) + buf := f.Now().AppendFormat(f.newBuffer(len(form)+bufMargin), form) f.ft.Store(&buf) } return *f.ft.Load() } // StartTimerD provides time refresh daemon -func (f *fastime) StartTimerD(ctx context.Context, dur time.Duration) Fastime { +func (f *fastime) StartTimerD(ctx context.Context, dur time.Duration) (ft Fastime) { f.mu.Lock() defer f.mu.Unlock() // if the daemon was already running, restart diff --git a/global.go b/global.go index 8afa373..25da882 100644 --- a/global.go +++ b/global.go @@ -17,36 +17,36 @@ func init() { }) } -func IsDaemonRunning() bool { +func IsDaemonRunning() (running bool) { return instance.IsDaemonRunning() } -func GetLocation() *time.Location { +func GetLocation() (loc *time.Location) { return instance.GetLocation() } -func GetFormat() string { +func GetFormat() (form string) { return instance.GetFormat() } // SetLocation replaces time location -func SetLocation(location *time.Location) Fastime { +func SetLocation(location *time.Location) (ft Fastime) { return instance.SetLocation(location) } // SetFormat replaces time format -func SetFormat(format string) Fastime { +func SetFormat(format string) (ft Fastime) { return instance.SetFormat(format) } // Now returns current time -func Now() time.Time { +func Now() (now time.Time) { return instance.Now() } // Since returns the time elapsed since t. // It is shorthand for fastime.Now().Sub(t). -func Since(t time.Time) time.Duration { +func Since(t time.Time) (dur time.Duration) { return instance.Since(t) } @@ -56,31 +56,31 @@ func Stop() { } // UnixNow returns current unix time -func UnixNow() int64 { +func UnixNow() (now int64) { return instance.UnixNow() } // UnixUNow returns current unix time -func UnixUNow() uint32 { +func UnixUNow() (now uint32) { return instance.UnixUNow() } // UnixNanoNow returns current unix nano time -func UnixNanoNow() int64 { +func UnixNanoNow() (now int64) { return instance.UnixNanoNow() } // UnixUNanoNow returns current unix nano time -func UnixUNanoNow() uint32 { +func UnixUNanoNow() (now uint32) { return instance.UnixUNanoNow() } // FormattedNow returns formatted byte time -func FormattedNow() []byte { +func FormattedNow() (now []byte) { return instance.FormattedNow() } // StartTimerD provides time refresh daemon -func StartTimerD(ctx context.Context, dur time.Duration) Fastime { +func StartTimerD(ctx context.Context, dur time.Duration) (ft Fastime) { return instance.StartTimerD(ctx, dur) }