// Max number of threads to run garbage collection.
// 2, 3, and 4 are all plausible maximums depending
- // on the hardware details of the machine. The second
- // proc is the one that helps the most (after the first),
- // so start with just 2 for now.
- MaxGcproc = 2,
+ // on the hardware details of the machine. The garbage
+ // collector scales well to 4 cpus.
+ MaxGcproc = 4,
};
// A generic linked list of blocks. (Typically the block is bigger than sizeof(MLink).)
#define bitMask (bitBlockBoundary | bitAllocated | bitMarked | bitSpecial)
// TODO: Make these per-M.
-static uint64 nlookup;
-static uint64 nsizelookup;
-static uint64 naddrlookup;
static uint64 nhandoff;
static int32 gctrace;
// Otherwise consult span table to find beginning.
// (Manually inlined copy of MHeap_LookupMaybe.)
- nlookup++;
- naddrlookup++;
k = (uintptr)obj>>PageShift;
x = k;
if(sizeof(void*) == 8)
b = *--wp;
nobj--;
- // Figure out n = size of b. Start by loading bits for b.
- off = (uintptr*)b - (uintptr*)arena_start;
- bitp = (uintptr*)arena_start - off/wordsPerBitmapWord - 1;
- shift = off % wordsPerBitmapWord;
- xbits = *bitp;
- bits = xbits >> shift;
-
- // Might be small; look for nearby block boundary.
- // A block boundary is marked by either bitBlockBoundary
- // or bitAllocated being set (see notes near their definition).
- enum {
- boundary = bitBlockBoundary|bitAllocated
- };
- // Look for a block boundary both after and before b
- // in the same bitmap word.
- //
- // A block boundary j words after b is indicated by
- // bits>>j & boundary
- // assuming shift+j < bitShift. (If shift+j >= bitShift then
- // we'll be bleeding other bit types like bitMarked into our test.)
- // Instead of inserting the conditional shift+j < bitShift into the loop,
- // we can let j range from 1 to bitShift as long as we first
- // apply a mask to keep only the bits corresponding
- // to shift+j < bitShift aka j < bitShift-shift.
- bits &= (boundary<<(bitShift-shift)) - boundary;
-
- // A block boundary j words before b is indicated by
- // xbits>>(shift-j) & boundary
- // (assuming shift >= j). There is no cleverness here
- // avoid the test, because when j gets too large the shift
- // turns negative, which is undefined in C.
-
- for(j=1; j<bitShift; j++) {
- if(((bits>>j)&boundary) != 0 || shift>=j && ((xbits>>(shift-j))&boundary) != 0) {
- n = j*PtrSize;
- goto scan;
- }
- }
-
- // Fall back to asking span about size class.
+ // Ask span about size class.
// (Manually inlined copy of MHeap_Lookup.)
- nlookup++;
- nsizelookup++;
x = (uintptr)b>>PageShift;
if(sizeof(void*) == 8)
x -= (uintptr)arena_start>>PageShift;
n = s->npages<<PageShift;
else
n = runtime·class_to_size[s->sizeclass];
- scan:;
}
}
}
t0 = runtime·nanotime();
- nlookup = 0;
- nsizelookup = 0;
- naddrlookup = 0;
nhandoff = 0;
m->gcing = 1;
runtime·printf("pause %D\n", t3-t0);
if(gctrace) {
- runtime·printf("gc%d(%d): %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D pointer lookups (%D size, %D addr) %D handoff\n",
+ runtime·printf("gc%d(%d): %D+%D+%D ms %D -> %D MB %D -> %D (%D-%D) objects %D handoff\n",
mstats.numgc, work.nproc, (t1-t0)/1000000, (t2-t1)/1000000, (t3-t2)/1000000,
heap0>>20, heap1>>20, obj0, obj1,
mstats.nmalloc, mstats.nfree,
- nlookup, nsizelookup, naddrlookup, nhandoff);
+ nhandoff);
}
runtime·semrelease(&gcsema);
parser\
peano\
tree\
+ tree2\
all: $(addsuffix .out, $(ALL))
var serve = flag.String("serve", "", "serve http on this address at end")
-func isGoFile(dir *os.FileInfo) bool {
- return dir.IsRegular() &&
- !strings.HasPrefix(dir.Name, ".") && // ignore .files
- path.Ext(dir.Name) == ".go"
+func isGoFile(dir os.FileInfo) bool {
+ return !dir.IsDir() &&
+ !strings.HasPrefix(dir.Name(), ".") && // ignore .files
+ path.Ext(dir.Name()) == ".go"
}
-func isPkgFile(dir *os.FileInfo) bool {
+func isPkgFile(dir os.FileInfo) bool {
return isGoFile(dir) &&
- !strings.HasSuffix(dir.Name, "_test.go") // ignore test files
+ !strings.HasSuffix(dir.Name(), "_test.go") // ignore test files
}
func pkgName(filename string) string {
_, pkgname := path.Split(dirpath)
// filter function to select the desired .go files
- filter := func(d *os.FileInfo) bool {
+ filter := func(d os.FileInfo) bool {
if isPkgFile(d) {
// Some directories contain main packages: Only accept
// files that belong to the expected package so that
// found" errors.
// Additionally, accept the special package name
// fakePkgName if we are looking at cmd documentation.
- name := pkgName(dirpath + "/" + d.Name)
+ name := pkgName(dirpath + "/" + d.Name())
return name == pkgname
}
return false
flag.Parse()
var lastParsed []map[string]*ast.Package
- var t0 int64
+ var t0 time.Time
pkgroot := runtime.GOROOT() + "/src/pkg/"
for pass := 0; pass < 2; pass++ {
// Once the heap is grown to full size, reset counters.
// the average look much better than it actually is.
st.NumGC = 0
st.PauseTotalNs = 0
- t0 = time.Nanoseconds()
+ t0 = time.Now()
for i := 0; i < *n; i++ {
parsed := make([]map[string]*ast.Package, *p)
runtime.GC()
runtime.GC()
}
- t1 := time.Nanoseconds()
+ t1 := time.Now()
fmt.Printf("Alloc=%d/%d Heap=%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
st.Alloc, st.TotalAlloc,
}
*/
// Standard gotest benchmark output, collected by build dashboard.
- gcstats("BenchmarkParser", *n, t1-t0)
+ gcstats("BenchmarkParser", *n, t1.Sub(t0))
if *serve != "" {
log.Fatal(http.ListenAndServe(*serve, nil))
var packages = []string{
"archive/tar",
- "asn1",
- "big",
+ "encoding/asn1",
+ "math/big",
"bufio",
"bytes",
- "cmath",
+ "math/cmplx",
"compress/flate",
"compress/gzip",
"compress/zlib",
"container/heap",
"container/list",
"container/ring",
- "container/vector",
"crypto/aes",
"crypto/blowfish",
"crypto/hmac",
"debug/macho",
"debug/elf",
"debug/gosym",
- "ebnf",
+ "exp/ebnf",
"encoding/ascii85",
"encoding/base64",
"encoding/binary",
"encoding/git85",
"encoding/hex",
"encoding/pem",
- "exec",
- "exp/datafmt",
- "expvar",
+ "os/exec",
"flag",
"fmt",
"go/ast",
"go/printer",
"go/scanner",
"go/token",
- "gob",
+ "encoding/gob",
"hash",
"hash/adler32",
"hash/crc32",
"hash/crc64",
- "http",
+ "net/http",
"image",
"image/jpeg",
"image/png",
"io",
"io/ioutil",
- "json",
+ "encoding/json",
"log",
"math",
"mime",
"os/signal",
"patch",
"path",
- "rand",
+ "math/rand",
"reflect",
"regexp",
- "rpc",
+ "net/rpc",
"runtime",
- "scanner",
+ "text/scanner",
"sort",
- "smtp",
+ "net/smtp",
"strconv",
"strings",
"sync",
"syscall",
- "syslog",
- "tabwriter",
- "template",
+ "log/syslog",
+ "text/tabwriter",
+ "text/template",
"testing",
"testing/iotest",
"testing/quick",
"testing/script",
"time",
"unicode",
- "utf8",
- "utf16",
+ "unicode/utf8",
+ "unicode/utf16",
"websocket",
- "xml",
+ "encoding/xml",
}
// -------------------------------------
// Factorial
-
func main() {
- t0 := time.Nanoseconds()
+ t0 := time.Now()
verify()
for i := 0; i <= 9; i++ {
print(i, "! = ", count(fact(gen(i))), "\n")
}
runtime.GC()
- t1 := time.Nanoseconds()
+ t1 := time.Now()
- gcstats("BenchmarkPeano", 1, t1-t0)
+ gcstats("BenchmarkPeano", 1, t1.Sub(t0))
}
"fmt"
"runtime"
"sort"
+ "time"
)
-func gcstats(name string, n int, t int64) {
+func gcstats(name string, n int, t time.Duration) {
st := &runtime.MemStats
fmt.Printf("garbage.%sMem Alloc=%d/%d Heap=%d NextGC=%d Mallocs=%d\n", name, st.Alloc, st.TotalAlloc, st.Sys, st.NextGC, st.Mallocs)
- fmt.Printf("garbage.%s %d %d ns/op\n", name, n, t/int64(n))
+ fmt.Printf("garbage.%s %d %d ns/op\n", name, n, t.Nanoseconds()/int64(n))
fmt.Printf("garbage.%sLastPause 1 %d ns/op\n", name, st.PauseNs[(st.NumGC-1)%uint32(len(st.PauseNs))])
fmt.Printf("garbage.%sPause %d %d ns/op\n", name, st.NumGC, int64(st.PauseTotalNs)/int64(st.NumGC))
nn := int(st.NumGC)
func main() {
flag.Parse()
- t0 := time.Nanoseconds()
+ t0 := time.Now()
maxDepth := *n
if minDepth+2 > *n {
}
fmt.Printf("long lived tree of depth %d\t check: %d\n", maxDepth, longLivedTree.itemCheck())
- t1 := time.Nanoseconds()
+ t1 := time.Now()
// Standard gotest benchmark output, collected by build dashboard.
- gcstats("BenchmarkTree", *n, t1-t0)
+ gcstats("BenchmarkTree", *n, t1.Sub(t0))
}
--- /dev/null
+// Copyright 2012 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.
+
+package main
+
+import (
+ "flag"
+ "fmt"
+ "log"
+ "os"
+ "runtime"
+ "runtime/pprof"
+ "unsafe"
+)
+
+const BranchingFactor = 4
+
+type Object struct {
+ child [BranchingFactor]*Object
+}
+
+var (
+ cpus = flag.Int("cpus", 1, "number of cpus to use")
+ heapsize = flag.Int64("heapsize", 100*1024*1024, "size of the heap in bytes")
+ cpuprofile = flag.String("cpuprofile", "", "write cpu profile to file")
+
+ lastPauseNs uint64 = 0
+ lastFree uint64 = 0
+ heap *Object
+ calls [20]int
+ numobjects int64
+)
+
+func buildHeap() {
+ objsize := int64(unsafe.Sizeof(Object{}))
+ heap, _ = buildTree(float64(objsize), float64(*heapsize), 0)
+ fmt.Printf("*** built heap: %.0f MB; (%d objects * %d bytes)\n",
+ float64(*heapsize)/1048576, numobjects, objsize)
+}
+
+func buildTree(objsize, size float64, depth int) (*Object, float64) {
+ calls[depth]++
+ x := &Object{}
+ numobjects++
+ subtreeSize := (size - objsize) / BranchingFactor
+ alloc := objsize
+ for i := 0; i < BranchingFactor && alloc < size; i++ {
+ c, n := buildTree(objsize, subtreeSize, depth+1)
+ x.child[i] = c
+ alloc += n
+ }
+ return x, alloc
+}
+
+func gc() {
+ runtime.GC()
+ runtime.UpdateMemStats()
+ pause := runtime.MemStats.PauseTotalNs
+ inuse := runtime.MemStats.Alloc
+ free := runtime.MemStats.TotalAlloc - inuse
+ fmt.Printf("gc pause: %8.3f ms; collect: %8.0f MB; heapsize: %8.0f MB\n",
+ float64(pause-lastPauseNs)/1e6,
+ float64(free-lastFree)/1048576,
+ float64(inuse)/1048576)
+ lastPauseNs = pause
+ lastFree = free
+}
+
+func main() {
+ flag.Parse()
+ buildHeap()
+ runtime.GOMAXPROCS(*cpus)
+ runtime.UpdateMemStats()
+ lastPauseNs = runtime.MemStats.PauseTotalNs
+ lastFree = runtime.MemStats.TotalAlloc - runtime.MemStats.Alloc
+ if *cpuprofile != "" {
+ f, err := os.Create(*cpuprofile)
+ if err != nil {
+ log.Fatal(err)
+ }
+ pprof.StartCPUProfile(f)
+ defer pprof.StopCPUProfile()
+ }
+ for i := 0; i < 10; i++ {
+ gc()
+ }
+}