blob: de64285b8a8e532f461ddc540bef0653a7078da4 [file] [log] [blame]
// 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.
// The race detector does not understand ParFor synchronization.
// +build !race
package runtime_test
import (
. "runtime"
"testing"
"unsafe"
)
var gdata []uint64
// Simple serial sanity test for parallelfor.
func TestParFor(t *testing.T) {
const P = 1
const N = 20
data := make([]uint64, N)
for i := uint64(0); i < N; i++ {
data[i] = i
}
desc := NewParFor(P)
// Avoid making func a closure: parfor cannot invoke them.
// Since it doesn't happen in the C code, it's not worth doing
// just for the test.
gdata = data
ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
data := gdata
data[i] = data[i]*data[i] + 1
})
ParForDo(desc)
for i := uint64(0); i < N; i++ {
if data[i] != i*i+1 {
t.Fatalf("Wrong element %d: %d", i, data[i])
}
}
}
// Test that nonblocking parallelfor does not block.
func TestParFor2(t *testing.T) {
const P = 7
const N = 1003
data := make([]uint64, N)
for i := uint64(0); i < N; i++ {
data[i] = i
}
desc := NewParFor(P)
ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
d[i] = d[i]*d[i] + 1
})
for p := 0; p < P; p++ {
ParForDo(desc)
}
for i := uint64(0); i < N; i++ {
if data[i] != i*i+1 {
t.Fatalf("Wrong element %d: %d", i, data[i])
}
}
}
// Test that iterations are properly distributed.
func TestParForSetup(t *testing.T) {
const P = 11
const N = 101
desc := NewParFor(P)
for n := uint32(0); n < N; n++ {
for p := uint32(1); p <= P; p++ {
ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
sum := uint32(0)
size0 := uint32(0)
end0 := uint32(0)
for i := uint32(0); i < p; i++ {
begin, end := ParForIters(desc, i)
size := end - begin
sum += size
if i == 0 {
size0 = size
if begin != 0 {
t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
}
} else {
if size != size0 && size != size0+1 {
t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
}
if begin != end0 {
t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
}
}
end0 = end
}
if sum != n {
t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
}
}
}
}
// Test parallel parallelfor.
func TestParForParallel(t *testing.T) {
N := uint64(1e7)
if testing.Short() {
N /= 10
}
data := make([]uint64, N)
for i := uint64(0); i < N; i++ {
data[i] = i
}
P := GOMAXPROCS(-1)
c := make(chan bool, P)
desc := NewParFor(uint32(P))
gdata = data
ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
data := gdata
data[i] = data[i]*data[i] + 1
})
for p := 1; p < P; p++ {
go func() {
ParForDo(desc)
c <- true
}()
}
ParForDo(desc)
for p := 1; p < P; p++ {
<-c
}
for i := uint64(0); i < N; i++ {
if data[i] != i*i+1 {
t.Fatalf("Wrong element %d: %d", i, data[i])
}
}
data, desc = nil, nil
GC()
}