Skip to content

Commit 974f011

Browse files
Merge pull request #6 from codeperfio/publish.update
Update bin name and references
2 parents 6f4e0b0 + 6454403 commit 974f011

File tree

6 files changed

+207
-55
lines changed

6 files changed

+207
-55
lines changed

README.md

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
# pprof-exporter
2-
Export and persist Go profiling data locally, or into https://codeperf.io for FREE.
1+
# codeperf
2+
Export and persist performance data into https://codeperf.io.
33

44

5-
bash <(curl -s https://raw.githubusercontent.com/codeperfio/pprof-exporter/main/get.sh)
6-
sudo install pprof-exporter /usr/local/bin/
5+
bash <(curl -s https://raw.githubusercontent.com/codeperfio/codeperf/main/get.sh)
6+
sudo install codeperf /usr/local/bin/
77

8-
pprof-exporter --help
8+
codeperf --help

cmd/export.go

+48-41
Original file line numberDiff line numberDiff line change
@@ -33,59 +33,66 @@ type TextReport struct {
3333
}
3434

3535
func exportLogic() func(cmd *cobra.Command, args []string) {
36-
granularityOptions := []string{"lines", "functions"}
36+
3737
return func(cmd *cobra.Command, args []string) {
3838
if len(args) != 1 {
3939
log.Fatalf("Exactly one profile file is required")
4040
}
41-
if local {
42-
err, finalTree := generateFlameGraph(args[0])
43-
if err != nil {
44-
log.Fatalf("An Error Occured %v", err)
45-
}
46-
postBody, err := json.Marshal(finalTree)
47-
if err != nil {
48-
log.Fatalf("An Error Occured %v", err)
49-
}
50-
fmt.Println(string(postBody))
41+
inputName := args[0]
42+
granularityOptions := []string{"lines", "functions"}
43+
exportFromPprof(inputName, bench, granularityOptions)
44+
}
45+
}
5146

52-
for _, granularity := range granularityOptions {
53-
err, report := generateTextReports(granularity, args[0])
54-
if err == nil {
55-
var w io.Writer
56-
// open output file
57-
localExportLogic(w, report)
58-
} else {
59-
log.Fatal(err)
60-
}
61-
}
62-
} else {
63-
for _, granularity := range granularityOptions {
64-
err, report := generateTextReports(granularity, args[0])
65-
if err == nil {
66-
remoteExportLogic(report, granularity)
67-
} else {
68-
log.Fatal(err)
69-
}
47+
func exportFromPprof(inputName string, benchmark string, granularityOptions []string) {
48+
if local {
49+
err, finalTree := generateFlameGraph(inputName)
50+
if err != nil {
51+
log.Fatalf("An Error Occured %v", err)
52+
}
53+
postBody, err := json.Marshal(finalTree)
54+
if err != nil {
55+
log.Fatalf("An Error Occured %v", err)
56+
}
57+
fmt.Println(string(postBody))
58+
59+
for _, granularity := range granularityOptions {
60+
err, report := generateTextReports(granularity, inputName)
61+
if err == nil {
62+
var w io.Writer
63+
// open output file
64+
localExportLogic(w, report)
65+
} else {
66+
log.Fatal(err)
7067
}
71-
err, finalTree := generateFlameGraph(args[0])
72-
if err != nil {
73-
log.Fatalf("An Error Occured %v", err)
68+
}
69+
} else {
70+
for _, granularity := range granularityOptions {
71+
err, report := generateTextReports(granularity, inputName)
72+
if err == nil {
73+
remoteExportLogic(report, benchmark, granularity)
74+
} else {
75+
log.Fatal(err)
7476
}
75-
remoteFlameGraphExport(finalTree)
76-
log.Printf("Successfully published profile data")
77-
log.Printf("Check it at: %s/gh/%s/%s/commit/%s/bench/%s/cpu", codeperfUrl, gitOrg, gitRepo, gitCommit, bench)
7877
}
78+
err, finalTree := generateFlameGraph(inputName)
79+
if err != nil {
80+
log.Fatalf("An Error Occured %v", err)
81+
}
82+
remoteFlameGraphExport(finalTree, benchmark)
83+
log.Printf("Successfully published profile data")
84+
link := fmt.Sprintf("%s/gh/%s/%s/commit/%s/bench/%s/cpu", codeperfUrl, gitOrg, gitRepo, gitCommit, benchmark)
85+
log.Printf(link)
7986
}
8087
}
8188

82-
func remoteFlameGraphExport(tree treeNodeSlice) {
89+
func remoteFlameGraphExport(tree treeNodeSlice, benchmark string) {
8390
postBody, err := json.Marshal(tree)
8491
if err != nil {
8592
log.Fatalf("An Error Occured %v", err)
8693
}
8794
responseBody := bytes.NewBuffer(postBody)
88-
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/commit/%s/bench/%s/cpu/flamegraph", codeperfApiUrl, gitOrg, gitRepo, gitCommit, bench)
95+
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/commit/%s/bench/%s/cpu/flamegraph", codeperfApiUrl, gitOrg, gitRepo, gitCommit, benchmark)
8996
resp, err := http.Post(endPoint, "application/json", responseBody)
9097
//Handle Error
9198
if err != nil {
@@ -99,18 +106,18 @@ func remoteFlameGraphExport(tree treeNodeSlice) {
99106
log.Fatalln(err)
100107
}
101108
if resp.StatusCode != 200 {
102-
log.Fatalf("An error ocurred while phusing data to remote %s. Status code %d. Reply: %s", codeperfApiUrl, resp.StatusCode, string(reply))
109+
log.Fatalf("An error ocurred while phusing flamegraph data to remote %s. Status code %d. Reply: %s", codeperfApiUrl, resp.StatusCode, string(reply))
103110
}
104111

105112
}
106113

107-
func remoteExportLogic(report TextReport, granularity string) {
114+
func remoteExportLogic(report TextReport, benchmark string, granularity string) {
108115
postBody, err := json.Marshal(report)
109116
if err != nil {
110117
log.Fatalf("An Error Occured %v", err)
111118
}
112119
responseBody := bytes.NewBuffer(postBody)
113-
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/commit/%s/bench/%s/cpu/%s", codeperfApiUrl, gitOrg, gitRepo, gitCommit, bench, granularity)
120+
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/commit/%s/bench/%s/cpu/%s", codeperfApiUrl, gitOrg, gitRepo, gitCommit, benchmark, granularity)
114121
resp, err := http.Post(endPoint, "application/json", responseBody)
115122
//Handle Error
116123
if err != nil {
@@ -124,7 +131,7 @@ func remoteExportLogic(report TextReport, granularity string) {
124131
log.Fatalln(err)
125132
}
126133
if resp.StatusCode != 200 {
127-
log.Fatalf("An error ocurred while phusing data to remote %s. Status code %d. Reply: %s", codeperfApiUrl, resp.StatusCode, string(reply))
134+
log.Fatalf("An error ocurred while pushing cpu data to remote %s.\nEndpoint %s. Status code %d. Reply: %s", codeperfApiUrl, endPoint, resp.StatusCode, string(reply))
128135
}
129136
}
130137

cmd/project_parser.go

+54
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
package cmd
2+
3+
import (
4+
"go/ast"
5+
"go/parser"
6+
"go/token"
7+
"io/fs"
8+
"log"
9+
"os"
10+
"path/filepath"
11+
"strings"
12+
)
13+
14+
func funcNames(filename string, exportOnly bool) []string {
15+
fset := token.NewFileSet()
16+
file, _ := parser.ParseFile(fset, filename, nil, 0)
17+
if exportOnly {
18+
ast.FileExports(file) // trim AST
19+
}
20+
21+
funcNames := []string{}
22+
for _, decl := range file.Decls {
23+
fn, ok := decl.(*ast.FuncDecl) // assert type of declaration
24+
if !ok {
25+
continue
26+
}
27+
funcNames = append(funcNames, fn.Name.Name)
28+
}
29+
return funcNames
30+
}
31+
32+
func GetBenchmarks(root string) ([]string, error) {
33+
var data []string
34+
fileSystem := os.DirFS(root)
35+
err := fs.WalkDir(fileSystem, ".", func(path string, d fs.DirEntry, err error) error {
36+
if err != nil {
37+
log.Fatal(err)
38+
}
39+
if filepath.Ext(path) != ".go" {
40+
return nil
41+
}
42+
if !strings.HasSuffix(filepath.Base(path), "_test.go") {
43+
return nil
44+
}
45+
fnames := funcNames(path, false)
46+
for _, fname := range fnames {
47+
if strings.HasPrefix(fname, "Benchmark") {
48+
data = append(data, fname)
49+
}
50+
}
51+
return nil
52+
})
53+
return data, err
54+
}

cmd/root.go

+98-7
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,14 @@ limitations under the License.
1616
package cmd
1717

1818
import (
19+
"bytes"
20+
"encoding/json"
1921
"fmt"
2022
"github.com/go-git/go-git/v5"
23+
"io/ioutil"
2124
"log"
25+
"net/http"
26+
"os/exec"
2227
"strings"
2328

2429
"github.com/spf13/cobra"
@@ -31,6 +36,7 @@ var cfgFile string
3136
var bench string
3237
var gitOrg string
3338
var gitRepo string
39+
var gitBranch string
3440
var gitCommit string
3541
var localFilename string
3642
var codeperfUrl string
@@ -43,19 +49,99 @@ var longDescription = ` __ ____ _
4349
\___/\____/\__,_/\___/ .___/\___/_/ /_/ (_) /_/\____/
4450
/_/
4551
46-
Export and persist Go's profiling data locally, or into https://codeperf.io.`
52+
Export and persist Go's performance data into https://codeperf.io.`
4753

4854
// rootCmd represents the base command when called without any subcommands
4955
var rootCmd = &cobra.Command{
50-
Use: "pprof-exporter",
51-
Short: "Export and persist Go's profiling data locally, or into https://codeperf.io.",
56+
Use: "codeperf",
57+
Short: "Export and persist Go's performance into https://codeperf.io.",
5258
Long: longDescription,
53-
Run: exportLogic(),
59+
}
60+
61+
var cmdPrint = &cobra.Command{
62+
Use: "test",
63+
Short: "Print anything to the screen",
64+
Long: `print is for printing anything back to the screen.
65+
For many years people have printed back to the screen.`,
66+
Args: cobra.MinimumNArgs(0),
67+
Run: testLogic,
68+
}
69+
70+
func testLogic(cmd *cobra.Command, args []string) {
71+
// TODO: Check pprof is available on path
72+
const shell = "/bin/bash"
73+
benchmarks, _ := GetBenchmarks(".")
74+
benchtime := "1s"
75+
var err error = nil
76+
77+
goPath, err := exec.LookPath("go")
78+
79+
log.Println(fmt.Sprintf("Detected %d distinct benchmarks.", len(benchmarks)))
80+
for _, benchmark := range benchmarks {
81+
82+
cpuProfileName := fmt.Sprintf("cpuprofile-%s.out", benchmark)
83+
cmdS := fmt.Sprintf("%s test -bench=%s -benchtime=%s -cpuprofile %s .", goPath, benchmark, benchtime, cpuProfileName)
84+
log.Println(fmt.Sprintf("Running benchmark %s with the following command: %s.", benchmark, cmdS))
85+
err := exec.Command(shell, "-c", cmdS).Run()
86+
if err != nil {
87+
log.Fatal(err)
88+
}
89+
granularityOptions := []string{"lines", "functions"}
90+
exportFromPprof(cpuProfileName, benchmark, granularityOptions)
91+
}
92+
coverprofile := "coverage.out"
93+
cmdS := fmt.Sprintf("%s test -cover -bench=. -benchtime=0.01s -coverprofile %s .", goPath, coverprofile)
94+
log.Println(fmt.Sprintf("Calculating the project benchmark coverage with the following command: %s.", cmdS))
95+
c := exec.Command(shell, "-c", cmdS)
96+
var outb, errb bytes.Buffer
97+
c.Stdout = &outb
98+
c.Stderr = &errb
99+
err = c.Run()
100+
if err != nil {
101+
log.Fatal(err)
102+
}
103+
104+
cleaned := strings.TrimSpace(string(outb.String()))
105+
lines := strings.Split(cleaned, "\n")
106+
coverageLine := lines[len(lines)-2]
107+
coverageLineS := strings.Split(coverageLine, ":")
108+
coverageVs := strings.Split(strings.TrimSpace(coverageLineS[1]), " ")[0]
109+
coverageVs = coverageVs[0 : len(coverageVs)-1]
110+
fmt.Println(coverageLine, coverageVs)
111+
exportCoverage(coverageVs)
112+
}
113+
114+
func exportCoverage(vs string) {
115+
postBody, err := json.Marshal(map[string]string{"coverage": vs})
116+
if err != nil {
117+
log.Fatalf("An Error Occured %v", err)
118+
}
119+
fmt.Println(string(postBody))
120+
121+
responseBody := bytes.NewBuffer(postBody)
122+
endPoint := fmt.Sprintf("%s/v1/gh/%s/%s/branch/%s/graph", codeperfApiUrl, gitOrg, gitRepo, gitBranch)
123+
resp, err := http.Post(endPoint, "application/json", responseBody)
124+
//Handle Error
125+
if err != nil {
126+
log.Fatalf("An Error Occured %v", err)
127+
}
128+
defer resp.Body.Close()
129+
130+
//Read the response body
131+
reply, err := ioutil.ReadAll(resp.Body)
132+
if err != nil {
133+
log.Fatalln(err)
134+
}
135+
if resp.StatusCode != 200 {
136+
log.Fatalf("An error ocurred while pushing cpu data to remote %s.\nEndpoint %s. Status code %d. Reply: %s", codeperfApiUrl, endPoint, resp.StatusCode, string(reply))
137+
}
138+
54139
}
55140

56141
// Execute adds all child commands to the root command and sets flags appropriately.
57142
// This is called by main.main(). It only needs to happen once to the rootCmd.
58143
func Execute() {
144+
rootCmd.AddCommand(cmdPrint)
59145
cobra.CheckErr(rootCmd.Execute())
60146
}
61147

@@ -64,12 +150,16 @@ func init() {
64150
defaultGitOrg := ""
65151
defaultGitRepo := ""
66152
defaultGitCommit := ""
153+
defaultGitBranch := ""
67154

68155
r, err := git.PlainOpen(".")
69156
if err != nil {
70-
log.Println("Unable to retrieve current repo git info. Use the --git-org, --git-repo, and --git-hash to properly fill the git info.")
157+
log.Println("Unable to retrieve current repo git info. Use the --git-org, --git-repo, --git-branch and --git-hash to properly fill the git info.")
71158
} else {
72159
ref, _ := r.Head()
160+
if ref.Name().IsBranch() {
161+
defaultGitBranch = ref.Name().Short()
162+
}
73163
refHash := ref.Hash().String()
74164
defaultGitCommit = getShortHash(refHash, 7)
75165
remotes, _ := r.Remotes()
@@ -87,14 +177,15 @@ func init() {
87177

88178
rootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.codeperf.yaml)")
89179
rootCmd.PersistentFlags().BoolVar(&local, "local", false, "don't push the data to https://codeperf.io")
90-
rootCmd.PersistentFlags().StringVar(&bench, "bench", "", "Benchmark name")
91180
rootCmd.PersistentFlags().StringVar(&gitOrg, "git-org", defaultGitOrg, "git org")
92181
rootCmd.PersistentFlags().StringVar(&gitRepo, "git-repo", defaultGitRepo, "git repo")
93182
rootCmd.PersistentFlags().StringVar(&gitCommit, "git-hash", defaultGitCommit, "git commit hash")
183+
rootCmd.PersistentFlags().StringVar(&gitBranch, "git-branch", defaultGitBranch, "git branch")
94184
rootCmd.PersistentFlags().StringVar(&localFilename, "local-filename", "profile.json", "Local file to export the json to. Only used when the --local flag is set")
95185
rootCmd.PersistentFlags().StringVar(&codeperfUrl, "codeperf-url", "https://codeperf.io", "codeperf URL")
96186
rootCmd.PersistentFlags().StringVar(&codeperfApiUrl, "codeperf-api-url", "https://api.codeperf.io", "codeperf API URL")
97-
rootCmd.MarkPersistentFlagRequired("bench")
187+
rootCmd.PersistentFlags().StringVar(&bench, "bench", "", "Benchmark name")
188+
//rootCmd.MarkPersistentFlagRequired("bench")
98189
}
99190

100191
// Abbreviate the long hash to a short hash (7 digits)

get.sh

+1-1
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
export VERIFY_CHECKSUM=0
99
export ALIAS=""
1010
export OWNER=codeperfio
11-
export REPO=pprof-exporter
11+
export REPO=codeperf
1212
export SUCCESS_CMD="$REPO version"
1313
export BINLOCATION="/usr/local/bin"
1414

main.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
Copyright © 2021 codeperf.io hello <at> codeperf <dot> io
2+
Copyright © 2021-present codeperf.io hello <at> codeperf <dot> io
33
44
Licensed under the Apache License, Version 2.0 (the "License");
55
you may not use this file except in compliance with the License.

0 commit comments

Comments
 (0)