Skip to content

Commit

Permalink
add Real Map memory size function
Browse files Browse the repository at this point in the history
Signed-off-by: kpango <kpango@vdaas.org>
  • Loading branch information
kpango committed Sep 11, 2024
1 parent f3ad957 commit 3cd1081
Show file tree
Hide file tree
Showing 18 changed files with 306 additions and 17 deletions.
Empty file modified .circleci/config.yml
100644 → 100755
Empty file.
Empty file modified .gitignore
100644 → 100755
Empty file.
Empty file modified .whitesource
100644 → 100755
Empty file.
Empty file modified LICENSE
100644 → 100755
Empty file.
Empty file modified Makefile
100644 → 100755
Empty file.
Empty file modified README.md
100644 → 100755
Empty file.
Empty file modified assets/logo.png
100644 → 100755
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
114 changes: 110 additions & 4 deletions example/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,58 @@ package main

import (
"context"
"encoding/gob"
"encoding/json"
"math/rand"
"os"
"runtime"
"strconv"
"time"
"unsafe"

"github.com/kpango/gache/v2"
"github.com/kpango/glg"
)

var (
bigData = map[string]string{}
bigDataLen = 2 << 10
bigDataCount = 2 << 11
)

func init() {
for i := 0; i < bigDataCount; i++ {
bigData[randStr(bigDataLen)] = randStr(bigDataLen)
}
}

var randSrc = rand.NewSource(time.Now().UnixNano())

const (
rs6Letters = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
rs6LetterIdxBits = 6
rs6LetterIdxMask = 1<<rs6LetterIdxBits - 1
rs6LetterIdxMax = 63 / rs6LetterIdxBits
)

func randStr(n int) string {
b := make([]byte, n)
cache, remain := randSrc.Int63(), rs6LetterIdxMax
for i := n - 1; i >= 0; {
if remain == 0 {
cache, remain = randSrc.Int63(), rs6LetterIdxMax
}
idx := int(cache & rs6LetterIdxMask)
if idx < len(rs6Letters) {
b[i] = rs6Letters[idx]
i--
}
cache >>= rs6LetterIdxBits
remain--
}
return *(*string)(unsafe.Pointer(&b))
}

func main() {
var (
key1 = "key1"
Expand Down Expand Up @@ -45,18 +90,30 @@ func main() {
return true
})

file, err := os.OpenFile("/tmp/gache-sample.gdb", os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o755)
var m runtime.MemStats
runtime.ReadMemStats(&m)
mbody, err := json.Marshal(m)
if err == nil {
glg.Debugf("memory size: %d, lenght: %d, mem stats: %v", gc.Size(), gc.Len(), string(mbody))
}
path := "/tmp/gache-sample.gdb"

file, err := os.OpenFile(path, os.O_TRUNC|os.O_CREATE|os.O_WRONLY, 0o755)
if err != nil {
glg.Error(err)
return
}
gc.Write(context.Background(), file)

gob.Register(struct{}{})
err = gc.Write(context.Background(), file)
gc.Stop()
file.Close()
if err != nil {
glg.Error(err)
return
}

gcn := gache.New[any]().SetDefaultExpire(time.Minute)
file, err = os.OpenFile("/tmp/gache-sample.gdb", os.O_RDONLY, 0o755)
file, err = os.OpenFile(path, os.O_RDONLY, 0o755)
if err != nil {
glg.Error(err)
return
Expand Down Expand Up @@ -88,4 +145,53 @@ func main() {
glg.Debugf("key:\t%v\nval:\t%d", k, v)
return true
})

runtime.GC()
gcs := gache.New[string]()
maxCnt := 10000000
digitLen := len(strconv.Itoa(maxCnt))
for i := 0; i < maxCnt; i++ {
if i%1000 == 0 {
// runtime.ReadMemStats(&m)
// mbody, err := json.Marshal(m)
if err == nil {
// glg.Debugf("before set memory size: %d, lenght: %d, mem stats: %v", gcs.Size(), gcs.Len(), string(mbody))
glg.Debugf("Execution No.%-*d:\tbefore set memory size: %d, lenght: %d", digitLen, i, gcs.Size(), gcs.Len())
}
}
for k, v := range bigData {
gcs.Set(k, v)
}
if i%1000 == 0 {
// runtime.ReadMemStats(&m)
// mbody, err := json.Marshal(m)
if err == nil {
glg.Debugf("Execution No.%-*d:\tafter set memory size: %d, lenght: %d", digitLen, i, gcs.Size(), gcs.Len())
// glg.Debugf("after set memory size: %d, lenght: %d, mem stats: %v", gcs.Size(), gcs.Len(), string(mbody))
}
}

for k := range bigData {
gcs.Get(k)
}
for k := range bigData {
gcs.Delete(k)
}
if i%1000 == 0 {
// runtime.ReadMemStats(&m)
// mbody, err := json.Marshal(m)
if err == nil {
glg.Debugf("Execution No.%-*d:\tafter delete memory size: %d, lenght: %d", digitLen, i, gcs.Size(), gcs.Len())
// glg.Debugf("after delete memory size: %d, lenght: %d, mem stats: %v", gcs.Size(), gcs.Len(), string(mbody))
}
runtime.GC()
// runtime.ReadMemStats(&m)
// mbody, err = json.Marshal(m)
if err == nil {
glg.Debugf("Execution No.%-*d:\tafter gc memory size: %d, lenght: %d", digitLen, i, gcs.Size(), gcs.Len())
// glg.Debugf("after gc memory size: %d, lenght: %d, mem stats: %v", gcs.Size(), gcs.Len(), string(mbody))
}
}

}
}
50 changes: 39 additions & 11 deletions gache.go
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ type (
SetWithExpire(string, V, time.Duration)
StartExpired(context.Context, time.Duration) Gache[V]
Len() int
Size() uintptr
ToMap(context.Context) *sync.Map
ToRawMap(context.Context) map[string]V
Write(context.Context, io.Writer) error
Expand All @@ -58,18 +59,18 @@ type (

// gache is base instance type
gache[V any] struct {
expFuncEnabled bool
expire int64
l uint64
shards [slen]*Map[string, *value[V]]
cancel atomic.Pointer[context.CancelFunc]
expChan chan string
expFunc func(context.Context, string)
shards [slen]*Map[string, *value[V]]
expFuncEnabled bool
expire int64
l uint64
}

value[V any] struct {
expire int64
val V
expire int64
}
)

Expand All @@ -83,6 +84,8 @@ const (

// NoTTL can be use for disabling ttl cache expiration
NoTTL time.Duration = -1

maxHashKeyLength = 256
)

// New returns Gache (*gache) instance
Expand All @@ -103,8 +106,8 @@ func newMap[V any]() (m *Map[string, *value[V]]) {
}

func getShardID(key string) (id uint64) {
if len(key) > 128 {
return xxh3.HashString(key[:128]) & mask
if len(key) > maxHashKeyLength {
return xxh3.HashString(key[:maxHashKeyLength]) & mask
}
return xxh3.HashString(key) & mask
}
Expand Down Expand Up @@ -142,7 +145,8 @@ func (g *gache[V]) SetExpiredHook(f func(context.Context, string)) Gache[V] {
func (g *gache[V]) StartExpired(ctx context.Context, dur time.Duration) Gache[V] {
go func() {
tick := time.NewTicker(dur)
ctx, cancel := context.WithCancel(ctx)
var cancel context.CancelFunc
ctx, cancel = context.WithCancel(ctx)
g.cancel.Store(&cancel)
for {
select {
Expand Down Expand Up @@ -193,7 +197,8 @@ func (g *gache[V]) ToRawMap(ctx context.Context) map[string]V {
// get returns value & exists from key
func (g *gache[V]) get(key string) (v V, expire int64, ok bool) {
var val *value[V]
val, ok = g.shards[getShardID(key)].Load(key)
shard := g.shards[getShardID(key)]
val, ok = shard.Load(key)
if !ok {
return v, 0, false
}
Expand Down Expand Up @@ -222,7 +227,8 @@ func (g *gache[V]) set(key string, val V, expire int64) {
if expire > 0 {
expire = fastime.UnixNanoNow() + expire
}
_, loaded := g.shards[getShardID(key)].Swap(key, &value[V]{
shard := g.shards[getShardID(key)]
_, loaded := shard.Swap(key, &value[V]{
expire: expire,
val: val,
})
Expand Down Expand Up @@ -313,6 +319,19 @@ func (g *gache[V]) Len() int {
return *(*int)(unsafe.Pointer(&l))
}

func (g *gache[V]) Size() (size uintptr) {
size += unsafe.Sizeof(g.expFuncEnabled) // bool
size += unsafe.Sizeof(g.expire) // int64
size += unsafe.Sizeof(g.l) // uint64
size += unsafe.Sizeof(g.cancel) // atomic.Pointer[context.CancelFunc]
size += unsafe.Sizeof(g.expChan) // chan string
size += unsafe.Sizeof(g.expFunc) // func(context.Context, string)
for _, shard := range g.shards {
size += shard.Size()
}
return size
}

// Write writes all cached data to writer
func (g *gache[V]) Write(ctx context.Context, w io.Writer) error {
m := g.ToRawMap(ctx)
Expand All @@ -329,7 +348,7 @@ func (g *gache[V]) Read(r io.Reader) error {
return err
}
for k, v := range m {
g.Set(k, v)
go g.Set(k, v)
}
return nil
}
Expand All @@ -348,3 +367,12 @@ func (g *gache[V]) Clear() {
g.shards[i] = newMap[V]()
}
}

func (v *value[V]) Size() uintptr {
var size uintptr

size += unsafe.Sizeof(v.expire) // int64
size += unsafe.Sizeof(v.val) // V size

return size
}
Empty file modified gache_benchmark_test.go
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
module github.com/kpango/gache/v2

go 1.20
go 1.23.0

require (
github.com/kpango/fastime v1.1.9
Expand Down
6 changes: 6 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,16 @@ github.com/kpango/fastime v1.1.9/go.mod h1:vyD7FnUn08zxY4b/QFBZVG+9EWMYsNl+QF0uE
github.com/kpango/glg v1.6.15 h1:nw0xSxpSyrDIWHeb3dvnE08PW+SCbK+aYFETT75IeLA=
github.com/kpango/glg v1.6.15/go.mod h1:cmsc7Yeu8AS3wHLmN7bhwENXOpxfq+QoqxCIk2FneRk=
github.com/sirupsen/logrus v1.9.0 h1:trlNQbNUG3OdDrDil03MCb1H2o9nJ1x4/5LYw7byDE0=
github.com/sirupsen/logrus v1.9.0/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ=
github.com/zeebo/assert v1.3.0 h1:g7C04CbJuIDKNPFHmsk4hwZDO5O+kntRxzaUoNXj+IQ=
github.com/zeebo/assert v1.3.0/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
go.uber.org/atomic v1.7.0 h1:ADUqmZGgLDDfbSL9ZmPxKTybcoEYHgpYfELNoN+7hsw=
go.uber.org/atomic v1.7.0/go.mod h1:fEN4uk6kAWBTFdckzkM89CLk9XfWZrxpCo0nPH17wJc=
go.uber.org/multierr v1.6.0 h1:y6IPFStTAIT5Ytl7/XYmHvzXQ7S3g/IeZW9hyZ5thw4=
go.uber.org/multierr v1.6.0/go.mod h1:cdWPpRnG4AhwMwsgIHip0KRBQjJy5kYEpYjJxpXp9iU=
go.uber.org/zap v1.24.0 h1:FiJd5l1UOLj0wCgbSE0rwwXHzEdAZS6hiiSnxJN/D60=
go.uber.org/zap v1.24.0/go.mod h1:2kMP+WWQ8aoFoedH3T2sq6iJ2yDWpHbP0f6MQbS9Gkg=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8 h1:0A+M6Uqn+Eje4kHMK80dtF3JCXC4ykBgQG4Fe06QRhQ=
golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Loading

0 comments on commit 3cd1081

Please sign in to comment.