github.com/varialus/godfly@v0.0.0-20130904042352-1934f9f095ab/src/pkg/runtime/chan_test.go (about) 1 // Copyright 2009 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 package runtime_test 6 7 import ( 8 "runtime" 9 "sync" 10 "sync/atomic" 11 "testing" 12 ) 13 14 func TestChanSendInterface(t *testing.T) { 15 type mt struct{} 16 m := &mt{} 17 c := make(chan interface{}, 1) 18 c <- m 19 select { 20 case c <- m: 21 default: 22 } 23 select { 24 case c <- m: 25 case c <- &mt{}: 26 default: 27 } 28 } 29 30 func TestPseudoRandomSend(t *testing.T) { 31 n := 100 32 c := make(chan int) 33 l := make([]int, n) 34 var m sync.Mutex 35 m.Lock() 36 go func() { 37 for i := 0; i < n; i++ { 38 runtime.Gosched() 39 l[i] = <-c 40 } 41 m.Unlock() 42 }() 43 for i := 0; i < n; i++ { 44 select { 45 case c <- 0: 46 case c <- 1: 47 } 48 } 49 m.Lock() // wait 50 n0 := 0 51 n1 := 0 52 for _, i := range l { 53 n0 += (i + 1) % 2 54 n1 += i 55 if n0 > n/10 && n1 > n/10 { 56 return 57 } 58 } 59 t.Errorf("Want pseudo random, got %d zeros and %d ones", n0, n1) 60 } 61 62 func TestMultiConsumer(t *testing.T) { 63 const nwork = 23 64 const niter = 271828 65 66 pn := []int{2, 3, 7, 11, 13, 17, 19, 23, 27, 31} 67 68 q := make(chan int, nwork*3) 69 r := make(chan int, nwork*3) 70 71 // workers 72 var wg sync.WaitGroup 73 for i := 0; i < nwork; i++ { 74 wg.Add(1) 75 go func(w int) { 76 for v := range q { 77 // mess with the fifo-ish nature of range 78 if pn[w%len(pn)] == v { 79 runtime.Gosched() 80 } 81 r <- v 82 } 83 wg.Done() 84 }(i) 85 } 86 87 // feeder & closer 88 expect := 0 89 go func() { 90 for i := 0; i < niter; i++ { 91 v := pn[i%len(pn)] 92 expect += v 93 q <- v 94 } 95 close(q) // no more work 96 wg.Wait() // workers done 97 close(r) // ... so there can be no more results 98 }() 99 100 // consume & check 101 n := 0 102 s := 0 103 for v := range r { 104 n++ 105 s += v 106 } 107 if n != niter || s != expect { 108 t.Errorf("Expected sum %d (got %d) from %d iter (saw %d)", 109 expect, s, niter, n) 110 } 111 } 112 113 func BenchmarkSelectUncontended(b *testing.B) { 114 const CallsPerSched = 1000 115 procs := runtime.GOMAXPROCS(-1) 116 N := int32(b.N / CallsPerSched) 117 c := make(chan bool, procs) 118 for p := 0; p < procs; p++ { 119 go func() { 120 myc1 := make(chan int, 1) 121 myc2 := make(chan int, 1) 122 myc1 <- 0 123 for atomic.AddInt32(&N, -1) >= 0 { 124 for g := 0; g < CallsPerSched; g++ { 125 select { 126 case <-myc1: 127 myc2 <- 0 128 case <-myc2: 129 myc1 <- 0 130 } 131 } 132 } 133 c <- true 134 }() 135 } 136 for p := 0; p < procs; p++ { 137 <-c 138 } 139 } 140 141 func BenchmarkSelectContended(b *testing.B) { 142 const CallsPerSched = 1000 143 procs := runtime.GOMAXPROCS(-1) 144 N := int32(b.N / CallsPerSched) 145 c := make(chan bool, procs) 146 myc1 := make(chan int, procs) 147 myc2 := make(chan int, procs) 148 for p := 0; p < procs; p++ { 149 myc1 <- 0 150 go func() { 151 for atomic.AddInt32(&N, -1) >= 0 { 152 for g := 0; g < CallsPerSched; g++ { 153 select { 154 case <-myc1: 155 myc2 <- 0 156 case <-myc2: 157 myc1 <- 0 158 } 159 } 160 } 161 c <- true 162 }() 163 } 164 for p := 0; p < procs; p++ { 165 <-c 166 } 167 } 168 169 func BenchmarkSelectNonblock(b *testing.B) { 170 const CallsPerSched = 1000 171 procs := runtime.GOMAXPROCS(-1) 172 N := int32(b.N / CallsPerSched) 173 c := make(chan bool, procs) 174 for p := 0; p < procs; p++ { 175 go func() { 176 myc1 := make(chan int) 177 myc2 := make(chan int) 178 myc3 := make(chan int, 1) 179 myc4 := make(chan int, 1) 180 for atomic.AddInt32(&N, -1) >= 0 { 181 for g := 0; g < CallsPerSched; g++ { 182 select { 183 case <-myc1: 184 default: 185 } 186 select { 187 case myc2 <- 0: 188 default: 189 } 190 select { 191 case <-myc3: 192 default: 193 } 194 select { 195 case myc4 <- 0: 196 default: 197 } 198 } 199 } 200 c <- true 201 }() 202 } 203 for p := 0; p < procs; p++ { 204 <-c 205 } 206 } 207 208 func BenchmarkChanUncontended(b *testing.B) { 209 const CallsPerSched = 1000 210 procs := runtime.GOMAXPROCS(-1) 211 N := int32(b.N / CallsPerSched) 212 c := make(chan bool, procs) 213 for p := 0; p < procs; p++ { 214 go func() { 215 myc := make(chan int, CallsPerSched) 216 for atomic.AddInt32(&N, -1) >= 0 { 217 for g := 0; g < CallsPerSched; g++ { 218 myc <- 0 219 } 220 for g := 0; g < CallsPerSched; g++ { 221 <-myc 222 } 223 } 224 c <- true 225 }() 226 } 227 for p := 0; p < procs; p++ { 228 <-c 229 } 230 } 231 232 func BenchmarkChanContended(b *testing.B) { 233 const CallsPerSched = 1000 234 procs := runtime.GOMAXPROCS(-1) 235 N := int32(b.N / CallsPerSched) 236 c := make(chan bool, procs) 237 myc := make(chan int, procs*CallsPerSched) 238 for p := 0; p < procs; p++ { 239 go func() { 240 for atomic.AddInt32(&N, -1) >= 0 { 241 for g := 0; g < CallsPerSched; g++ { 242 myc <- 0 243 } 244 for g := 0; g < CallsPerSched; g++ { 245 <-myc 246 } 247 } 248 c <- true 249 }() 250 } 251 for p := 0; p < procs; p++ { 252 <-c 253 } 254 } 255 256 func BenchmarkChanSync(b *testing.B) { 257 const CallsPerSched = 1000 258 procs := 2 259 N := int32(b.N / CallsPerSched / procs * procs) 260 c := make(chan bool, procs) 261 myc := make(chan int) 262 for p := 0; p < procs; p++ { 263 go func() { 264 for { 265 i := atomic.AddInt32(&N, -1) 266 if i < 0 { 267 break 268 } 269 for g := 0; g < CallsPerSched; g++ { 270 if i%2 == 0 { 271 <-myc 272 myc <- 0 273 } else { 274 myc <- 0 275 <-myc 276 } 277 } 278 } 279 c <- true 280 }() 281 } 282 for p := 0; p < procs; p++ { 283 <-c 284 } 285 } 286 287 func benchmarkChanProdCons(b *testing.B, chanSize, localWork int) { 288 const CallsPerSched = 1000 289 procs := runtime.GOMAXPROCS(-1) 290 N := int32(b.N / CallsPerSched) 291 c := make(chan bool, 2*procs) 292 myc := make(chan int, chanSize) 293 for p := 0; p < procs; p++ { 294 go func() { 295 foo := 0 296 for atomic.AddInt32(&N, -1) >= 0 { 297 for g := 0; g < CallsPerSched; g++ { 298 for i := 0; i < localWork; i++ { 299 foo *= 2 300 foo /= 2 301 } 302 myc <- 1 303 } 304 } 305 myc <- 0 306 c <- foo == 42 307 }() 308 go func() { 309 foo := 0 310 for { 311 v := <-myc 312 if v == 0 { 313 break 314 } 315 for i := 0; i < localWork; i++ { 316 foo *= 2 317 foo /= 2 318 } 319 } 320 c <- foo == 42 321 }() 322 } 323 for p := 0; p < procs; p++ { 324 <-c 325 <-c 326 } 327 } 328 329 func BenchmarkChanProdCons0(b *testing.B) { 330 benchmarkChanProdCons(b, 0, 0) 331 } 332 333 func BenchmarkChanProdCons10(b *testing.B) { 334 benchmarkChanProdCons(b, 10, 0) 335 } 336 337 func BenchmarkChanProdCons100(b *testing.B) { 338 benchmarkChanProdCons(b, 100, 0) 339 } 340 341 func BenchmarkChanProdConsWork0(b *testing.B) { 342 benchmarkChanProdCons(b, 0, 100) 343 } 344 345 func BenchmarkChanProdConsWork10(b *testing.B) { 346 benchmarkChanProdCons(b, 10, 100) 347 } 348 349 func BenchmarkChanProdConsWork100(b *testing.B) { 350 benchmarkChanProdCons(b, 100, 100) 351 } 352 353 func BenchmarkChanCreation(b *testing.B) { 354 const CallsPerSched = 1000 355 procs := runtime.GOMAXPROCS(-1) 356 N := int32(b.N / CallsPerSched) 357 c := make(chan bool, procs) 358 for p := 0; p < procs; p++ { 359 go func() { 360 for atomic.AddInt32(&N, -1) >= 0 { 361 for g := 0; g < CallsPerSched; g++ { 362 myc := make(chan int, 1) 363 myc <- 0 364 <-myc 365 } 366 } 367 c <- true 368 }() 369 } 370 for p := 0; p < procs; p++ { 371 <-c 372 } 373 } 374 375 func BenchmarkChanSem(b *testing.B) { 376 type Empty struct{} 377 c := make(chan Empty, 1) 378 for i := 0; i < b.N; i++ { 379 c <- Empty{} 380 <-c 381 } 382 }