| // Copyright 2014 The Gonum Authors. All rights reserved. |
| // Use of this code is governed by a BSD-style |
| // license that can be found in the LICENSE file |
| |
| // Script for automatic code generation of the benchmark routines |
| package main |
| |
| import ( |
| "fmt" |
| "os" |
| "os/exec" |
| "path" |
| "path/filepath" |
| "strconv" |
| ) |
| |
| var gopath string |
| |
| var copyrightnotice = []byte(`// Copyright 2014 The Gonum Authors. All rights reserved. |
| // Use of this code is governed by a BSD-style |
| // license that can be found in the LICENSE file`) |
| |
| var autogen = []byte("// Code generated by \"go run gonum.org/v1/gonum/blas/testblas/benchautogen/autogen_bench_level1double.go\"; DO NOT EDIT.\n") |
| |
| var imports = []byte(`import( |
| "math/rand" |
| "testing" |
| |
| "gonum.org/v1/gonum/blas" |
| )`) |
| |
| var randomSliceFunction = []byte(`func randomSlice(l, idx int) ([]float64) { |
| if idx < 0{ |
| idx = -idx |
| } |
| s := make([]float64, l * idx) |
| for i := range s { |
| s[i] = rand.Float64() |
| } |
| return s |
| }`) |
| |
| const ( |
| posInc1 = 5 |
| posInc2 = 3 |
| negInc1 = -3 |
| negInc2 = -4 |
| ) |
| |
| var level1Sizes = []struct { |
| lower string |
| upper string |
| camel string |
| size int |
| }{ |
| { |
| lower: "small", |
| upper: "SMALL_SLICE", |
| camel: "Small", |
| size: 10, |
| }, |
| { |
| lower: "medium", |
| upper: "MEDIUM_SLICE", |
| camel: "Medium", |
| size: 1000, |
| }, |
| { |
| lower: "large", |
| upper: "LARGE_SLICE", |
| camel: "Large", |
| size: 100000, |
| }, |
| { |
| lower: "huge", |
| upper: "HUGE_SLICE", |
| camel: "Huge", |
| size: 10000000, |
| }, |
| } |
| |
| type level1functionStruct struct { |
| camel string |
| sig string |
| call string |
| extraSetup string |
| oneInput bool |
| extraName string // if have a couple different cases for the same function |
| } |
| |
| var level1Functions = []level1functionStruct{ |
| { |
| camel: "Ddot", |
| sig: "n int, x []float64, incX int, y []float64, incY int", |
| call: "n, x, incX, y, incY", |
| oneInput: false, |
| }, |
| { |
| camel: "Dnrm2", |
| sig: "n int, x []float64, incX int", |
| call: "n, x, incX", |
| oneInput: true, |
| }, |
| { |
| camel: "Dasum", |
| sig: "n int, x []float64, incX int", |
| call: "n, x, incX", |
| oneInput: true, |
| }, |
| { |
| camel: "Idamax", |
| sig: "n int, x []float64, incX int", |
| call: "n, x, incX", |
| oneInput: true, |
| }, |
| { |
| camel: "Dswap", |
| sig: "n int, x []float64, incX int, y []float64, incY int", |
| call: "n, x, incX, y, incY", |
| oneInput: false, |
| }, |
| { |
| camel: "Dcopy", |
| sig: "n int, x []float64, incX int, y []float64, incY int", |
| call: "n, x, incX, y, incY", |
| oneInput: false, |
| }, |
| { |
| camel: "Daxpy", |
| sig: "n int, alpha float64, x []float64, incX int, y []float64, incY int", |
| call: "n, alpha, x, incX, y, incY", |
| extraSetup: "alpha := 2.4", |
| oneInput: false, |
| }, |
| { |
| camel: "Drot", |
| sig: "n int, x []float64, incX int, y []float64, incY int, c, s float64", |
| call: "n, x, incX, y, incY, c, s", |
| extraSetup: "c := 0.89725836967\ns:= 0.44150585279", |
| oneInput: false, |
| }, |
| { |
| camel: "Drotm", |
| sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", |
| call: "n, x, incX, y, incY, p", |
| extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{0, -0.625, 0.9375,0}}", |
| oneInput: false, |
| extraName: "OffDia", |
| }, |
| { |
| camel: "Drotm", |
| sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", |
| call: "n, x, incX, y, incY, p", |
| extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{5.0 / 12, 0, 0, 0.625}}", |
| oneInput: false, |
| extraName: "Dia", |
| }, |
| { |
| camel: "Drotm", |
| sig: "n int, x []float64, incX int, y []float64, incY int, p blas.DrotmParams", |
| call: "n, x, incX, y, incY, p", |
| extraSetup: "p := blas.DrotmParams{Flag: blas.OffDiagonal, H: [4]float64{4096, -3584, 1792, 4096}}", |
| oneInput: false, |
| extraName: "Resc", |
| }, |
| { |
| camel: "Dscal", |
| sig: "n int, alpha float64, x []float64, incX int", |
| call: "n, alpha, x, incX", |
| extraSetup: "alpha := 2.4", |
| oneInput: true, |
| }, |
| } |
| |
| func init() { |
| gopath = os.Getenv("GOPATH") |
| if gopath == "" { |
| panic("gopath not set") |
| } |
| } |
| |
| func main() { |
| blasPath := filepath.Join(gopath, "src", "gonum.org", "v1", "gonum", "blas") |
| |
| pkgs := []struct{ name string }{{name: "native"}, {name: "cgo"}} |
| |
| for _, pkg := range pkgs { |
| err := level1(filepath.Join(blasPath, pkg.name), pkg.name) |
| if err != nil { |
| fmt.Println(err) |
| os.Exit(1) |
| } |
| |
| err = exec.Command("go", "fmt", path.Join("gonum.org", "v1", "gonum", "blas", pkg.name)).Run() |
| if err != nil { |
| fmt.Println(err) |
| os.Exit(1) |
| } |
| } |
| } |
| |
| func printHeader(f *os.File, name string) error { |
| if _, err := f.Write(autogen); err != nil { |
| return err |
| } |
| f.WriteString("\n\n") |
| f.Write(copyrightnotice) |
| f.WriteString("\n\n") |
| f.WriteString("package " + name) |
| f.WriteString("\n\n") |
| f.Write(imports) |
| f.WriteString("\n\n") |
| return nil |
| } |
| |
| // Generate the benchmark scripts for level1 |
| func level1(benchPath string, pkgname string) error { |
| // Generate level 1 benchmarks |
| level1Filepath := filepath.Join(benchPath, "level1doubleBench_auto_test.go") |
| f, err := os.Create(level1Filepath) |
| if err != nil { |
| fmt.Println(err) |
| os.Exit(1) |
| } |
| defer f.Close() |
| printHeader(f, pkgname) |
| |
| // Print all of the constants |
| f.WriteString("const (\n") |
| f.WriteString("\tposInc1 = " + strconv.Itoa(posInc1) + "\n") |
| f.WriteString("\tposInc2 = " + strconv.Itoa(posInc2) + "\n") |
| f.WriteString("\tnegInc1 = " + strconv.Itoa(negInc1) + "\n") |
| f.WriteString("\tnegInc2 = " + strconv.Itoa(negInc2) + "\n") |
| for _, con := range level1Sizes { |
| f.WriteString("\t" + con.upper + " = " + strconv.Itoa(con.size) + "\n") |
| } |
| f.WriteString(")\n") |
| f.WriteString("\n") |
| |
| // Write the randomSlice function |
| f.Write(randomSliceFunction) |
| f.WriteString("\n\n") |
| |
| // Start writing the benchmarks |
| for _, fun := range level1Functions { |
| writeLevel1Benchmark(fun, f) |
| f.WriteString("\n/* ------------------ */ \n") |
| } |
| |
| return nil |
| } |
| |
| func writeLevel1Benchmark(fun level1functionStruct, f *os.File) { |
| // First, write the base benchmark file |
| f.WriteString("func benchmark" + fun.camel + fun.extraName + "(b *testing.B, ") |
| f.WriteString(fun.sig) |
| f.WriteString(") {\n") |
| |
| f.WriteString("b.ResetTimer()\n") |
| f.WriteString("for i := 0; i < b.N; i++{\n") |
| f.WriteString("\timpl." + fun.camel + "(") |
| |
| f.WriteString(fun.call) |
| f.WriteString(")\n}\n}\n") |
| f.WriteString("\n") |
| |
| // Write all of the benchmarks to call it |
| for _, sz := range level1Sizes { |
| lambda := func(incX, incY, name string, twoInput bool) { |
| f.WriteString("func Benchmark" + fun.camel + fun.extraName + sz.camel + name + "(b *testing.B){\n") |
| f.WriteString("n := " + sz.upper + "\n") |
| f.WriteString("incX := " + incX + "\n") |
| f.WriteString("x := randomSlice(n, incX)\n") |
| if twoInput { |
| f.WriteString("incY := " + incY + "\n") |
| f.WriteString("y := randomSlice(n, incY)\n") |
| } |
| f.WriteString(fun.extraSetup + "\n") |
| f.WriteString("benchmark" + fun.camel + fun.extraName + "(b, " + fun.call + ")\n") |
| f.WriteString("}\n\n") |
| } |
| if fun.oneInput { |
| lambda("1", "", "UnitaryInc", false) |
| lambda("posInc1", "", "PosInc", false) |
| } else { |
| lambda("1", "1", "BothUnitary", true) |
| lambda("posInc1", "1", "IncUni", true) |
| lambda("1", "negInc1", "UniInc", true) |
| lambda("posInc1", "negInc1", "BothInc", true) |
| } |
| } |
| } |