Skip to content

Commit ea52ffb

Browse files
committed
add cache manager
1 parent 48f3d01 commit ea52ffb

File tree

2 files changed

+166
-0
lines changed

2 files changed

+166
-0
lines changed

cachem/cache.go

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
package cachem
2+
3+
import (
4+
"math/bits"
5+
"sync"
6+
)
7+
8+
const maxSize = 46
9+
10+
// index contains []byte which cap is 1<<index
11+
var caches [maxSize]sync.Pool
12+
13+
func init() {
14+
for i := 0; i < maxSize; i++ {
15+
size := 1 << i
16+
caches[i].New = func() interface{} {
17+
buf := make([]byte, 0, size)
18+
return buf
19+
}
20+
}
21+
}
22+
23+
// calculates which pool to get from
24+
func calcIndex(size int) int {
25+
if size == 0 {
26+
return 0
27+
}
28+
if isPowerOfTwo(size) {
29+
return bsr(size)
30+
}
31+
return bsr(size) + 1
32+
}
33+
34+
// Malloc supports one or two integer argument.
35+
// The size specifies the length of the returned slice, which means len(ret) == size.
36+
// A second integer argument may be provided to specify the minimum capacity, which means cap(ret) >= cap.
37+
func Malloc(size int, capacity ...int) []byte {
38+
if len(capacity) > 1 {
39+
panic("too many arguments to Malloc")
40+
}
41+
var c = size
42+
if len(capacity) > 0 && capacity[0] > size {
43+
c = capacity[0]
44+
}
45+
var ret = caches[calcIndex(c)].Get().([]byte)
46+
ret = ret[:size]
47+
return ret
48+
}
49+
50+
// Free should be called when the buf is no longer used.
51+
func Free(buf []byte) {
52+
size := cap(buf)
53+
if !isPowerOfTwo(size) {
54+
return
55+
}
56+
buf = buf[:0]
57+
caches[bsr(size)].Put(buf)
58+
}
59+
60+
func bsr(x int) int {
61+
return bits.Len(uint(x)) - 1
62+
}
63+
64+
func isPowerOfTwo(x int) bool {
65+
return (x & (-x)) == x
66+
}

cachem/cache_test.go

Lines changed: 100 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,100 @@
1+
package cachem
2+
3+
import "testing"
4+
5+
func TestMalloc(t *testing.T) {
6+
buf := Malloc(4096)
7+
t.Log(cap(buf))
8+
}
9+
10+
func BenchmarkNormal4096(b *testing.B) {
11+
var buf []byte
12+
b.ReportAllocs()
13+
for i := 0; i < b.N; i++ {
14+
buf = make([]byte, 0, 4096)
15+
}
16+
_ = buf
17+
}
18+
19+
func BenchmarkMCache4096(b *testing.B) {
20+
var buf []byte
21+
b.ReportAllocs()
22+
for i := 0; i < b.N; i++ {
23+
buf = Malloc(4096)
24+
Free(buf)
25+
}
26+
_ = buf
27+
}
28+
29+
func BenchmarkNormal10M(b *testing.B) {
30+
var buf []byte
31+
b.ReportAllocs()
32+
for i := 0; i < b.N; i++ {
33+
buf = make([]byte, 0, 1024*1024*10)
34+
}
35+
_ = buf
36+
}
37+
38+
func BenchmarkMCache10M(b *testing.B) {
39+
var buf []byte
40+
b.ReportAllocs()
41+
for i := 0; i < b.N; i++ {
42+
buf = Malloc(1024 * 1024 * 10)
43+
Free(buf)
44+
}
45+
_ = buf
46+
}
47+
48+
func BenchmarkNormal4096Parallel(b *testing.B) {
49+
b.ReportAllocs()
50+
b.RunParallel(func(pb *testing.PB) {
51+
var buf []byte
52+
for pb.Next() {
53+
for i := 0; i < b.N; i++ {
54+
buf = make([]byte, 0, 4096)
55+
}
56+
}
57+
_ = buf
58+
})
59+
}
60+
61+
func BenchmarkMCache4096Parallel(b *testing.B) {
62+
b.ReportAllocs()
63+
b.RunParallel(func(pb *testing.PB) {
64+
var buf []byte
65+
for pb.Next() {
66+
for i := 0; i < b.N; i++ {
67+
buf = Malloc(4096)
68+
Free(buf)
69+
}
70+
}
71+
_ = buf
72+
})
73+
}
74+
75+
func BenchmarkNormal10MParallel(b *testing.B) {
76+
b.ReportAllocs()
77+
b.RunParallel(func(pb *testing.PB) {
78+
var buf []byte
79+
for pb.Next() {
80+
for i := 0; i < b.N; i++ {
81+
buf = make([]byte, 0, 1024*1024*10)
82+
}
83+
}
84+
_ = buf
85+
})
86+
}
87+
88+
func BenchmarkMCache10MParallel(b *testing.B) {
89+
b.ReportAllocs()
90+
b.RunParallel(func(pb *testing.PB) {
91+
var buf []byte
92+
for pb.Next() {
93+
for i := 0; i < b.N; i++ {
94+
buf = Malloc(1024 * 1024 * 10)
95+
Free(buf)
96+
}
97+
}
98+
_ = buf
99+
})
100+
}

0 commit comments

Comments
 (0)