github.com/outcaste-io/ristretto@v0.2.3/contrib/memtest/main.go (about) 1 /* 2 * Copyright 2020 Dgraph Labs, Inc. and Contributors 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package main 18 19 // #include <stdlib.h> 20 import "C" 21 import ( 22 "fmt" 23 "math/rand" 24 "net/http" 25 _ "net/http/pprof" 26 "os" 27 "os/signal" 28 "runtime" 29 "sync/atomic" 30 "syscall" 31 "time" 32 "unsafe" 33 34 "github.com/dustin/go-humanize" 35 "github.com/outcaste-io/ristretto/z" 36 ) 37 38 type S struct { 39 key uint64 40 val []byte 41 next *S 42 inGo bool 43 } 44 45 var ( 46 ssz = int(unsafe.Sizeof(S{})) 47 lo, hi = int64(1 << 30), int64(16 << 30) 48 increase = true 49 stop int32 50 fill []byte 51 maxMB = 32 52 53 cycles int64 = 16 54 ) 55 var numbytes int64 56 var counter int64 57 58 func newS(sz int) *S { 59 var s *S 60 if b := Calloc(ssz); len(b) > 0 { 61 s = (*S)(unsafe.Pointer(&b[0])) 62 } else { 63 s = &S{inGo: true} 64 } 65 66 s.val = Calloc(sz) 67 copy(s.val, fill) 68 if s.next != nil { 69 panic(fmt.Sprintf("news.next must be nil: %p", s.next)) 70 } 71 return s 72 } 73 74 func freeS(s *S) { 75 Free(s.val) 76 if !s.inGo { 77 buf := (*[z.MaxArrayLen]byte)(unsafe.Pointer(s))[:ssz:ssz] 78 Free(buf) 79 } 80 } 81 82 func (s *S) allocateNext(sz int) { 83 ns := newS(sz) 84 s.next, ns.next = ns, s.next 85 } 86 87 func (s *S) deallocNext() { 88 if s.next == nil { 89 panic("next should not be nil") 90 } 91 next := s.next 92 s.next = next.next 93 freeS(next) 94 } 95 96 func memory() { 97 // In normal mode, z.NumAllocBytes would always be zero. So, this program would misbehave. 98 curMem := NumAllocBytes() 99 if increase { 100 if curMem > hi { 101 increase = false 102 } 103 } else { 104 if curMem < lo { 105 increase = true 106 runtime.GC() 107 time.Sleep(3 * time.Second) 108 109 counter++ 110 } 111 } 112 var js z.MemStats 113 z.ReadMemStats(&js) 114 115 fmt.Printf("[%d] Current Memory: %s. Increase? %v, MemStats [Active: %s, Allocated: %s,"+ 116 " Resident: %s, Retained: %s]\n", 117 counter, humanize.IBytes(uint64(curMem)), increase, 118 humanize.IBytes(js.Active), humanize.IBytes(js.Allocated), 119 humanize.IBytes(js.Resident), humanize.IBytes(js.Retained)) 120 } 121 122 func viaLL() { 123 ticker := time.NewTicker(10 * time.Millisecond) 124 defer ticker.Stop() 125 126 root := newS(1) 127 for range ticker.C { 128 if counter >= cycles { 129 fmt.Printf("Finished %d cycles. Deallocating...\n", counter) 130 break 131 } 132 if atomic.LoadInt32(&stop) == 1 { 133 break 134 } 135 if increase { 136 root.allocateNext(rand.Intn(maxMB) << 20) 137 } else { 138 root.deallocNext() 139 } 140 memory() 141 } 142 for root.next != nil { 143 root.deallocNext() 144 memory() 145 } 146 freeS(root) 147 } 148 149 func main() { 150 check() 151 fill = make([]byte, maxMB<<20) 152 rand.Read(fill) 153 154 c := make(chan os.Signal) 155 signal.Notify(c, os.Interrupt, syscall.SIGTERM) 156 go func() { 157 <-c 158 fmt.Println("Stopping") 159 atomic.StoreInt32(&stop, 1) 160 }() 161 go func() { 162 if err := http.ListenAndServe("0.0.0.0:8080", nil); err != nil { 163 panic(fmt.Sprintf("Error: %v", err)) 164 } 165 }() 166 167 viaLL() 168 if left := NumAllocBytes(); left != 0 { 169 panic(fmt.Sprintf("Unable to deallocate all memory: %v\n", left)) 170 } 171 runtime.GC() 172 fmt.Println("Done. Reduced to zero memory usage.") 173 time.Sleep(5 * time.Second) 174 }