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
16var gdata []uint64
17
18// Simple serial sanity test for parallelfor.
19func TestParFor(t *testing.T) {
20	const P = 1
21	const N = 20
22	data := make([]uint64, N)
23	for i := uint64(0); i < N; i++ {
24		data[i] = i
25	}
26	desc := NewParFor(P)
27	// Avoid making func a closure: parfor cannot invoke them.
28	// Since it doesn't happen in the C code, it's not worth doing
29	// just for the test.
30	gdata = data
31	ParForSetup(desc, P, N, nil, true, func(desc *ParFor, i uint32) {
32		data := gdata
33		data[i] = data[i]*data[i] + 1
34	})
35	ParForDo(desc)
36	for i := uint64(0); i < N; i++ {
37		if data[i] != i*i+1 {
38			t.Fatalf("Wrong element %d: %d", i, data[i])
39		}
40	}
41}
42
43// Test that nonblocking parallelfor does not block.
44func TestParFor2(t *testing.T) {
45	const P = 7
46	const N = 1003
47	data := make([]uint64, N)
48	for i := uint64(0); i < N; i++ {
49		data[i] = i
50	}
51	desc := NewParFor(P)
52	ParForSetup(desc, P, N, (*byte)(unsafe.Pointer(&data)), false, func(desc *ParFor, i uint32) {
53		d := *(*[]uint64)(unsafe.Pointer(desc.Ctx))
54		d[i] = d[i]*d[i] + 1
55	})
56	for p := 0; p < P; p++ {
57		ParForDo(desc)
58	}
59	for i := uint64(0); i < N; i++ {
60		if data[i] != i*i+1 {
61			t.Fatalf("Wrong element %d: %d", i, data[i])
62		}
63	}
64}
65
66// Test that iterations are properly distributed.
67func TestParForSetup(t *testing.T) {
68	const P = 11
69	const N = 101
70	desc := NewParFor(P)
71	for n := uint32(0); n < N; n++ {
72		for p := uint32(1); p <= P; p++ {
73			ParForSetup(desc, p, n, nil, true, func(desc *ParFor, i uint32) {})
74			sum := uint32(0)
75			size0 := uint32(0)
76			end0 := uint32(0)
77			for i := uint32(0); i < p; i++ {
78				begin, end := ParForIters(desc, i)
79				size := end - begin
80				sum += size
81				if i == 0 {
82					size0 = size
83					if begin != 0 {
84						t.Fatalf("incorrect begin: %d (n=%d, p=%d)", begin, n, p)
85					}
86				} else {
87					if size != size0 && size != size0+1 {
88						t.Fatalf("incorrect size: %d/%d (n=%d, p=%d)", size, size0, n, p)
89					}
90					if begin != end0 {
91						t.Fatalf("incorrect begin/end: %d/%d (n=%d, p=%d)", begin, end0, n, p)
92					}
93				}
94				end0 = end
95			}
96			if sum != n {
97				t.Fatalf("incorrect sum: %d/%d (p=%d)", sum, n, p)
98			}
99		}
100	}
101}
102
103// Test parallel parallelfor.
104func TestParForParallel(t *testing.T) {
105	if GOARCH != "amd64" {
106		t.Log("temporarily disabled, see http://golang.org/issue/4155")
107		return
108	}
109
110	N := uint64(1e7)
111	if testing.Short() {
112		N /= 10
113	}
114	data := make([]uint64, N)
115	for i := uint64(0); i < N; i++ {
116		data[i] = i
117	}
118	P := GOMAXPROCS(-1)
119	c := make(chan bool, P)
120	desc := NewParFor(uint32(P))
121	gdata = data
122	ParForSetup(desc, uint32(P), uint32(N), nil, false, func(desc *ParFor, i uint32) {
123		data := gdata
124		data[i] = data[i]*data[i] + 1
125	})
126	for p := 1; p < P; p++ {
127		go func() {
128			ParForDo(desc)
129			c <- true
130		}()
131	}
132	ParForDo(desc)
133	for p := 1; p < P; p++ {
134		<-c
135	}
136	for i := uint64(0); i < N; i++ {
137		if data[i] != i*i+1 {
138			t.Fatalf("Wrong element %d: %d", i, data[i])
139		}
140	}
141
142	data, desc = nil, nil
143	GC()
144}
145