| // $G $D/$F.go && $L $F.$A && ./$A.out | |
| // Copyright 2009 The Go Authors. All rights reserved. | |
| // Use of this source code is governed by a BSD-style | |
| // license that can be found in the LICENSE file. | |
| // Repeated malloc test. | |
| package main | |
| import ( | |
| "flag" | |
| "fmt" | |
| "runtime" | |
| "strconv" | |
| ) | |
| var chatty = flag.Bool("v", false, "chatty") | |
| var reverse = flag.Bool("r", false, "reverse") | |
| var longtest = flag.Bool("l", false, "long test") | |
| var b []*byte | |
| var stats = &runtime.MemStats | |
| func OkAmount(size, n uintptr) bool { | |
| if n < size { | |
| return false | |
| } | |
| if size < 16*8 { | |
| if n > size+16 { | |
| return false | |
| } | |
| } else { | |
| if n > size*9/8 { | |
| return false | |
| } | |
| } | |
| return true | |
| } | |
| func AllocAndFree(size, count int) { | |
| if *chatty { | |
| fmt.Printf("size=%d count=%d ...\n", size, count) | |
| } | |
| n1 := stats.Alloc | |
| for i := 0; i < count; i++ { | |
| b[i] = runtime.Alloc(uintptr(size)) | |
| base, n := runtime.Lookup(b[i]) | |
| if base != b[i] || !OkAmount(uintptr(size), n) { | |
| println("lookup failed: got", base, n, "for", b[i]) | |
| panic("fail") | |
| } | |
| if runtime.MemStats.Sys > 1e9 { | |
| println("too much memory allocated") | |
| panic("fail") | |
| } | |
| } | |
| n2 := stats.Alloc | |
| if *chatty { | |
| fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats) | |
| } | |
| n3 := stats.Alloc | |
| runtime.GC() | |
| for j := 0; j < count; j++ { | |
| i := j | |
| if *reverse { | |
| i = count - 1 - j | |
| } | |
| alloc := uintptr(stats.Alloc) | |
| base, n := runtime.Lookup(b[i]) | |
| if base != b[i] || !OkAmount(uintptr(size), n) { | |
| println("lookup failed: got", base, n, "for", b[i]) | |
| panic("fail") | |
| } | |
| runtime.Free(b[i]) | |
| runtime.GC() | |
| if stats.Alloc != uint64(alloc-n) { | |
| println("free alloc got", stats.Alloc, "expected", alloc-n, "after free of", n) | |
| panic("fail") | |
| } | |
| if runtime.MemStats.Sys > 1e9 { | |
| println("too much memory allocated") | |
| panic("fail") | |
| } | |
| } | |
| n4 := stats.Alloc | |
| if *chatty { | |
| fmt.Printf("size=%d count=%d stats=%+v\n", size, count, *stats) | |
| } | |
| if n2-n1 != n3-n4 { | |
| println("wrong alloc count: ", n2-n1, n3-n4) | |
| panic("fail") | |
| } | |
| } | |
| func atoi(s string) int { | |
| i, _ := strconv.Atoi(s) | |
| return i | |
| } | |
| func main() { | |
| runtime.MemProfileRate = 0 // disable profiler | |
| flag.Parse() | |
| b = make([]*byte, 10000) | |
| if flag.NArg() > 0 { | |
| AllocAndFree(atoi(flag.Arg(0)), atoi(flag.Arg(1))) | |
| return | |
| } | |
| maxb := 1 << 22 | |
| if !*longtest { | |
| maxb = 1 << 19 | |
| } | |
| for j := 1; j <= maxb; j <<= 1 { | |
| n := len(b) | |
| max := uintptr(1 << 28) | |
| if !*longtest { | |
| max = uintptr(maxb) | |
| } | |
| if uintptr(j)*uintptr(n) > max { | |
| n = int(max / uintptr(j)) | |
| } | |
| if n < 10 { | |
| n = 10 | |
| } | |
| for m := 1; m <= n; { | |
| AllocAndFree(j, m) | |
| if m == n { | |
| break | |
| } | |
| m = 5 * m / 4 | |
| if m < 4 { | |
| m++ | |
| } | |
| if m > n { | |
| m = n | |
| } | |
| } | |
| } | |
| } |