Skip to content

Commit

Permalink
move github.com/niean/gotools/proc here
Browse files Browse the repository at this point in the history
  • Loading branch information
niean committed Jun 2, 2015
0 parents commit df9c4cb
Show file tree
Hide file tree
Showing 4 changed files with 296 additions and 0 deletions.
18 changes: 18 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# proc
statistics utils for golang

## peference
```
// proc.counter Benchmark Test Result
BenchmarkSCounterBaseIncr 5000000 49.7 ns/op
BenchmarkSCounterBaseIncrConcurrent 5000000 51.1 ns/op
BenchmarkSCounterQpsIncr 5000000 51.0 ns/op
BenchmarkSCounterQpsIncrConcurrent 5000000 51.7 ns/op
```

## usage
```
```

## reference
140 changes: 140 additions & 0 deletions counter.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
package proc

import (
ntime "github.com/niean/gotools/time"
"sync"
"time"
)

const (
DefaultOtherMaxSize = 100
DefaultSCounterQpsPeriod = 1
)

// basic counter
type SCounterBase struct {
sync.RWMutex
Name string
Cnt int64
Time string
ts int64
Other map[string]interface{}
}

func NewSCounterBase(name string) *SCounterBase {
uts := time.Now().Unix()
return &SCounterBase{Name: name, Cnt: 0, Time: ntime.FormatTs(uts),
ts: uts, Other: make(map[string]interface{})}
}

func (this *SCounterBase) Get() *SCounterBase {
this.RLock()
defer this.RUnlock()

return this
}

func (this *SCounterBase) SetCnt(cnt int64) {
this.Lock()
this.Cnt = cnt
this.ts = time.Now().Unix()
this.Time = ntime.FormatTs(this.ts)
this.Unlock()
}

func (this *SCounterBase) Incr() {
this.IncrBy(int64(1))
}

func (this *SCounterBase) IncrBy(incr int64) {
this.Lock()
this.Cnt += incr
this.Unlock()
}

func (this *SCounterBase) PutOther(key string, value interface{}) bool {
this.Lock()
defer this.Unlock()

ret := false
_, exist := this.Other[key]
if exist {
this.Other[key] = value
ret = true
} else {
if len(this.Other) < DefaultOtherMaxSize {
this.Other[key] = value
ret = true
}
}

return ret
}

// counter with qps
type SCounterQps struct {
sync.RWMutex
Name string
Cnt int64
Qps int64
Time string
ts int64
lastTs int64
lastCnt int64
Other map[string]interface{}
}

func NewSCounterQps(name string) *SCounterQps {
uts := time.Now().Unix()
return &SCounterQps{Name: name, Cnt: 0, Time: ntime.FormatTs(uts), ts: uts,
Qps: 0, lastCnt: 0, lastTs: uts, Other: make(map[string]interface{})}
}

func (this *SCounterQps) Get() *SCounterQps {
this.Lock()
defer this.Unlock()

this.ts = time.Now().Unix()
this.Time = ntime.FormatTs(this.ts)
// get smooth qps value
if this.ts-this.lastTs > DefaultSCounterQpsPeriod {
this.Qps = int64((this.Cnt - this.lastCnt) / (this.ts - this.lastTs))
this.lastTs = this.ts
this.lastCnt = this.Cnt
}

return this
}

func (this *SCounterQps) Incr() {
this.IncrBy(int64(1))
}

func (this *SCounterQps) IncrBy(incr int64) {
this.Lock()
this.incrBy(incr)
this.Unlock()
}

func (this *SCounterQps) PutOther(key string, value interface{}) bool {
this.Lock()
defer this.Unlock()

ret := false
_, exist := this.Other[key]
if exist {
this.Other[key] = value
ret = true
} else {
if len(this.Other) < DefaultOtherMaxSize {
this.Other[key] = value
ret = true
}
}

return ret
}

func (this *SCounterQps) incrBy(incr int64) {
this.Cnt += incr
}
79 changes: 79 additions & 0 deletions counter_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package proc

import (
"runtime"
"sync"
"testing"
)

func BenchmarkSCounterBaseIncr(b *testing.B) {
b.StopTimer()
b.N = 5000000
cnt := NewSCounterBase("cnt.base")
b.StartTimer()
for i := 0; i < b.N; i++ {
cnt.Incr()
}
if int(cnt.Cnt) != b.N {
b.Error("error, SCounterBase.Incr not safe")
}
}

func BenchmarkSCounterBaseIncrConcurrent(b *testing.B) {
b.StopTimer()
b.N = 5000000
cnt := NewSCounterBase("cnt.base")
wg := sync.WaitGroup{}
workers := runtime.NumCPU()
each := b.N / workers
wg.Add(workers)
b.StartTimer()
for i := 0; i < workers; i++ {
go func() {
for i := 0; i < each; i++ {
cnt.Incr()
}
wg.Done()
}()
}
wg.Wait()
if int(cnt.Cnt) != b.N {
b.Error("error, SCounterBase.Incr concurrently not safe")
}
}

func BenchmarkSCounterQpsIncr(b *testing.B) {
b.StopTimer()
b.N = 5000000
cnt := NewSCounterQps("cnt.qps")
b.StartTimer()
for i := 0; i < b.N; i++ {
cnt.Incr()
}
if int(cnt.Cnt) != b.N {
b.Error("error, SCounterQps.Incr not safe")
}
}

func BenchmarkSCounterQpsIncrConcurrent(b *testing.B) {
b.StopTimer()
b.N = 5000000
cnt := NewSCounterQps("cnt.qps")
wg := sync.WaitGroup{}
workers := runtime.NumCPU()
each := b.N / workers
wg.Add(workers)
b.StartTimer()
for i := 0; i < workers; i++ {
go func() {
for i := 0; i < each; i++ {
cnt.Incr()
}
wg.Done()
}()
}
wg.Wait()
if int(cnt.Cnt) != b.N {
b.Error("error, SCounterQps.Incr concurrently not safe")
}
}
59 changes: 59 additions & 0 deletions trace.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
package proc

import (
"container/list"
"sync"
)

type DataTrace struct {
sync.RWMutex
MaxSize int
Name string
PK string
L *list.List
}

func NewDataTrace(name string, maxSize int) *DataTrace {
return &DataTrace{L: list.New(), Name: name, MaxSize: maxSize}
}

func (this *DataTrace) SetPK(pk string) {
this.Lock()
defer this.Unlock()

// rm old caches when trace's pk changed
if this.PK != pk {
this.L = list.New()
}
this.PK = pk
}

// proposed that there were few traced items
func (this *DataTrace) Trace(pk string, v interface{}) {
this.RLock()
if this.PK != pk {
this.RUnlock()
return
}
this.RUnlock()

// we could almost not step here, so we get few wlock
this.Lock()
defer this.Unlock()
this.L.PushFront(v)
if this.L.Len() > this.MaxSize {
this.L.Remove(this.L.Back())
}
}

func (this *DataTrace) GetAllTraced() []interface{} {
this.RLock()
defer this.RUnlock()

items := make([]interface{}, 0)
for e := this.L.Front(); e != nil; e = e.Next() {
items = append(items, e)
}

return items
}

0 comments on commit df9c4cb

Please sign in to comment.