diff --git a/test/bench/fannkuch-parallel.go b/test/bench/fannkuch-parallel.go new file mode 100644 index 00000000000..7897eac0524 --- /dev/null +++ b/test/bench/fannkuch-parallel.go @@ -0,0 +1,224 @@ +/* +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + + * Neither the name of "The Computer Language Benchmarks Game" nor the + name of "The Computer Language Shootout Benchmarks" nor the names of + its contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE +LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR +CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE +POSSIBILITY OF SUCH DAMAGE. +*/ + +/* + * The Computer Language Benchmarks Game + * http://shootout.alioth.debian.org/ + * + * contributed by The Go Authors. + * Based on fannkuch.scala by Rex Kerr + */ + +package main + +import ( + "flag" + "fmt" + "runtime" +) + +var n = flag.Int("n", 7, "count") +var nCPU = flag.Int("ncpu", 2, "number of cpus") + +type Job struct { + start []int + n int +} + +type Found struct { + who *Kucher + k int +} + +type Kucher struct { + perm []int + temp []int + flip []int + in chan Job +} + +func NewKucher(length int) *Kucher { + return &Kucher{ + perm: make([]int, length), + temp: make([]int, length), + flip: make([]int, length), + in: make(chan Job), + } +} + +func (k *Kucher) permute(n int) bool { + i := 0 + for ; i < n-1 && k.flip[i] == 0; i++ { + t := k.perm[0] + j := 0 + for ; j <= i; j++ { + k.perm[j] = k.perm[j+1] + } + k.perm[j] = t + } + k.flip[i]-- + for i > 0 { + i-- + k.flip[i] = i + } + return k.flip[n-1] >= 0 +} + +func (k *Kucher) count() int { + K := 0 + copy(k.temp, k.perm) + for k.temp[0] != 0 { + m := k.temp[0] + for i := 0; i < m; i++ { + k.temp[i], k.temp[m] = k.temp[m], k.temp[i] + m-- + } + K++ + } + return K +} + +func (k *Kucher) Run(foreman chan<- Found) { + for job := range k.in { + verbose := 30 + copy(k.perm, job.start) + for i, v := range k.perm { + if v != i { + verbose = 0 + } + k.flip[i] = i + } + K := 0 + for { + if verbose > 0 { + for _, p := range k.perm { + fmt.Print(p + 1) + } + fmt.Println() + verbose-- + } + count := k.count() + if count > K { + K = count + } + if !k.permute(job.n) { + break + } + } + foreman <- Found{k, K} + } +} + +type Fanner struct { + jobind int + jobsdone int + k int + jobs []Job + workers []*Kucher + in chan Found + result chan int +} + +func NewFanner(jobs []Job, workers []*Kucher) *Fanner { + return &Fanner{ + jobs: jobs, workers: workers, + in: make(chan Found), + result: make(chan int), + } +} + +func (f *Fanner) Run(N int) { + for msg := range f.in { + if msg.k > f.k { + f.k = msg.k + } + if msg.k >= 0 { + f.jobsdone++ + } + if f.jobind < len(f.jobs) { + msg.who.in <- f.jobs[f.jobind] + f.jobind++ + } else if f.jobsdone == len(f.jobs) { + f.result <- f.k + return + } + } +} + +func swapped(a []int, i, j int) []int { + b := make([]int, len(a)) + copy(b, a) + b[i], b[j] = a[j], a[i] + return b +} + +func main() { + flag.Parse() + runtime.GOMAXPROCS(*nCPU) + N := *n + base := make([]int, N) + for i := range base { + base[i] = i + } + + njobs := 1 + if N > 8 { + njobs += (N*(N-1))/2 - 28 // njobs = 1 + sum(8..N-1) = 1 + sum(1..N-1) - sum(1..7) + } + jobs := make([]Job, njobs) + jobsind := 0 + + firstN := N + if firstN > 8 { + firstN = 8 + } + jobs[jobsind] = Job{base, firstN} + jobsind++ + for i := N - 1; i >= 8; i-- { + for j := 0; j < i; j++ { + jobs[jobsind] = Job{swapped(base, i, j), i} + jobsind++ + } + } + + nworkers := *nCPU + if njobs < nworkers { + nworkers = njobs + } + workers := make([]*Kucher, nworkers) + foreman := NewFanner(jobs, workers) + go foreman.Run(N) + for i := range workers { + k := NewKucher(N) + workers[i] = k + go k.Run(foreman.in) + foreman.in <- Found{k, -1} + } + fmt.Printf("Pfannkuchen(%d) = %d\n", N, <-foreman.result) +} diff --git a/test/bench/fannkuch-parallel.txt b/test/bench/fannkuch-parallel.txt new file mode 100644 index 00000000000..e66f779ea1d --- /dev/null +++ b/test/bench/fannkuch-parallel.txt @@ -0,0 +1,31 @@ +1234567 +2134567 +2314567 +3214567 +3124567 +1324567 +2341567 +3241567 +3421567 +4321567 +4231567 +2431567 +3412567 +4312567 +4132567 +1432567 +1342567 +3142567 +4123567 +1423567 +1243567 +2143567 +2413567 +4213567 +2345167 +3245167 +3425167 +4325167 +4235167 +2435167 +Pfannkuchen(7) = 16 diff --git a/test/bench/timing.sh b/test/bench/timing.sh index 7543834fbdf..83ffd2494c8 100755 --- a/test/bench/timing.sh +++ b/test/bench/timing.sh @@ -106,7 +106,9 @@ fannkuch() { runonly echo 'fannkuch 12' run 'gcc -O2 fannkuch.c' a.out 12 run 'gccgo -O2 fannkuch.go' a.out -n 12 + run 'gccgo -O2 fannkuch-parallel.go' a.out -n 12 run 'gc fannkuch' $O.out -n 12 + run 'gc fannkuch-parallel' $O.out -n 12 run 'gc_B fannkuch' $O.out -n 12 }