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  }