fdbc38a6e8
This changes the representation of a Go value of function type from being a pointer to function code (like a C function pointer) to being a pointer to a struct. The first field of the struct points to the function code. The remaining fields, if any, are the addresses of variables referenced in enclosing functions. For each call to a function, the address of the function descriptor is passed as the last argument. This lets us avoid generating trampolines, and removes the use of writable/executable sections of the heap. From-SVN: r200181
145 lines
3.2 KiB
Go
145 lines
3.2 KiB
Go
// 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) {
|
|
if GOARCH != "amd64" {
|
|
t.Log("temporarily disabled, see http://golang.org/issue/4155")
|
|
return
|
|
}
|
|
|
|
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()
|
|
}
|