Commit e4f06812 authored by Russ Cox's avatar Russ Cox

runtime: instrument malloc + garbage collector.

add simple garbage collection benchmark.

R=iant
CC=golang-dev
https://golang.org/cl/204053
parent 49c42569
...@@ -42,6 +42,22 @@ TEXT ·mmap(SB),7,$0 ...@@ -42,6 +42,22 @@ TEXT ·mmap(SB),7,$0
CALL notok(SB) CALL notok(SB)
RET RET
// void gettime(int64 *sec, int32 *usec)
TEXT gettime(SB), 7, $32
LEAL 12(SP), AX // must be non-nil, unused
MOVL AX, 4(SP)
MOVL $0, 8(SP) // time zone pointer
MOVL $116, AX
INT $0x80
MOVL sec+0(FP), DI
MOVL AX, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64
MOVL usec+4(FP), DI
MOVL DX, (DI)
RET
TEXT sigaction(SB),7,$0 TEXT sigaction(SB),7,$0
MOVL $46, AX MOVL $46, AX
INT $0x80 INT $0x80
......
...@@ -37,6 +37,18 @@ TEXT write(SB),7,$0 ...@@ -37,6 +37,18 @@ TEXT write(SB),7,$0
CALL notok(SB) CALL notok(SB)
RET RET
// void gettime(int64 *sec, int32 *usec)
TEXT gettime(SB), 7, $32
MOVQ SP, DI // must be non-nil, unused
MOVQ $0, SI
MOVQ $(0x2000000+116), AX
SYSCALL
MOVQ sec+0(FP), DI
MOVQ AX, (DI)
MOVQ usec+8(FP), DI
MOVL DX, (DI)
RET
TEXT sigaction(SB),7,$0 TEXT sigaction(SB),7,$0
MOVL 8(SP), DI // arg 1 sig MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act MOVQ 16(SP), SI // arg 2 act
...@@ -226,4 +238,3 @@ TEXT mach_semaphore_signal_all(SB),7,$0 ...@@ -226,4 +238,3 @@ TEXT mach_semaphore_signal_all(SB),7,$0
MOVL $(0x1000000+34), AX // semaphore_signal_all_trap MOVL $(0x1000000+34), AX // semaphore_signal_all_trap
SYSCALL SYSCALL
RET RET
...@@ -73,13 +73,22 @@ func Siginit() ...@@ -73,13 +73,22 @@ func Siginit()
type MemStatsType struct { type MemStatsType struct {
Alloc uint64 Alloc uint64
TotalAlloc uint64
Sys uint64 Sys uint64
Stacks uint64 Stacks uint64
InusePages uint64 InusePages uint64
NextGC uint64 NextGC uint64
Lookups uint64 Lookups uint64
Mallocs uint64 Mallocs uint64
PauseNs uint64
NumGC uint32
EnableGC bool EnableGC bool
DebugGC bool
BySize [67]struct {
Size uint32
Mallocs uint64
Frees uint64
}
} }
// MemStats holds statistics about the memory system. // MemStats holds statistics about the memory system.
......
...@@ -73,6 +73,23 @@ TEXT ·mmap(SB),7,$-4 ...@@ -73,6 +73,23 @@ TEXT ·mmap(SB),7,$-4
CALL notok(SB) CALL notok(SB)
RET RET
TEXT gettime(SB), 7, $32
MOVL $116, AX
LEAL 12(SP), BX
MOVL BX, 4(SP)
MOVL $0, 8(SP)
INT $0x80
MOVL 12(SP), BX // sec
MOVL sec+0(FP), DI
MOVL BX, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64 bits
MOVL 16(SP), BX // usec
MOVL usec+4(FP), DI
MOVL BX, (DI)
RET
TEXT sigaction(SB),7,$-4 TEXT sigaction(SB),7,$-4
MOVL $416, AX MOVL $416, AX
INT $0x80 INT $0x80
......
...@@ -58,6 +58,21 @@ TEXT write(SB),7,$-8 ...@@ -58,6 +58,21 @@ TEXT write(SB),7,$-8
CALL notok(SB) CALL notok(SB)
RET RET
TEXT gettime(SB), 7, $32
MOVL $116, AX
LEAQ 8(SP), DI
SYSCALL
MOVQ 8(SP), BX // sec
MOVQ sec+0(FP), DI
MOVQ BX, (DI)
MOVL 16(SP), BX // usec
MOVQ usec+8(FP), DI
MOVL BX, (DI)
RET
TEXT sigaction(SB),7,$-8 TEXT sigaction(SB),7,$-8
MOVL 8(SP), DI // arg 1 sig MOVL 8(SP), DI // arg 1 sig
MOVQ 16(SP), SI // arg 2 act MOVQ 16(SP), SI // arg 2 act
......
...@@ -30,6 +30,23 @@ TEXT write(SB),7,$0 ...@@ -30,6 +30,23 @@ TEXT write(SB),7,$0
INT $0x80 INT $0x80
RET RET
TEXT gettime(SB), 7, $32
MOVL $78, AX // syscall - gettimeofday
LEAL 8(SP), BX
MOVL $0, CX
MOVL $0, DX
INT $0x80
MOVL 8(SP), BX // sec
MOVL sec+0(FP), DI
MOVL BX, (DI)
MOVL $0, 4(DI) // zero extend 32 -> 64 bits
MOVL 12(SP), BX // usec
MOVL usec+4(FP), DI
MOVL BX, (DI)
RET
TEXT rt_sigaction(SB),7,$0 TEXT rt_sigaction(SB),7,$0
MOVL $174, AX // syscall - rt_sigaction MOVL $174, AX // syscall - rt_sigaction
MOVL 4(SP), BX MOVL 4(SP), BX
......
...@@ -44,6 +44,21 @@ TEXT ·write(SB),7,$0-24 ...@@ -44,6 +44,21 @@ TEXT ·write(SB),7,$0-24
SYSCALL SYSCALL
RET RET
TEXT gettime(SB), 7, $32
LEAQ 8(SP), DI
MOVQ $0, SI
MOVQ $0xffffffffff600000, AX
CALL AX
MOVQ 8(SP), BX // sec
MOVQ sec+0(FP), DI
MOVQ BX, (DI)
MOVL 16(SP), BX // usec
MOVQ usec+8(FP), DI
MOVL BX, (DI)
RET
TEXT rt_sigaction(SB),7,$0-32 TEXT rt_sigaction(SB),7,$0-32
MOVL 8(SP), DI MOVL 8(SP), DI
MOVQ 16(SP), SI MOVQ 16(SP), SI
......
...@@ -46,6 +46,8 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc) ...@@ -46,6 +46,8 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc)
if(v == nil) if(v == nil)
throw("out of memory"); throw("out of memory");
mstats.alloc += size; mstats.alloc += size;
mstats.total_alloc += size;
mstats.by_size[sizeclass].nmalloc++;
} else { } else {
// TODO(rsc): Report tracebacks for very large allocations. // TODO(rsc): Report tracebacks for very large allocations.
...@@ -57,6 +59,7 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc) ...@@ -57,6 +59,7 @@ mallocgc(uintptr size, uint32 refflag, int32 dogc)
if(s == nil) if(s == nil)
throw("out of memory"); throw("out of memory");
mstats.alloc += npages<<PageShift; mstats.alloc += npages<<PageShift;
mstats.total_alloc += npages<<PageShift;
v = (void*)(s->start << PageShift); v = (void*)(s->start << PageShift);
} }
...@@ -127,6 +130,7 @@ free(void *v) ...@@ -127,6 +130,7 @@ free(void *v)
size = class_to_size[sizeclass]; size = class_to_size[sizeclass];
runtime_memclr(v, size); runtime_memclr(v, size);
mstats.alloc -= size; mstats.alloc -= size;
mstats.by_size[sizeclass].nfree++;
MCache_Free(c, v, sizeclass, size); MCache_Free(c, v, sizeclass, size);
out: out:
......
...@@ -156,17 +156,26 @@ void FixAlloc_Free(FixAlloc *f, void *p); ...@@ -156,17 +156,26 @@ void FixAlloc_Free(FixAlloc *f, void *p);
// Statistics. // Statistics.
// Shared with Go: if you edit this structure, also edit ../malloc/malloc.go. // Shared with Go: if you edit this structure, also edit extern.go.
struct MStats struct MStats
{ {
uint64 alloc; uint64 alloc;
uint64 total_alloc;
uint64 sys; uint64 sys;
uint64 stacks; uint64 stacks;
uint64 inuse_pages; // protected by mheap.Lock uint64 inuse_pages; // protected by mheap.Lock
uint64 next_gc; // protected by mheap.Lock uint64 next_gc; // protected by mheap.Lock
uint64 nlookup; // unprotected (approximate) uint64 nlookup; // unprotected (approximate)
uint64 nmalloc; // unprotected (approximate) uint64 nmalloc; // unprotected (approximate)
uint64 pause_ns;
uint32 numgc;
bool enablegc; bool enablegc;
bool debuggc;
struct {
uint32 size;
uint64 nmalloc;
uint64 nfree;
} by_size[NumSizeClasses];
}; };
#define mstats ·MemStats /* name shared with Go */ #define mstats ·MemStats /* name shared with Go */
......
...@@ -240,6 +240,7 @@ static int32 gcpercent = -2; ...@@ -240,6 +240,7 @@ static int32 gcpercent = -2;
void void
gc(int32 force) gc(int32 force)
{ {
int64 t0, t1;
byte *p; byte *p;
void **fp; void **fp;
...@@ -268,6 +269,7 @@ gc(int32 force) ...@@ -268,6 +269,7 @@ gc(int32 force)
//printf("gc...\n"); //printf("gc...\n");
semacquire(&gcsema); semacquire(&gcsema);
t0 = nanotime();
m->gcing = 1; m->gcing = 1;
stoptheworld(); stoptheworld();
if(mheap.Lock.key != 0) if(mheap.Lock.key != 0)
...@@ -289,6 +291,11 @@ gc(int32 force) ...@@ -289,6 +291,11 @@ gc(int32 force)
pfinq = finq; pfinq = finq;
m->locks--; m->locks--;
t1 = nanotime();
mstats.numgc++;
mstats.pause_ns += t1 - t0;
if(mstats.debuggc)
printf("pause %D\n", t1-t0);
semrelease(&gcsema); semrelease(&gcsema);
starttheworld(); starttheworld();
} }
...@@ -134,6 +134,10 @@ InitSizes(void) ...@@ -134,6 +134,10 @@ InitSizes(void)
} }
} }
// Copy out for statistics table.
for(i=0; i<nelem(class_to_size); i++)
mstats.by_size[i].size = class_to_size[i];
// Initialize the class_to_transfercount table. // Initialize the class_to_transfercount table.
for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) { for(sizeclass = 1; sizeclass < NumSizeClasses; sizeclass++) {
n = 64*1024 / class_to_size[sizeclass]; n = 64*1024 / class_to_size[sizeclass];
......
...@@ -461,3 +461,14 @@ FLUSH(void *v) ...@@ -461,3 +461,14 @@ FLUSH(void *v)
USED(v); USED(v);
} }
int64
nanotime(void)
{
int64 sec;
int32 usec;
sec = 0;
usec = 0;
gettime(&sec, &usec);
return sec*1000000000 + (int64)usec*1000;
}
...@@ -393,6 +393,8 @@ void ·exitsyscall(void); ...@@ -393,6 +393,8 @@ void ·exitsyscall(void);
void ·newproc(int32, byte*, byte*); void ·newproc(int32, byte*, byte*);
void siginit(void); void siginit(void);
bool sigsend(int32 sig); bool sigsend(int32 sig);
void gettime(int64*, int32*);
int64 nanotime(void);
#pragma varargck argpos printf 1 #pragma varargck argpos printf 1
......
// Copyright 2010 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.
// Garbage collection benchmark: parse Go packages repeatedly.
package main
import (
"flag"
"fmt"
"go/ast"
"go/parser"
"os"
"path"
"runtime"
"strings"
)
func isGoFile(dir *os.Dir) bool {
return dir.IsRegular() &&
!strings.HasPrefix(dir.Name, ".") && // ignore .files
path.Ext(dir.Name) == ".go"
}
func isPkgFile(dir *os.Dir) bool {
return isGoFile(dir) &&
!strings.HasSuffix(dir.Name, "_test.go") // ignore test files
}
func pkgName(filename string) string {
file, err := parser.ParseFile(filename, nil, nil, parser.PackageClauseOnly)
if err != nil || file == nil {
return ""
}
return file.Name.Name()
}
func parseDir(dirpath string) map[string]*ast.Package {
// the package name is the directory name within its parent
// (use dirname instead of path because dirname is clean; i.e. has no trailing '/')
_, pkgname := path.Split(dirpath)
// filter function to select the desired .go files
filter := func(d *os.Dir) bool {
if isPkgFile(d) {
// Some directories contain main packages: Only accept
// files that belong to the expected package so that
// parser.ParsePackage doesn't return "multiple packages
// found" errors.
// Additionally, accept the special package name
// fakePkgName if we are looking at cmd documentation.
name := pkgName(dirpath + "/" + d.Name)
return name == pkgname
}
return false
}
// get package AST
pkgs, err := parser.ParseDir(dirpath, filter, parser.ParseComments)
if err != nil {
panicln("parse", dirpath, err.String())
}
return pkgs
}
func main() {
st := &runtime.MemStats
n := flag.Int("n", 10, "iterations")
p := flag.Int("p", len(packages), "# of packages to keep in memory")
flag.BoolVar(&st.DebugGC, "d", st.DebugGC, "print GC debugging info (pause times)")
flag.Parse()
pkgroot := os.Getenv("GOROOT") + "/src/pkg/"
for i := -1; i < *n; i++ {
parsed := make([]map[string]*ast.Package, *p)
for j := range parsed {
parsed[j] = parseDir(pkgroot + packages[j%len(packages)])
}
if i == -1 {
// Now that heap is grown to full size, reset counters.
// This hides the start-up pauses, which are much smaller
// than the normal pauses and would otherwise make
// the average look much better than it actually is.
st.NumGC = 0
st.PauseNs = 0
}
}
fmt.Printf("Alloc=%d/%d Heap=%d/%d Mallocs=%d PauseTime=%.3f/%d = %.3f\n",
st.Alloc, st.TotalAlloc,
st.InusePages<<12, st.Sys,
st.Mallocs, float64(st.PauseNs)/1e9,
st.NumGC, float64(st.PauseNs)/1e9/float64(st.NumGC))
fmt.Printf("%10s %10s %10s\n", "size", "#alloc", "#free")
for _, s := range st.BySize {
fmt.Printf("%10d %10d %10d\n", s.Size, s.Mallocs, s.Frees)
}
}
var packages = []string{
"archive/tar",
"asn1",
"big",
"bignum",
"bufio",
"bytes",
"compress/flate",
"compress/gzip",
"compress/zlib",
"container/heap",
"container/list",
"container/ring",
"container/vector",
"crypto/aes",
"crypto/block",
"crypto/hmac",
"crypto/md4",
"crypto/md5",
"crypto/rc4",
"crypto/rsa",
"crypto/sha1",
"crypto/sha256",
"crypto/subtle",
"crypto/tls",
"crypto/x509",
"crypto/xtea",
"debug/dwarf",
"debug/macho",
"debug/elf",
"debug/gosym",
"debug/proc",
"ebnf",
"encoding/ascii85",
"encoding/base64",
"encoding/binary",
"encoding/git85",
"encoding/hex",
"encoding/pem",
"exec",
"exp/datafmt",
"exp/draw",
"exp/eval",
"exp/exception",
"exp/iterable",
"exp/parser",
"expvar",
"flag",
"fmt",
"go/ast",
"go/doc",
"go/parser",
"go/printer",
"go/scanner",
"go/token",
"gob",
"hash",
"hash/adler32",
"hash/crc32",
"http",
"image",
"image/jpeg",
"image/png",
"io",
"io/ioutil",
"json",
"log",
"math",
"net",
"once",
"os",
"os/signal",
"patch",
"path",
"rand",
"reflect",
"regexp",
"rpc",
"runtime",
"scanner",
"sort",
"strconv",
"strings",
"sync",
"syscall",
"syslog",
"tabwriter",
"template",
"testing",
"testing/iotest",
"testing/quick",
"testing/script",
"time",
"unicode",
"utf8",
"websocket",
"xgb",
"xml",
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment