// Copyright 2013 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import (
	"bufio"
	"bytes"
	"fmt"
	"io"
	"io/ioutil"
	"log"
	"os"
	"os/exec"
	"path/filepath"
	"regexp"
	"strconv"
	"strings"
)

// benchHash benchmarks a single commit.
func (b *Builder) benchHash(hash string, benchs []string) error {
	if *verbose {
		log.Println(b.name, "benchmarking", hash)
	}

	res := &PerfResult{Hash: hash, Benchmark: "meta-done"}

	// Create place in which to do work.
	workpath := filepath.Join(*buildroot, b.name+"-"+hash[:12])
	// Prepare a workpath if we don't have one we can reuse.
	update := false
	if b.lastWorkpath != workpath {
		if err := os.Mkdir(workpath, mkdirPerm); err != nil {
			return err
		}
		buildLog, _, err := b.buildRepoOnHash(workpath, hash, makeCmd)
		if err != nil {
			removePath(workpath)
			// record failure
			res.Artifacts = append(res.Artifacts, PerfArtifact{"log", buildLog})
			return b.recordPerfResult(res)
		}
		b.lastWorkpath = workpath
		update = true
	}

	// Build the benchmark binary.
	benchBin, buildLog, err := b.buildBenchmark(workpath, update)
	if err != nil {
		// record failure
		res.Artifacts = append(res.Artifacts, PerfArtifact{"log", buildLog})
		return b.recordPerfResult(res)
	}

	benchmark, procs, affinity, last := chooseBenchmark(benchBin, benchs)
	if benchmark != "" {
		res.Benchmark = fmt.Sprintf("%v-%v", benchmark, procs)
		res.Metrics, res.Artifacts, res.OK = b.executeBenchmark(workpath, hash, benchBin, benchmark, procs, affinity)
		if err = b.recordPerfResult(res); err != nil {
			return fmt.Errorf("recordResult: %s", err)
		}
	}

	if last {
		// All benchmarks have beed executed, don't need workpath anymore.
		removePath(b.lastWorkpath)
		b.lastWorkpath = ""
		// Notify the app.
		res = &PerfResult{Hash: hash, Benchmark: "meta-done", OK: true}
		if err = b.recordPerfResult(res); err != nil {
			return fmt.Errorf("recordResult: %s", err)
		}
	}

	return nil
}

// buildBenchmark builds the benchmark binary.
func (b *Builder) buildBenchmark(workpath string, update bool) (benchBin, log string, err error) {
	goroot := filepath.Join(workpath, "go")
	gobin := filepath.Join(goroot, "bin", "go") + exeExt
	gopath := filepath.Join(*buildroot, "gopath")
	env := append([]string{
		"GOROOT=" + goroot,
		"GOPATH=" + gopath},
		b.envv()...)
	// First, download without installing.
	cmd := []string{gobin, "get", "-d"}
	if update {
		cmd = append(cmd, "-u")
	}
	cmd = append(cmd, *benchPath)
	var buildlog bytes.Buffer
	ok, err := runOutput(*buildTimeout, env, &buildlog, workpath, cmd...)
	if !ok || err != nil {
		fmt.Fprintf(&buildlog, "go get -d %s failed: %s", *benchPath, err)
		return "", buildlog.String(), err
	}
	// Then, build into workpath.
	benchBin = filepath.Join(workpath, "benchbin") + exeExt
	cmd = []string{gobin, "build", "-o", benchBin, *benchPath}
	buildlog.Reset()
	ok, err = runOutput(*buildTimeout, env, &buildlog, workpath, cmd...)
	if !ok || err != nil {
		fmt.Fprintf(&buildlog, "go build %s failed: %s", *benchPath, err)
		return "", buildlog.String(), err
	}
	return benchBin, "", nil
}

// chooseBenchmark chooses the next benchmark to run
// based on the list of available benchmarks, already executed benchmarks
// and -benchcpu list.
func chooseBenchmark(benchBin string, doneBenchs []string) (bench string, procs, affinity int, last bool) {
	out, err := exec.Command(benchBin).CombinedOutput()
	if err != nil {
		log.Printf("Failed to query benchmark list: %v\n%s", err, out)
		last = true
		return
	}
	outStr := string(out)
	nlIdx := strings.Index(outStr, "\n")
	if nlIdx < 0 {
		log.Printf("Failed to parse benchmark list (no new line): %s", outStr)
		last = true
		return
	}
	localBenchs := strings.Split(outStr[:nlIdx], ",")
	benchsMap := make(map[string]bool)
	for _, b := range doneBenchs {
		benchsMap[b] = true
	}
	cnt := 0
	// We want to run all benchmarks with GOMAXPROCS=1 first.
	for i, procs1 := range benchCPU {
		for _, bench1 := range localBenchs {
			if benchsMap[fmt.Sprintf("%v-%v", bench1, procs1)] {
				continue
			}
			cnt++
			if cnt == 1 {
				bench = bench1
				procs = procs1
				if i < len(benchAffinity) {
					affinity = benchAffinity[i]
				}
			}
		}
	}
	last = cnt <= 1
	return
}

// executeBenchmark runs a single benchmark and parses its output.
func (b *Builder) executeBenchmark(workpath, hash, benchBin, bench string, procs, affinity int) (metrics []PerfMetric, artifacts []PerfArtifact, ok bool) {
	// Benchmarks runs mutually exclusive with other activities.
	benchMutex.RUnlock()
	defer benchMutex.RLock()
	benchMutex.Lock()
	defer benchMutex.Unlock()

	log.Printf("%v executing benchmark %v-%v on %v", b.name, bench, procs, hash)

	// The benchmark executes 'go build'/'go tool',
	// so we need properly setup env.
	env := append([]string{
		"GOROOT=" + filepath.Join(workpath, "go"),
		"PATH=" + filepath.Join(workpath, "go", "bin") + string(os.PathListSeparator) + os.Getenv("PATH"),
		"GODEBUG=gctrace=1", // since Go1.2
		"GOGCTRACE=1",       // before Go1.2
		fmt.Sprintf("GOMAXPROCS=%v", procs)},
		b.envv()...)
	cmd := []string{benchBin,
		"-bench", bench,
		"-benchmem", strconv.Itoa(*benchMem),
		"-benchtime", benchTime.String(),
		"-benchnum", strconv.Itoa(*benchNum),
		"-tmpdir", workpath}
	if affinity != 0 {
		cmd = append(cmd, "-affinity", strconv.Itoa(affinity))
	}
	benchlog := new(bytes.Buffer)
	ok, err := runOutput(*buildTimeout, env, benchlog, workpath, cmd...)
	if strip := benchlog.Len() - 512<<10; strip > 0 {
		// Leave the last 512K, that part contains metrics.
		benchlog = bytes.NewBuffer(benchlog.Bytes()[strip:])
	}
	artifacts = []PerfArtifact{{Type: "log", Body: benchlog.String()}}
	if !ok || err != nil {
		if err != nil {
			log.Printf("Failed to execute benchmark '%v': %v", bench, err)
			ok = false
		}
		return
	}

	metrics1, artifacts1, err := parseBenchmarkOutput(benchlog)
	if err != nil {
		log.Printf("Failed to parse benchmark output: %v", err)
		ok = false
		return
	}
	metrics = metrics1
	artifacts = append(artifacts, artifacts1...)
	return
}

// parseBenchmarkOutput fetches metrics and artifacts from benchmark output.
func parseBenchmarkOutput(out io.Reader) (metrics []PerfMetric, artifacts []PerfArtifact, err error) {
	s := bufio.NewScanner(out)
	metricRe := regexp.MustCompile("^GOPERF-METRIC:([a-z,0-9,-]+)=([0-9]+)$")
	fileRe := regexp.MustCompile("^GOPERF-FILE:([a-z,0-9,-]+)=(.+)$")
	for s.Scan() {
		ln := s.Text()
		if ss := metricRe.FindStringSubmatch(ln); ss != nil {
			var v uint64
			v, err = strconv.ParseUint(ss[2], 10, 64)
			if err != nil {
				err = fmt.Errorf("Failed to parse metric '%v=%v': %v", ss[1], ss[2], err)
				return
			}
			metrics = append(metrics, PerfMetric{Type: ss[1], Val: v})
		} else if ss := fileRe.FindStringSubmatch(ln); ss != nil {
			var buf []byte
			buf, err = ioutil.ReadFile(ss[2])
			if err != nil {
				err = fmt.Errorf("Failed to read file '%v': %v", ss[2], err)
				return
			}
			artifacts = append(artifacts, PerfArtifact{ss[1], string(buf)})
		}
	}
	return
}

// needsBenchmarking determines whether the commit needs benchmarking.
func needsBenchmarking(log *HgLog) bool {
	// Do not benchmark branch commits, they are usually not interesting
	// and fall out of the trunk succession.
	if log.Branch != "" {
		return false
	}
	// Do not benchmark commits that do not touch source files (e.g. CONTRIBUTORS).
	for _, f := range strings.Split(log.Files, " ") {
		if (strings.HasPrefix(f, "include") || strings.HasPrefix(f, "src")) &&
			!strings.HasSuffix(f, "_test.go") && !strings.Contains(f, "testdata") {
			return true
		}
	}
	return false
}
