// 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() }