func main()

in funcbench/main.go [55:225]


func main() {
	cfg := struct {
		userTestName   string
		verbose        bool
		nocomment      bool
		owner          string
		repo           string
		resultsDir     string
		workspaceDir   string
		ghPR           int
		benchTime      time.Duration
		benchTimeout   time.Duration
		compareTarget  string
		benchFuncRegex string
		packagePath    string
		enablePerflock bool
	}{}

	app := kingpin.New(
		filepath.Base(os.Args[0]),
		`Benchmark and compare your Go code between sub benchmarks or commits.
		* For BenchmarkFuncName, compare current with master: ./funcbench -v master BenchmarkFuncName
		* For BenchmarkFunc.*, compare current with master: ./funcbench -v master BenchmarkFunc.*
		* For all benchmarks, compare current with devel: ./funcbench -v devel .* or ./funcbench -v devel
		* For BenchmarkFunc.*, compare current with 6d280 commit: ./funcbench -v 6d280 BenchmarkFunc.*
		* For BenchmarkFunc.*, compare between sub-benchmarks of same benchmark on current commit: ./funcbench -v . BenchmarkFunc.*
		* For BenchmarkFuncName, compare pr#35 with master: ./funcbench --nocomment --github-pr="35" master BenchmarkFuncName`,
	)
	// Options.
	app.HelpFlag.Short('h')
	app.Flag("verbose", "Verbose mode. Errors includes trace and commands output are logged.").
		Short('v').BoolVar(&cfg.verbose)
	app.Flag("nocomment", "Disable posting of comment using the GitHub API.").
		BoolVar(&cfg.nocomment)

	app.Flag("owner", "A Github owner or organisation name.").
		Default("prometheus").StringVar(&cfg.owner)
	app.Flag("repo", "This is the repository name.").
		Default("prometheus").StringVar(&cfg.repo)
	app.Flag("github-pr", "GitHub PR number to pull changes from and to post benchmark results.").
		IntVar(&cfg.ghPR)
	app.Flag("workspace", "Directory to clone GitHub PR.").
		Default("/tmp/funcbench").
		StringVar(&cfg.workspaceDir)
	app.Flag("result-cache", "Directory to store benchmark results.").
		Default("funcbench-results").
		StringVar(&cfg.resultsDir)
	app.Flag("user-test-name", "Name of the test to keep track of multiple benchmarks").
		Default("default").
		Short('n').
		StringVar(&cfg.userTestName)

	app.Flag("bench-time", "Run enough iterations of each benchmark to take t, specified "+
		"as a time.Duration. The special syntax Nx means to run the benchmark N times").
		Short('t').Default("1s").DurationVar(&cfg.benchTime)
	app.Flag("timeout", "Benchmark timeout specified in time.Duration format, "+
		"disabled if set to 0. If a test binary runs longer than duration d, panic.").
		Short('d').Default("2h").DurationVar(&cfg.benchTimeout)
	app.Flag("perflock", "Enable perflock (you must have perflock installed to use this)").
		Short('l').
		Default("false").
		BoolVar(&cfg.enablePerflock)

	app.Arg("target", "Can be one of '.', tag name, branch name or commit SHA of the branch "+
		"to compare against. If set to '.', branch/commit is the same as the current one; "+
		"funcbench will run once and try to compare between 2 sub-benchmarks. "+
		"Errors out if there are no sub-benchmarks.").
		Required().StringVar(&cfg.compareTarget)
	app.Arg("bench-func-regex", "Function regex to use for benchmark."+
		"Supports RE2 regexp and is fully anchored, by default will run all benchmarks.").
		Default(".*").
		StringVar(&cfg.benchFuncRegex) // TODO (geekodour) : validate regex?
	app.Arg("packagepath", "Package to run benchmark against. Eg. ./tsdb, defaults to ./...").
		Default("./...").
		StringVar(&cfg.packagePath)

	kingpin.MustParse(app.Parse(os.Args[1:]))
	logger := &logger{
		// Show file line with each log.
		Logger:  log.New(os.Stdout, "funcbech", log.Ltime|log.Lshortfile),
		verbose: cfg.verbose,
	}

	var g run.Group
	// Main routine.
	{
		ctx, cancel := context.WithCancel(context.Background())
		g.Add(func() error {
			var (
				env Environment
				err error
			)

			// Setup Environment.
			e := environment{
				logger:        logger,
				benchFunc:     cfg.benchFuncRegex,
				compareTarget: cfg.compareTarget,
			}
			if cfg.ghPR == 0 {
				// Local Mode.
				env, err = newLocalEnv(e)
				if err != nil {
					return errors.Wrap(err, "environment create")
				}
			} else {
				// Github Mode.
				ghClient, err := newGitHubClient(ctx, cfg.owner, cfg.repo, cfg.ghPR, cfg.nocomment)
				if err != nil {
					return errors.Wrapf(err, "github client")
				}

				env, err = newGitHubEnv(ctx, e, ghClient, cfg.workspaceDir)
				if err != nil {
					if err := ghClient.postComment(fmt.Sprintf("%v. Could not setup environment, please check logs.", err)); err != nil {
						return errors.Wrap(err, "could not post error")
					}
					return errors.Wrap(err, "environment create")
				}
			}

			// ( β—”_β—”)οΎ‰ Start benchmarking!
			benchmarker := newBenchmarker(logger, env,
				&commander{verbose: cfg.verbose, ctx: ctx},
				cfg.benchTime, cfg.benchTimeout,
				path.Join(cfg.resultsDir, cfg.userTestName),
				cfg.packagePath,
				cfg.enablePerflock,
			)
			tables, err := startBenchmark(env, benchmarker)
			if err != nil {
				pErr := env.PostErr(
					fmt.Sprintf(
						"```\n%s\n```\nError:\n```\n%s\n```",
						strings.Join(benchmarker.benchmarkArgs, " "),
						err.Error(),
					),
				)

				if pErr != nil {
					return errors.Wrap(pErr, "could not log error")
				}
				return err
			}

			// Post results.
			// TODO (geekodour): probably post some kind of funcbench summary(?)
			return env.PostResults(
				tables,
				fmt.Sprintf("```\n%s\n```", strings.Join(benchmarker.benchmarkArgs, " ")),
			)

		}, func(err error) {
			cancel()
		})
	}
	// Listen for termination signals.
	{
		cancel := make(chan struct{})
		g.Add(func() error {
			return interrupt(logger, cancel)
		}, func(error) {
			close(cancel)
		})
	}

	if err := g.Run(); err != nil {
		logger.FatalError(errors.Wrap(err, "running command failed"))
	}
	logger.Println("exiting")
}