Created
June 13, 2018 18:15
-
-
Save burakguven/22ed71598fd9f0f963a12aaf22c19111 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// runoutput | |
// Copyright 2018 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. | |
// Generate a program that tests independent goroutines modifying | |
// a comprehensive variety of vars during aggressive garbage collection. | |
// The output of this program is run to do the actual test. | |
// The point is to catch GC regressions like fixedbugs/issue22781.go | |
package main | |
import ( | |
"fmt" | |
"os" | |
"text/template" | |
) | |
func main() { | |
fmt.Print(header) | |
printTypes() | |
fmt.Print(footer) | |
} | |
func printTypes() { | |
fmt.Print("\nvar types = []modifier{\n") | |
fmt.Print(boolModifier) | |
// sized int | |
for _, prefix := range []string{"uint", "int"} { | |
for logBits := uint(3); logBits <= 6; logBits++ { | |
mustExec(numTemplate, fmt.Sprintf("%s%d", prefix, 1<<logBits)) | |
} | |
} | |
// float | |
for _, typ := range []string{"float32", "float64"} { | |
mustExec(floatTemplate, typ) | |
} | |
// complex | |
for _, typ := range []struct{ C, F string }{ | |
{"complex64", "float32"}, | |
{"complex128", "float64"}, | |
} { | |
mustExec(complexTemplate, typ) | |
} | |
// misc. numeric | |
for _, typ := range []string{"byte", "rune", "uint", "int", "uintptr"} { | |
mustExec(numTemplate, typ) | |
} | |
fmt.Print(stringModifier) | |
fmt.Print(structModifier) | |
fmt.Print("}\n") | |
} | |
func mustExec(t *template.Template, data interface{}) { | |
err := t.Execute(os.Stdout, data) | |
if err != nil { | |
panic("mustExec: " + err.Error()) | |
} | |
} | |
var header = `// Generated by gengcgort.go; DO NOT EDIT | |
package main | |
import ( | |
"errors" | |
"runtime" | |
"runtime/debug" | |
"sync" | |
) | |
const ( | |
goroutines = 8 | |
allocs = 8 | |
mods = 8 | |
length = 9 | |
) | |
func main() { | |
debug.SetGCPercent(1) | |
var wg sync.WaitGroup | |
for i := 0; i < goroutines; i++ { | |
for _, t := range types { | |
err := t.valid() | |
if err != nil { | |
panic(err) | |
} | |
wg.Add(1) | |
go func(f modifier) { | |
var wg2 sync.WaitGroup | |
for j := 0; j < allocs; j++ { | |
wg2.Add(1) | |
go func() { | |
f.t() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.pointerT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.arrayT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.sliceT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.mapT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.mapPointerKeyT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.chanT() | |
wg2.Done() | |
}() | |
wg2.Add(1) | |
go func() { | |
f.interfaceT() | |
wg2.Done() | |
}() | |
} | |
wg2.Wait() | |
wg.Done() | |
}(t) | |
} | |
} | |
wg.Wait() | |
} | |
type modifier struct { | |
name string | |
t func() | |
pointerT func() | |
arrayT func() | |
sliceT func() | |
mapT func() | |
mapPointerKeyT func() | |
chanT func() | |
interfaceT func() | |
} | |
func (a modifier) valid() error { | |
switch { | |
case a.name == "": | |
return errors.New("modifier without name") | |
case a.t == nil: | |
return errors.New(a.name + " missing t") | |
case a.pointerT == nil: | |
return errors.New(a.name + " missing pointerT") | |
case a.arrayT == nil: | |
return errors.New(a.name + " missing arrayT") | |
case a.sliceT == nil: | |
return errors.New(a.name + " missing sliceT") | |
case a.mapT == nil: | |
return errors.New(a.name + " missing mapT") | |
case a.mapPointerKeyT == nil: | |
return errors.New(a.name + " missing mapPointerKeyT") | |
case a.chanT == nil: | |
return errors.New(a.name + " missing chanT") | |
case a.interfaceT == nil: | |
return errors.New(a.name + " missing interfaceT") | |
default: | |
return nil | |
} | |
} | |
` | |
var footer = `type structT struct { | |
u8 uint8 | |
u16 uint16 | |
u32 uint32 | |
u64 uint64 | |
i8 int8 | |
i16 int16 | |
i32 int32 | |
i64 int64 | |
f32 float32 | |
f64 float64 | |
c64 complex64 | |
c128 complex128 | |
b byte | |
r rune | |
u uint | |
in int | |
uip uintptr | |
s string | |
} | |
func newStructT() structT { | |
return structT{ | |
f32: 1.01, | |
f64: 1.01, | |
c64: complex(float32(1.01), float32(1.01)), | |
c128: complex(float64(1.01), float64(1.01)), | |
} | |
} | |
func str(in int) string { | |
switch in % 3 { | |
case 0: | |
return "Hello" | |
case 1: | |
return "world" | |
case 2: | |
return "!" | |
} | |
return "?" | |
} | |
` | |
var boolModifier = "\t" + `modifier{ | |
name: "bool", | |
t: func() { | |
var a bool | |
for i := 0; i < mods; i++ { | |
a = !a | |
runtime.Gosched() | |
} | |
}, | |
pointerT: func() { | |
a := func() *bool { return new(bool) }() | |
for i := 0; i < mods; i++ { | |
*a = !*a | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]bool{} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] = !a[j] | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]bool, length) | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] = !a[j] | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[bool]bool) | |
for i := 0; i < mods; i++ { | |
a[false] = !a[false] | |
a[true] = !a[true] | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*bool]bool) | |
for i := 0; i < length; i++ { | |
a[new(bool)] = false | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, v := range a { | |
a[k] = !v | |
runtime.Gosched() | |
} | |
} | |
}, | |
chanT: func() { | |
a := make(chan bool) | |
for i := 0; i < mods; i++ { | |
go func() { a <- false }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}(bool(false)) | |
for i := 0; i < mods; i++ { | |
a = !a.(bool) | |
runtime.Gosched() | |
} | |
}, | |
}, | |
` | |
var numTemplate = template.Must(template.New("int").Parse("\t" + `modifier{ | |
name: "{{.}}", | |
t: func() { | |
var u {{.}} | |
for i := 0; i < mods; i++ { | |
u++ | |
runtime.Gosched() | |
} | |
}, | |
pointerT: func() { | |
a := func() *{{.}} { return new({{.}}) }() | |
for i := 0; i < mods; i++ { | |
*a++ | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]{{.}}{} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j]++ | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]{{.}}, length) | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j]++ | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[{{.}}]{{.}}) | |
for i := 0; i < length; i++ { | |
a[{{.}}(i)] = {{.}}(i) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k]++ | |
} | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*{{.}}]{{.}}) | |
for i := 0; i < length; i++ { | |
a[new({{.}})] = {{.}}(i) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k]++ | |
runtime.Gosched() | |
} | |
} | |
}, | |
chanT: func() { | |
a := make(chan {{.}}) | |
for i := 0; i < mods; i++ { | |
go func() { a <- {{.}}(i) }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}({{.}}(0)) | |
for i := 0; i < mods; i++ { | |
a = a.({{.}}) + 1 | |
runtime.Gosched() | |
} | |
}, | |
}, | |
`)) | |
var floatTemplate = template.Must(template.New("float").Parse("\t" + `modifier{ | |
name: "{{.}}", | |
t: func() { | |
u := {{.}}(1.01) | |
for i := 0; i < mods; i++ { | |
u *= 1.01 | |
runtime.Gosched() | |
} | |
}, | |
pointerT: func() { | |
a := func() *{{.}} { return new({{.}}) }() | |
*a = 1.01 | |
for i := 0; i < mods; i++ { | |
*a *= 1.01 | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]{{.}}{} | |
for i := 0; i < length; i++ { | |
a[i] = {{.}}(1.01) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] *= 1.01 | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]{{.}}, length) | |
for i := 0; i < length; i++ { | |
a[i] = {{.}}(1.01) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] *= 1.01 | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[{{.}}]{{.}}) | |
for i := 0; i < length; i++ { | |
a[{{.}}(i)] = {{.}}(i) + 0.01 | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] *= 1.01 | |
} | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*{{.}}]{{.}}) | |
for i := 0; i < length; i++ { | |
a[new({{.}})] = {{.}}(i) + 0.01 | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] *= 1.01 | |
runtime.Gosched() | |
} | |
} | |
}, | |
chanT: func() { | |
a := make(chan {{.}}) | |
for i := 0; i < mods; i++ { | |
go func() { a <- {{.}}(i) }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}({{.}}(0)) | |
for i := 0; i < mods; i++ { | |
a = a.({{.}}) * 1.01 | |
runtime.Gosched() | |
} | |
}, | |
}, | |
`)) | |
var complexTemplate = template.Must(template.New("complex").Parse("\t" + `modifier{ | |
name: "{{.C}}", | |
t: func() { | |
c := {{.C}}(complex({{.F}}(1.01), {{.F}}(1.01))) | |
for i := 0; i < mods; i++ { | |
c = complex(real(c)*1.01, imag(c)*1.01) | |
runtime.Gosched() | |
} | |
}, | |
pointerT: func() { | |
a := func() *{{.C}} { return new({{.C}}) }() | |
*a = {{.C}}(complex({{.F}}(1.01), {{.F}}(1.01))) | |
for i := 0; i < mods; i++ { | |
*a *= complex(real(*a)*1.01, imag(*a)*1.01) | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]{{.C}}{} | |
for i := 0; i < length; i++ { | |
a[i] = {{.C}}(complex({{.F}}(1.01), {{.F}}(1.01))) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] *= complex(real(a[j])*1.01, imag(a[j])*1.01) | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]{{.C}}, length) | |
for i := 0; i < length; i++ { | |
a[i] = {{.C}}(complex({{.F}}(1.01), {{.F}}(1.01))) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] *= complex(real(a[j])*1.01, imag(a[j])*1.01) | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[{{.C}}]{{.C}}) | |
for i := 0; i < length; i++ { | |
a[{{.C}}(complex({{.F}}(i), {{.F}}(i)))] = {{.C}}(complex({{.F}}(i), {{.F}}(i))) + 0.01 | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] *= complex(real(a[k])*1.01, imag(a[k])*1.01) | |
} | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*{{.C}}]{{.C}}) | |
for i := 0; i < length; i++ { | |
a[new({{.C}})] = {{.C}}(complex({{.F}}(i), {{.F}}(i))) + 0.01 | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] *= complex(real(a[k])*1.01, imag(a[k])*1.01) | |
runtime.Gosched() | |
} | |
} | |
}, | |
chanT: func() { | |
a := make(chan {{.C}}) | |
for i := 0; i < mods; i++ { | |
go func() { a <- {{.C}}(complex({{.F}}(i), {{.F}}(i))) }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}({{.C}}(complex({{.F}}(1.01), {{.F}}(1.01)))) | |
for i := 0; i < mods; i++ { | |
a = a.({{.C}}) * complex(real(a.({{.C}}))*1.01, imag(a.({{.C}}))*1.01) | |
runtime.Gosched() | |
} | |
}, | |
}, | |
`)) | |
var stringModifier = "\t" + `modifier{ | |
name: "string", | |
t: func() { | |
var s string | |
f := func(a string) string { return a } | |
for i := 0; i < mods; i++ { | |
s = str(i) | |
s = f(s) | |
} | |
}, | |
pointerT: func() { | |
a := func() *string { return new(string) }() | |
for i := 0; i < mods; i++ { | |
*a = str(i) | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]string{} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] = str(i) | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]string, length) | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j] = str(i) | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[string]string) | |
for i := 0; i < length; i++ { | |
a[string(i)] = str(i) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] = str(i) | |
} | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*string]string) | |
for i := 0; i < length; i++ { | |
a[new(string)] = str(i) | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for k, _ := range a { | |
a[k] = str(i) | |
runtime.Gosched() | |
} | |
} | |
}, | |
chanT: func() { | |
a := make(chan string) | |
for i := 0; i < mods; i++ { | |
go func() { a <- str(i) }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}(str(0)) | |
f := func(a string) string { return a } | |
for i := 0; i < mods; i++ { | |
a = str(i) | |
a = f(a.(string)) | |
runtime.Gosched() | |
} | |
}, | |
}, | |
` | |
var structModifier = "\t" + `modifier{ | |
name: "structT", | |
t: func() { | |
s := newStructT() | |
for i := 0; i < mods; i++ { | |
s.u8++ | |
s.u16++ | |
s.u32++ | |
s.u64++ | |
s.i8++ | |
s.i16++ | |
s.i32++ | |
s.i64++ | |
s.f32 *= 1.01 | |
s.f64 *= 1.01 | |
s.c64 = complex(real(s.c64)*1.01, imag(s.c64)*1.01) | |
s.c128 = complex(real(s.c128)*1.01, imag(s.c128)*1.01) | |
s.b++ | |
s.r++ | |
s.u++ | |
s.in++ | |
s.uip++ | |
s.s = str(i) | |
runtime.Gosched() | |
} | |
}, | |
pointerT: func() { | |
s := func() *structT { | |
t := newStructT() | |
return &t | |
}() | |
for i := 0; i < mods; i++ { | |
s.u8++ | |
s.u16++ | |
s.u32++ | |
s.u64++ | |
s.i8++ | |
s.i16++ | |
s.i32++ | |
s.i64++ | |
s.f32 *= 1.01 | |
s.f64 *= 1.01 | |
s.c64 = complex(real(s.c64)*1.01, imag(s.c64)*1.01) | |
s.c128 = complex(real(s.c128)*1.01, imag(s.c128)*1.01) | |
s.b++ | |
s.r++ | |
s.u++ | |
s.in++ | |
s.uip++ | |
s.s = str(i) | |
runtime.Gosched() | |
} | |
}, | |
arrayT: func() { | |
a := [length]structT{} | |
for i := 0; i < len(a); i++ { | |
a[i] = newStructT() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j].u8++ | |
a[j].u16++ | |
a[j].u32++ | |
a[j].u64++ | |
a[j].i8++ | |
a[j].i16++ | |
a[j].i32++ | |
a[j].i64++ | |
a[j].f32 *= 1.01 | |
a[j].f64 *= 1.01 | |
a[j].c64 = complex(real(a[j].c64)*1.01, imag(a[j].c64)*1.01) | |
a[j].c128 = complex(real(a[j].c128)*1.01, imag(a[j].c128)*1.01) | |
a[j].b++ | |
a[j].r++ | |
a[j].u++ | |
a[j].in++ | |
a[j].uip++ | |
a[j].s = str(i) | |
runtime.Gosched() | |
} | |
} | |
}, | |
sliceT: func() { | |
a := make([]structT, length) | |
for i := 0; i < len(a); i++ { | |
a[i] = newStructT() | |
} | |
for i := 0; i < mods; i++ { | |
for j := 0; j < len(a); j++ { | |
a[j].u8++ | |
a[j].u16++ | |
a[j].u32++ | |
a[j].u64++ | |
a[j].i8++ | |
a[j].i16++ | |
a[j].i32++ | |
a[j].i64++ | |
a[j].f32 *= 1.01 | |
a[j].f64 *= 1.01 | |
a[j].c64 = complex(real(a[j].c64)*1.01, imag(a[j].c64)*1.01) | |
a[j].c128 = complex(real(a[j].c128)*1.01, imag(a[j].c128)*1.01) | |
a[j].b++ | |
a[j].r++ | |
a[j].u++ | |
a[j].in++ | |
a[j].uip++ | |
a[j].s = str(i) | |
runtime.Gosched() | |
} | |
} | |
}, | |
mapT: func() { | |
a := make(map[structT]structT) | |
for i := 0; i < length; i++ { | |
m := newStructT() | |
m.in = i | |
a[m] = newStructT() | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j, _ := range a { | |
m := a[j] | |
m.u8++ | |
m.u16++ | |
m.u32++ | |
m.u64++ | |
m.i8++ | |
m.i16++ | |
m.i32++ | |
m.i64++ | |
m.f32 *= 1.01 | |
m.f64 *= 1.01 | |
m.c64 = complex(real(a[j].c64)*1.01, imag(a[j].c64)*1.01) | |
m.c128 = complex(real(a[j].c128)*1.01, imag(a[j].c128)*1.01) | |
m.b++ | |
m.r++ | |
m.u++ | |
m.in++ | |
m.uip++ | |
m.s = str(i) | |
a[j] = m | |
runtime.Gosched() | |
} | |
runtime.Gosched() | |
} | |
}, | |
mapPointerKeyT: func() { | |
a := make(map[*structT]structT) | |
f := func() *structT { | |
m := newStructT() | |
return &m | |
} | |
for i := 0; i < length; i++ { | |
m := f() | |
m.in = i | |
a[m] = newStructT() | |
runtime.Gosched() | |
} | |
for i := 0; i < mods; i++ { | |
for j, _ := range a { | |
m := a[j] | |
m.u8++ | |
m.u16++ | |
m.u32++ | |
m.u64++ | |
m.i8++ | |
m.i16++ | |
m.i32++ | |
m.i64++ | |
m.f32 *= 1.01 | |
m.f64 *= 1.01 | |
m.c64 = complex(real(a[j].c64)*1.01, imag(a[j].c64)*1.01) | |
m.c128 = complex(real(a[j].c128)*1.01, imag(a[j].c128)*1.01) | |
m.b++ | |
m.r++ | |
m.u++ | |
m.in++ | |
m.uip++ | |
m.s = str(i) | |
a[j] = m | |
runtime.Gosched() | |
} | |
runtime.Gosched() | |
} | |
}, | |
chanT: func() { | |
a := make(chan structT) | |
for i := 0; i < mods; i++ { | |
go func() { a <- newStructT() }() | |
<-a | |
runtime.Gosched() | |
} | |
}, | |
interfaceT: func() { | |
a := interface{}(newStructT()) | |
for i := 0; i < mods; i++ { | |
a = a.(structT) | |
runtime.Gosched() | |
} | |
}, | |
}, | |
` |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment