be47d6ecef
From-SVN: r200974
286 lines
5.5 KiB
Go
286 lines
5.5 KiB
Go
// Copyright 2011 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 runtime_test
|
|
|
|
import (
|
|
"math"
|
|
"runtime"
|
|
"sync/atomic"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var stop = make(chan bool, 1)
|
|
|
|
func perpetuumMobile() {
|
|
select {
|
|
case <-stop:
|
|
default:
|
|
go perpetuumMobile()
|
|
}
|
|
}
|
|
|
|
func TestStopTheWorldDeadlock(t *testing.T) {
|
|
if testing.Short() {
|
|
t.Skip("skipping during short test")
|
|
}
|
|
maxprocs := runtime.GOMAXPROCS(3)
|
|
compl := make(chan bool, 2)
|
|
go func() {
|
|
for i := 0; i != 1000; i += 1 {
|
|
runtime.GC()
|
|
}
|
|
compl <- true
|
|
}()
|
|
go func() {
|
|
for i := 0; i != 1000; i += 1 {
|
|
runtime.GOMAXPROCS(3)
|
|
}
|
|
compl <- true
|
|
}()
|
|
go perpetuumMobile()
|
|
<-compl
|
|
<-compl
|
|
stop <- true
|
|
runtime.GOMAXPROCS(maxprocs)
|
|
}
|
|
|
|
func TestYieldProgress(t *testing.T) {
|
|
testYieldProgress(t, false)
|
|
}
|
|
|
|
func TestYieldLockedProgress(t *testing.T) {
|
|
testYieldProgress(t, true)
|
|
}
|
|
|
|
func testYieldProgress(t *testing.T, locked bool) {
|
|
c := make(chan bool)
|
|
cack := make(chan bool)
|
|
go func() {
|
|
if locked {
|
|
runtime.LockOSThread()
|
|
}
|
|
for {
|
|
select {
|
|
case <-c:
|
|
cack <- true
|
|
return
|
|
default:
|
|
runtime.Gosched()
|
|
}
|
|
}
|
|
}()
|
|
time.Sleep(10 * time.Millisecond)
|
|
c <- true
|
|
<-cack
|
|
}
|
|
|
|
func TestYieldLocked(t *testing.T) {
|
|
const N = 10
|
|
c := make(chan bool)
|
|
go func() {
|
|
runtime.LockOSThread()
|
|
for i := 0; i < N; i++ {
|
|
runtime.Gosched()
|
|
time.Sleep(time.Millisecond)
|
|
}
|
|
c <- true
|
|
// runtime.UnlockOSThread() is deliberately omitted
|
|
}()
|
|
<-c
|
|
}
|
|
|
|
func TestBlockLocked(t *testing.T) {
|
|
const N = 10
|
|
c := make(chan bool)
|
|
go func() {
|
|
runtime.LockOSThread()
|
|
for i := 0; i < N; i++ {
|
|
c <- true
|
|
}
|
|
runtime.UnlockOSThread()
|
|
}()
|
|
for i := 0; i < N; i++ {
|
|
<-c
|
|
}
|
|
}
|
|
|
|
func stackGrowthRecursive(i int) {
|
|
var pad [128]uint64
|
|
if i != 0 && pad[0] == 0 {
|
|
stackGrowthRecursive(i - 1)
|
|
}
|
|
}
|
|
|
|
func TestSchedLocalQueue(t *testing.T) {
|
|
runtime.TestSchedLocalQueue1()
|
|
}
|
|
|
|
func TestSchedLocalQueueSteal(t *testing.T) {
|
|
runtime.TestSchedLocalQueueSteal1()
|
|
}
|
|
|
|
func benchmarkStackGrowth(b *testing.B, rec int) {
|
|
const CallsPerSched = 1000
|
|
procs := runtime.GOMAXPROCS(-1)
|
|
N := int32(b.N / CallsPerSched)
|
|
c := make(chan bool, procs)
|
|
for p := 0; p < procs; p++ {
|
|
go func() {
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
runtime.Gosched()
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
stackGrowthRecursive(rec)
|
|
}
|
|
}
|
|
c <- true
|
|
}()
|
|
}
|
|
for p := 0; p < procs; p++ {
|
|
<-c
|
|
}
|
|
}
|
|
|
|
func BenchmarkStackGrowth(b *testing.B) {
|
|
benchmarkStackGrowth(b, 10)
|
|
}
|
|
|
|
func BenchmarkStackGrowthDeep(b *testing.B) {
|
|
benchmarkStackGrowth(b, 1024)
|
|
}
|
|
|
|
func BenchmarkSyscall(b *testing.B) {
|
|
benchmarkSyscall(b, 0, 1)
|
|
}
|
|
|
|
func BenchmarkSyscallWork(b *testing.B) {
|
|
benchmarkSyscall(b, 100, 1)
|
|
}
|
|
|
|
func BenchmarkSyscallExcess(b *testing.B) {
|
|
benchmarkSyscall(b, 0, 4)
|
|
}
|
|
|
|
func BenchmarkSyscallExcessWork(b *testing.B) {
|
|
benchmarkSyscall(b, 100, 4)
|
|
}
|
|
|
|
func benchmarkSyscall(b *testing.B, work, excess int) {
|
|
const CallsPerSched = 1000
|
|
procs := runtime.GOMAXPROCS(-1) * excess
|
|
N := int32(b.N / CallsPerSched)
|
|
c := make(chan bool, procs)
|
|
for p := 0; p < procs; p++ {
|
|
go func() {
|
|
foo := 42
|
|
for atomic.AddInt32(&N, -1) >= 0 {
|
|
runtime.Gosched()
|
|
for g := 0; g < CallsPerSched; g++ {
|
|
runtime.Entersyscall()
|
|
for i := 0; i < work; i++ {
|
|
foo *= 2
|
|
foo /= 2
|
|
}
|
|
runtime.Exitsyscall()
|
|
}
|
|
}
|
|
c <- foo == 42
|
|
}()
|
|
}
|
|
for p := 0; p < procs; p++ {
|
|
<-c
|
|
}
|
|
}
|
|
|
|
func BenchmarkCreateGoroutines(b *testing.B) {
|
|
benchmarkCreateGoroutines(b, 1)
|
|
}
|
|
|
|
func BenchmarkCreateGoroutinesParallel(b *testing.B) {
|
|
benchmarkCreateGoroutines(b, runtime.GOMAXPROCS(-1))
|
|
}
|
|
|
|
func benchmarkCreateGoroutines(b *testing.B, procs int) {
|
|
c := make(chan bool)
|
|
var f func(n int)
|
|
f = func(n int) {
|
|
if n == 0 {
|
|
c <- true
|
|
return
|
|
}
|
|
go f(n - 1)
|
|
}
|
|
for i := 0; i < procs; i++ {
|
|
go f(b.N / procs)
|
|
}
|
|
for i := 0; i < procs; i++ {
|
|
<-c
|
|
}
|
|
}
|
|
|
|
type Matrix [][]float64
|
|
|
|
func BenchmarkMatmult(b *testing.B) {
|
|
b.StopTimer()
|
|
// matmult is O(N**3) but testing expects O(b.N),
|
|
// so we need to take cube root of b.N
|
|
n := int(math.Cbrt(float64(b.N))) + 1
|
|
A := makeMatrix(n)
|
|
B := makeMatrix(n)
|
|
C := makeMatrix(n)
|
|
b.StartTimer()
|
|
matmult(nil, A, B, C, 0, n, 0, n, 0, n, 8)
|
|
}
|
|
|
|
func makeMatrix(n int) Matrix {
|
|
m := make(Matrix, n)
|
|
for i := 0; i < n; i++ {
|
|
m[i] = make([]float64, n)
|
|
for j := 0; j < n; j++ {
|
|
m[i][j] = float64(i*n + j)
|
|
}
|
|
}
|
|
return m
|
|
}
|
|
|
|
func matmult(done chan<- struct{}, A, B, C Matrix, i0, i1, j0, j1, k0, k1, threshold int) {
|
|
di := i1 - i0
|
|
dj := j1 - j0
|
|
dk := k1 - k0
|
|
if di >= dj && di >= dk && di >= threshold {
|
|
// divide in two by y axis
|
|
mi := i0 + di/2
|
|
done1 := make(chan struct{}, 1)
|
|
go matmult(done1, A, B, C, i0, mi, j0, j1, k0, k1, threshold)
|
|
matmult(nil, A, B, C, mi, i1, j0, j1, k0, k1, threshold)
|
|
<-done1
|
|
} else if dj >= dk && dj >= threshold {
|
|
// divide in two by x axis
|
|
mj := j0 + dj/2
|
|
done1 := make(chan struct{}, 1)
|
|
go matmult(done1, A, B, C, i0, i1, j0, mj, k0, k1, threshold)
|
|
matmult(nil, A, B, C, i0, i1, mj, j1, k0, k1, threshold)
|
|
<-done1
|
|
} else if dk >= threshold {
|
|
// divide in two by "k" axis
|
|
// deliberately not parallel because of data races
|
|
mk := k0 + dk/2
|
|
matmult(nil, A, B, C, i0, i1, j0, j1, k0, mk, threshold)
|
|
matmult(nil, A, B, C, i0, i1, j0, j1, mk, k1, threshold)
|
|
} else {
|
|
// the matrices are small enough, compute directly
|
|
for i := i0; i < i1; i++ {
|
|
for j := j0; j < j1; j++ {
|
|
for k := k0; k < k1; k++ {
|
|
C[i][j] += A[i][k] * B[k][j]
|
|
}
|
|
}
|
|
}
|
|
}
|
|
if done != nil {
|
|
done <- struct{}{}
|
|
}
|
|
}
|