1// Copyright 2012 The Go Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style
3// license that can be found in the LICENSE file.
4
5// The race detector does not understand ParFor synchronization.
6// +build !race
7
8package runtime_test
9
10import (
11	. "runtime"
12	"testing"
13	"unsafe"
14)
15
16// Simple serial sanity test for parallelfor.
17func TestParFor(t *testing.T) {
18	const P = 1
19	const N = 20
20	data := make([]uint64, N)
21	for i := uint64(0); i < N; i++ {
22		data[i] = i
23	}
24	desc := NewParFor(P)
25	ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
26		data[i] = data[i]*data[i] + 1
27	})
28	ParForDo(desc)
29	for i := uint64(0); i < N; i++ {
30		if data[i] != i*i+1 {
31			t.Fatalf("Wrong element %d: %d", i, data[i])
32		}
33	}
34}
35
36// Test that nonblocking parallelfor does not block.
37func TestParFor2(t *testing.T) {
38	const P = 7
39	const N = 1003
40	data := make([]uint64, N)
41	for i := uint64(0); i < N; i++ {
42		data[i] = i
43	}
44	desc := NewParFor(P)
45	ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
46		d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
47		d[i] = d[i]*d[i] + 1
48	})
49	for p := 0; p < P; p++ {
50		ParForDo(desc)
51	}
52	for i := uint64(0); i < N; i++ {
53		if data[i] != i*i+1 {
54			t.Fatalf("Wrong element %d: %d", i, data[i])
55		}
56	}
57}
58
59// Test that iterations are properly distributed.
60func TestParForSetup(t *testing.T) {
61	const P = 11
62	const N = 101
63	desc := NewParFor(P)
64	for n := uint32(0); n < N; n++ {
65		for p := uint32(1); p <= P; p++ {
66			ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
67			sum := uint32(0)
68			size0 := uint32(0)
69			end0 := uint32(0)
70			for i := uint32(0); i < p; i++ {
71				begin, end := ParForIters(desc, i)
72				size := end - begin
73				sum += size
74				if i == 0 {
75					size0 = size
76					if begin != 0 {
77						t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
78					}
79				} else {
80					if size != size0 && size != size0+1 {
81						t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
82					}
83					if begin != end0 {
84						t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
85					}
86				}
87				end0 = end
88			}
89			if sum != n {
90				t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
91			}
92		}
93	}
94}
95
96// Test parallel parallelfor.
97func TestParForParallel(t *testing.T) {
98	if GOARCH != "amd64" {
99		t.Log("temporarily disabled, see http://golang.org/issue/4155")
100		return
101	}
102
103	N := uint64(1e7)
104	if testing.Short() {
105		N /= 10
106	}
107	data := make([]uint64, N)
108	for i := uint64(0); i < N; i++ {
109		data[i] = i
110	}
111	P := GOMAXPROCS(-1)
112	c := make(chan bool, P)
113	desc := NewParFor(uint32(P))
114	ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
115		data[i] = data[i]*data[i] + 1
116	})
117	for p := 1; p < P; p++ {
118		go func() {
119			ParForDo(desc)
120			c <- true
121		}()
122	}
123	ParForDo(desc)
124	for p := 1; p < P; p++ {
125		<-c
126	}
127	for i := uint64(0); i < N; i++ {
128		if data[i] != i*i+1 {
129			t.Fatalf("Wrong element %d: %d", i, data[i])
130		}
131	}
132
133	data, desc = nil, nil
134	GC()
135}
136