• Home
  • History
  • Annotate
Name Date Size #Lines LOC

..30-Apr-2019-

readme.goH A D30-Apr-20195.9 KiB210171

readme.go

1// Copyright (c) 2016 Uber Technologies, Inc.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in
11// all copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19// THE SOFTWARE.
20
21package main
22
23import (
24	"flag"
25	"fmt"
26	"io/ioutil"
27	"log"
28	"os"
29	"os/exec"
30	"sort"
31	"strconv"
32	"strings"
33	"text/template"
34	"time"
35)
36
37var (
38	libraryNameToMarkdownName = map[string]string{
39		"Zap":                   ":zap: zap",
40		"Zap.Sugar":             ":zap: zap (sugared)",
41		"stdlib.Println":        "standard library",
42		"sirupsen/logrus":       "logrus",
43		"go-kit/kit/log":        "go-kit",
44		"inconshreveable/log15": "log15",
45		"apex/log":              "apex/log",
46		"go.pedge.io/lion":      "lion",
47		"rs/zerolog":            "zerolog",
48	}
49)
50
51func main() {
52	flag.Parse()
53	if err := do(); err != nil {
54		log.Fatal(err)
55	}
56}
57
58func do() error {
59	tmplData, err := getTmplData()
60	if err != nil {
61		return err
62	}
63	data, err := ioutil.ReadAll(os.Stdin)
64	if err != nil {
65		return err
66	}
67	t, err := template.New("tmpl").Parse(string(data))
68	if err != nil {
69		return err
70	}
71	return t.Execute(os.Stdout, tmplData)
72}
73
74func getTmplData() (*tmplData, error) {
75	tmplData := &tmplData{}
76	rows, err := getBenchmarkRows("BenchmarkAddingFields")
77	if err != nil {
78		return nil, err
79	}
80	tmplData.BenchmarkAddingFields = rows
81	rows, err = getBenchmarkRows("BenchmarkAccumulatedContext")
82	if err != nil {
83		return nil, err
84	}
85	tmplData.BenchmarkAccumulatedContext = rows
86	rows, err = getBenchmarkRows("BenchmarkWithoutFields")
87	if err != nil {
88		return nil, err
89	}
90	tmplData.BenchmarkWithoutFields = rows
91	return tmplData, nil
92}
93
94func getBenchmarkRows(benchmarkName string) (string, error) {
95	benchmarkOutput, err := getBenchmarkOutput(benchmarkName)
96	if err != nil {
97		return "", err
98	}
99	var benchmarkRows []*benchmarkRow
100	for libraryName := range libraryNameToMarkdownName {
101		benchmarkRow, err := getBenchmarkRow(benchmarkOutput, benchmarkName, libraryName)
102		if err != nil {
103			return "", err
104		}
105		if benchmarkRow == nil {
106			continue
107		}
108		benchmarkRows = append(benchmarkRows, benchmarkRow)
109	}
110	sort.Sort(benchmarkRowsByTime(benchmarkRows))
111	rows := []string{
112		"| Package | Time | Objects Allocated |",
113		"| :--- | :---: | :---: |",
114	}
115	for _, benchmarkRow := range benchmarkRows {
116		rows = append(rows, benchmarkRow.String())
117	}
118	return strings.Join(rows, "\n"), nil
119}
120
121func getBenchmarkRow(input []string, benchmarkName string, libraryName string) (*benchmarkRow, error) {
122	line, err := findUniqueSubstring(input, fmt.Sprintf("%s/%s-", benchmarkName, libraryName))
123	if err != nil {
124		return nil, err
125	}
126	if line == "" {
127		return nil, nil
128	}
129	split := strings.Split(line, "\t")
130	if len(split) < 5 {
131		return nil, fmt.Errorf("unknown benchmark line: %s", line)
132	}
133	duration, err := time.ParseDuration(strings.Replace(strings.TrimSuffix(strings.TrimSpace(split[2]), "/op"), " ", "", -1))
134	if err != nil {
135		return nil, err
136	}
137	allocatedBytes, err := strconv.Atoi(strings.TrimSuffix(strings.TrimSpace(split[3]), " B/op"))
138	if err != nil {
139		return nil, err
140	}
141	allocatedObjects, err := strconv.Atoi(strings.TrimSuffix(strings.TrimSpace(split[4]), " allocs/op"))
142	if err != nil {
143		return nil, err
144	}
145	return &benchmarkRow{
146		libraryNameToMarkdownName[libraryName],
147		duration,
148		allocatedBytes,
149		allocatedObjects,
150	}, nil
151}
152
153func findUniqueSubstring(input []string, substring string) (string, error) {
154	var output string
155	for _, line := range input {
156		if strings.Contains(line, substring) {
157			if output != "" {
158				return "", fmt.Errorf("input has duplicate substring %s", substring)
159			}
160			output = line
161		}
162	}
163	return output, nil
164}
165
166func getBenchmarkOutput(benchmarkName string) ([]string, error) {
167	return getOutput("go", "test", fmt.Sprintf("-bench=%s", benchmarkName), "-benchmem", "./benchmarks")
168}
169
170func getOutput(name string, arg ...string) ([]string, error) {
171	output, err := exec.Command(name, arg...).CombinedOutput()
172	if err != nil {
173		return nil, fmt.Errorf("error running %s %s: %v\n%s", name, strings.Join(arg, " "), err, string(output))
174	}
175	return strings.Split(string(output), "\n"), nil
176}
177
178type tmplData struct {
179	BenchmarkAddingFields       string
180	BenchmarkAccumulatedContext string
181	BenchmarkWithoutFields      string
182}
183
184type benchmarkRow struct {
185	Name             string
186	Time             time.Duration
187	AllocatedBytes   int
188	AllocatedObjects int
189}
190
191func (b *benchmarkRow) String() string {
192	return fmt.Sprintf("| %s | %d ns/op | %d allocs/op |", b.Name, b.Time.Nanoseconds(), b.AllocatedObjects)
193}
194
195type benchmarkRowsByTime []*benchmarkRow
196
197func (b benchmarkRowsByTime) Len() int      { return len(b) }
198func (b benchmarkRowsByTime) Swap(i, j int) { b[i], b[j] = b[j], b[i] }
199func (b benchmarkRowsByTime) Less(i, j int) bool {
200	left, right := b[i], b[j]
201	leftZap, rightZap := strings.Contains(left.Name, "zap"), strings.Contains(right.Name, "zap")
202
203	// If neither benchmark is for zap or both are, sort by time.
204	if !(leftZap || rightZap) || (leftZap && rightZap) {
205		return left.Time.Nanoseconds() < right.Time.Nanoseconds()
206	}
207	// Sort zap benchmark first.
208	return leftZap
209}
210