blob: 9d9eb4090de51c57d7d0a74d2aaced82280ad410 [file] [log] [blame]
// Copyright 2022 The Tint Authors.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// tint-bench repeatedly emits a WGSL file from a template, then times how long
// it takes to execute the tint executable with that WGSL file.
package main
import (
"flag"
"fmt"
"os"
"os/exec"
"path/filepath"
"sort"
"time"
"dawn.googlesource.com/dawn/tools/src/fileutils"
"dawn.googlesource.com/dawn/tools/src/template"
)
func main() {
if err := run(); err != nil {
fmt.Println(err)
os.Exit(1)
}
}
// [from .. to]
type Range struct {
from int
to int
}
func run() error {
alphaRange := Range{}
iterations := 0
tmplPath := ""
flag.StringVar(&tmplPath, "tmpl", "tint-bench.tmpl", `the WGSL template to benchmark.
Searches in order: absolute, relative to CWD, then relative to `+fileutils.ThisDir())
flag.IntVar(&alphaRange.from, "alpha-from", 0, "the start value for 'Alpha'")
flag.IntVar(&alphaRange.to, "alpha-to", 10, "the end value for 'Alpha'")
flag.IntVar(&iterations, "iterations", 10, "number of times to benchmark tint")
flag.Usage = func() {
fmt.Println("tint-bench repeatedly emits a WGSL file from a template, then times how long")
fmt.Println("it takes to execute the tint executable with that WGSL file.")
fmt.Println("")
fmt.Println("usage:")
fmt.Println(" tint-bench <bench-flags> [tint-exe] <tint-flags>")
fmt.Println("")
fmt.Println("bench-flags:")
flag.PrintDefaults()
os.Exit(1)
}
flag.Parse()
if tmplPath == "" {
return fmt.Errorf("missing template path")
}
tmpl, err := template.FromFile(tmplPath)
if err != nil {
if !filepath.IsAbs(tmplPath) {
// Try relative to this .go file
tmplPath = filepath.Join(fileutils.ThisDir(), tmplPath)
tmpl, err = template.FromFile(tmplPath)
}
}
if err != nil {
return fmt.Errorf("failed to load template: %v", err)
}
args := flag.Args()
if len(args) < 1 {
flag.Usage()
}
tintExe := args[0]
fmt.Println(" alpha | Time (μs)")
fmt.Println("-------+-----------------")
for alpha := alphaRange.from; alpha < alphaRange.to; alpha++ {
alpha := alpha
funcs := template.Functions{
"Alpha": func() int { return alpha },
}
wgslPath, err := writeWGSLFile(tmpl, funcs)
if err != nil {
return err
}
tintArgs := []string{wgslPath}
tintArgs = append(tintArgs, args[1:]...)
durations := []time.Duration{}
for i := 0; i < iterations; i++ {
tint := exec.Command(tintExe, tintArgs...)
start := time.Now()
if out, err := tint.CombinedOutput(); err != nil {
return fmt.Errorf("tint failed with error: %w\n%v\n\nwith: Alpha=%v", err, string(out), alpha)
}
duration := time.Since(start)
durations = append(durations, duration)
}
sort.Slice(durations, func(i, j int) bool { return durations[i] < durations[j] })
median := durations[len(durations)/2]
fmt.Printf("%6.v | %v\n", alpha, median.Microseconds())
}
return nil
}
func writeWGSLFile(tmpl *template.Template, funcs template.Functions) (string, error) {
const path = "tint-bench.wgsl"
wgslFile, err := os.Create(path)
if err != nil {
return "", fmt.Errorf("failed to create benchmark WGSL test file: %w", err)
}
defer wgslFile.Close()
if err := tmpl.Run(wgslFile, nil, funcs); err != nil {
return "", fmt.Errorf("template error:\n%w", err)
}
return path, nil
}