package main import ( "flag" "fmt" "math/rand" "os" "sync/atomic" "time" "golang.org/x/text/language" "golang.org/x/text/message" ) func handshake(stop chan struct {}, c chan [] uint64, data [] uint64, share bool) (bool, [] uint64) { var s [] uint64 = data if !share { s = nil } // send the data select { case <- stop: return true, nil case c <- s: } // get the new data chunk select { case <- stop: return true, nil case n := <- c: if share { return false, n } return false, data } } func local(result chan uint64, start chan struct{}, stop chan struct{}, size uint64, cnt uint64, channels []chan [] uint64, chan_cnt uint64, share bool) { var data [] uint64 data = make([]uint64, size) for i := uint64(0); i < size; i++ { data[i] = 0 } count := uint64(0) <- start for true { for i := uint64(0); i < cnt; i++ { data[rand.Uint64() % size] += 1 } i := rand.Uint64() % chan_cnt var closed bool closed, data = handshake(stop, channels[i], data, share) count += 1 if closed { break } if !clock_mode && count >= stop_count { break } } atomic.AddInt64(&threads_left, -1); result <- count } func main() { work_sizeOpt := flag.Uint64("w", 2 , "Number of words (uint64) per threads") countOpt := flag.Uint64("c", 2 , "Number of words (uint64) to touch") shareOpt := flag.Bool ("s", false, "Pass the work data to the next thread when blocking") bench_init() size := *work_sizeOpt cnt := *countOpt share := *shareOpt if ! (nthreads > nprocs) { fmt.Fprintf(os.Stderr, "Must have more threads than procs\n") os.Exit(1) } barrierStart := make(chan struct{}) barrierStop := make(chan struct{}) threads_left = int64(nthreads) result := make(chan uint64) channels := make([]chan [] uint64, nthreads - nprocs) for i := range channels { channels[i] = make(chan [] uint64, 1) } for i := 0; i < nthreads; i++ { go local(result, barrierStart, barrierStop, size, cnt, channels, uint64(nthreads - nprocs), share) } fmt.Printf("Starting\n"); start := time.Now() close(barrierStart) wait(start, true); close(barrierStop) end := time.Now() delta := end.Sub(start) fmt.Printf("\nDone\n") global_counter := uint64(0) for i := 0; i < nthreads; i++ { global_counter += <- result } p := message.NewPrinter(language.English) p.Printf("Duration (ms) : %f\n", delta.Seconds()); p.Printf("Number of processors : %d\n", nprocs); p.Printf("Number of threads : %d\n", nthreads); p.Printf("Work size (64bit words): %d\n", size); p.Printf("Total Operations(ops) : %15d\n", global_counter) p.Printf("Ops per second : %18.2f\n", float64(global_counter) / delta.Seconds()) p.Printf("ns per ops : %18.2f\n", float64(delta.Nanoseconds()) / float64(global_counter)) p.Printf("Ops per threads : %15d\n", global_counter / uint64(nthreads)) p.Printf("Ops per procs : %15d\n", global_counter / uint64(nprocs)) p.Printf("Ops/sec/procs : %18.2f\n", (float64(global_counter) / float64(nprocs)) / delta.Seconds()) p.Printf("ns per ops/procs : %18.2f\n", float64(delta.Nanoseconds()) / (float64(global_counter) / float64(nprocs))) }