From 9bb1e09cc4958ce4497e1d35994d3a4e4fcde11a Mon Sep 17 00:00:00 2001 From: Dmitriy Vyukov Date: Tue, 13 May 2014 11:01:38 +0400 Subject: [PATCH] dashboard: database updater for performance dashboard This CL moves code from code.google.com/p/dvyukov-go-perf-dashboard, which was previously reviewed. LGTM=adg R=adg CC=golang-codereviews https://golang.org/cl/97250044 --- dashboard/updater/updater.go | 128 +++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 dashboard/updater/updater.go diff --git a/dashboard/updater/updater.go b/dashboard/updater/updater.go new file mode 100644 index 0000000000..0601611de0 --- /dev/null +++ b/dashboard/updater/updater.go @@ -0,0 +1,128 @@ +// 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 ( + "bytes" + "encoding/json" + "encoding/xml" + "flag" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "os" + "os/exec" + "strings" +) + +var ( + builder = flag.String("builder", "", "builder name") + key = flag.String("key", "", "builder key") + gopath = flag.String("gopath", "", "path to go repo") + dashboard = flag.String("dashboard", "build.golang.org", "Go Dashboard Host") + batch = flag.Int("batch", 100, "upload batch size") +) + +// Do not benchmark beyond this commit. +// There is little sense in benchmarking till first commit, +// and the benchmark won't build anyway. +const Go1Commit = "0051c7442fed" // test/bench/shootout: update timing.log to Go 1. + +// HgLog represents a single Mercurial revision. +type HgLog struct { + Hash string + Branch string + Files string +} + +func main() { + flag.Parse() + logs := hgLog() + var hashes []string + ngo1 := 0 + for i := range logs { + if strings.HasPrefix(logs[i].Hash, Go1Commit) { + break + } + if needsBenchmarking(&logs[i]) { + hashes = append(hashes, logs[i].Hash) + } + ngo1++ + } + fmt.Printf("found %v commits, %v after Go1, %v need benchmarking\n", len(logs), ngo1, len(hashes)) + for i := 0; i < len(hashes); i += *batch { + j := i + *batch + if j > len(hashes) { + j = len(hashes) + } + fmt.Printf("sending %v-%v... ", i, j) + res := postCommits(hashes[i:j]) + fmt.Printf("%s\n", res) + } +} + +func hgLog() []HgLog { + var out bytes.Buffer + cmd := exec.Command("hg", "log", "--encoding=utf-8", "--template", xmlLogTemplate) + cmd.Dir = *gopath + cmd.Stdout = &out + cmd.Stderr = os.Stderr + err := cmd.Run() + if err != nil { + fmt.Printf("failed to execute 'hg log': %v\n", err) + os.Exit(1) + } + var top struct{ Log []HgLog } + err = xml.Unmarshal([]byte(""+out.String()+""), &top) + if err != nil { + fmt.Printf("failed to parse log: %v\n", err) + os.Exit(1) + } + return top.Log +} + +func needsBenchmarking(log *HgLog) bool { + if log.Branch != "" { + return false + } + 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 +} + +func postCommits(hashes []string) string { + args := url.Values{"builder": {*builder}, "key": {*key}} + cmd := fmt.Sprintf("http://%v/updatebenchmark?%v", *dashboard, args.Encode()) + b, err := json.Marshal(hashes) + if err != nil { + return fmt.Sprintf("failed to encode request: %v\n", err) + } + r, err := http.Post(cmd, "text/json", bytes.NewReader(b)) + if err != nil { + return fmt.Sprintf("failed to send http request: %v\n", err) + } + defer r.Body.Close() + if r.StatusCode != http.StatusOK { + return fmt.Sprintf("http request failed: %v\n", r.Status) + } + resp, err := ioutil.ReadAll(r.Body) + if err != nil { + return fmt.Sprintf("failed to read http response: %v\n", err) + } + return string(resp) +} + +const xmlLogTemplate = ` + + {node|escape} + {branches} + {files} + +`