Skip to content

Commit 7a616d9

Browse files
committed
Initial commit
0 parents  commit 7a616d9

1,299 files changed

Lines changed: 353966 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
/*.json
2+
/binaries/
3+
/release/

Gopkg.lock

Lines changed: 63 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Gopkg.toml

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
2+
# Gopkg.toml example
3+
#
4+
# Refer to https://github.com/golang/dep/blob/master/docs/Gopkg.toml.md
5+
# for detailed Gopkg.toml documentation.
6+
#
7+
# required = ["github.com/user/thing/cmd/thing"]
8+
# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"]
9+
#
10+
# [[constraint]]
11+
# name = "github.com/user/project"
12+
# version = "1.0.0"
13+
#
14+
# [[constraint]]
15+
# name = "github.com/user/project2"
16+
# branch = "dev"
17+
# source = "github.com/myfork/project2"
18+
#
19+
# [[override]]
20+
# name = "github.com/x/y"
21+
# version = "2.4.0"
22+
23+
24+
[[constraint]]
25+
name = "github.com/gonum/stat"
26+
branch = "master"
27+
28+
[[constraint]]
29+
name = "github.com/schollz/progressbar"
30+
branch = "master"

Makefile

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
VERSION = 1.0.0
2+
3+
APP := tcp-time
4+
PACKAGES := $(shell go list -f {{.Dir}} ./...)
5+
GOFILES := $(addsuffix /*.go,$(PACKAGES))
6+
GOFILES := $(wildcard $(GOFILES))
7+
8+
.PHONY: clean release docker docker-latest
9+
10+
# go get -u github.com/github/hub
11+
release: zip
12+
git push
13+
hub release delete $(VERSION) || true
14+
hub release create $(VERSION) -m "$(VERSION)" -a release/$(APP)_$(VERSION)_osx_x86_64.zip -a release/$(APP)_$(VERSION)_windows_x86_64.zip -a release/$(APP)_$(VERSION)_linux_x86_64.zip
15+
16+
docker: binaries/linux_x86_64/$(APP)
17+
docker build -t quay.io/sergey_grebenshchikov/$(APP):v$(VERSION) .
18+
docker push quay.io/sergey_grebenshchikov/$(APP):v$(VERSION)
19+
20+
docker-latest: docker
21+
docker tag quay.io/sergey_grebenshchikov/$(APP):v$(VERSION) quay.io/sergey_grebenshchikov/$(APP):latest
22+
docker push quay.io/sergey_grebenshchikov/$(APP):latest
23+
24+
zip: release/$(APP)_$(VERSION)_osx_x86_64.zip release/$(APP)_$(VERSION)_windows_x86_64.zip release/$(APP)_$(VERSION)_linux_x86_64.zip
25+
26+
binaries: binaries/osx_x86_64/$(APP) binaries/windows_x86_64/$(APP).exe binaries/linux_x86_64/$(APP)
27+
28+
clean:
29+
rm -rf binaries/
30+
rm -rf release/
31+
32+
release/$(APP)_$(VERSION)_osx_x86_64.zip: binaries/osx_x86_64/$(APP)
33+
mkdir -p release
34+
cd ./binaries/osx_x86_64 && zip -r -D ../../release/$(APP)_$(VERSION)_osx_x86_64.zip $(APP)
35+
36+
binaries/osx_x86_64/$(APP): $(GOFILES)
37+
GOOS=darwin GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/osx_x86_64/$(APP) ./cmd/$(APP)
38+
39+
release/$(APP)_$(VERSION)_windows_x86_64.zip: binaries/windows_x86_64/$(APP).exe
40+
mkdir -p release
41+
cd ./binaries/windows_x86_64 && zip -r -D ../../release/$(APP)_$(VERSION)_windows_x86_64.zip $(APP).exe
42+
43+
binaries/windows_x86_64/$(APP).exe: $(GOFILES)
44+
GOOS=windows GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/windows_x86_64/$(APP).exe ./cmd/$(APP)
45+
46+
release/$(APP)_$(VERSION)_linux_x86_64.zip: binaries/linux_x86_64/$(APP)
47+
mkdir -p release
48+
cd ./binaries/linux_x86_64 && zip -r -D ../../release/$(APP)_$(VERSION)_linux_x86_64.zip $(APP)
49+
50+
binaries/linux_x86_64/$(APP): $(GOFILES)
51+
GOOS=linux GOARCH=amd64 go build -ldflags "-X main.version=$(VERSION)" -o binaries/linux_x86_64/$(APP) ./cmd/$(APP)

README.md

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
# tcp-time
2+
3+
Repeatedly measures TCP connection durations to a given target. Prints the measurements and a summary (mean, standard deviation, quantiles, histogram) as JSON to stdout.
4+
5+
<!-- TOC -->
6+
7+
- [Get it](#get-it)
8+
- [Use it](#use-it)
9+
- [Example](#example)
10+
11+
<!-- /TOC -->
12+
13+
## Get it
14+
15+
```bash
16+
go get -u github.com/sgreben/tcp-time/cmd/tcp-time
17+
```
18+
19+
Or [download the binary](https://github.com/sgreben/tcp-time/releases/latest) from the releases page.
20+
21+
```bash
22+
# Linux
23+
curl -LO https://github.com/sgreben/tcp-time/releases/download/1.0.0/tcp-time_1.0.0_linux_x86_64.zip
24+
unzip tcp-time_1.0.0_linux_x86_64.zip
25+
26+
# OS X
27+
curl -LO https://github.com/sgreben/tcp-time/releases/download/1.0.0/tcp-time_1.0.0_osx_x86_64.zip
28+
unzip tcp-time_1.0.0_osx_x86_64.zip
29+
30+
# Windows
31+
curl -LO https://github.com/sgreben/tcp-time/releases/download/1.0.0/tcp-time_1.0.0_windows_x86_64.zip
32+
unzip tcp-time_1.0.0_windows_x86_64.zip
33+
```
34+
35+
## Use it
36+
37+
```text
38+
Usage of tcp-time:
39+
-target string
40+
host:port to ping. (default "duckduckgo.com:443")
41+
-n int
42+
Number of connections to make. (default 10)
43+
-p int
44+
Number of connections to make in parallel. (default 3)
45+
-b int
46+
Number of histogram bins. (default 5)
47+
-progress
48+
Print a progress bar to stderr.
49+
-debug
50+
Print debug logs to stderr.
51+
```
52+
53+
## Example
54+
55+
```bash
56+
$ tcp-time -n 1000 | jq .
57+
{
58+
"Measurements": [
59+
{
60+
"Valid": true,
61+
"Duration": 40605393
62+
},
63+
{
64+
"Valid": true,
65+
"Duration": 35469927
66+
},
67+
# ...
68+
],
69+
"Summary": {
70+
"All": {
71+
"Mean": 36694356.154,
72+
"StdDev": 31847099.84842516,
73+
"Quantiles": [ 32873052, 34962729, 36098973, 37387095, 89838530 ],
74+
"Histogram": [
75+
{
76+
"Label": "32.873052ms",
77+
"Value": 32873052,
78+
"Count": 990
79+
},
80+
{
81+
"Label": "47.114421ms",
82+
"Value": 47114421,
83+
"Count": 2
84+
},
85+
{
86+
"Label": "61.355791ms",
87+
"Value": 61355791,
88+
"Count": 2
89+
},
90+
{
91+
"Label": "75.597161ms",
92+
"Value": 75597161,
93+
"Count": 6
94+
}
95+
]
96+
}
97+
}
98+
}
99+
```

cmd/tcp-time/main.go

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
package main
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"flag"
7+
"io/ioutil"
8+
"log"
9+
"os"
10+
"sync"
11+
12+
"github.com/schollz/progressbar"
13+
"golang.org/x/sync/semaphore"
14+
)
15+
16+
type configuration struct {
17+
Target string
18+
N int
19+
Parallel int
20+
HistogramBins int
21+
Debug bool
22+
Progress bool
23+
}
24+
25+
type output struct {
26+
Measurements measurements
27+
Summary summary
28+
}
29+
30+
var config configuration
31+
32+
func init() {
33+
flag.StringVar(&config.Target, "target", "duckduckgo.com:443", "host:port to ping.")
34+
flag.IntVar(&config.N, "n", 10, "Number of pings to make.")
35+
flag.IntVar(&config.Parallel, "p", 3, "Number of pings to make in parallel.")
36+
flag.IntVar(&config.HistogramBins, "b", 5, "Number of histogram bins.")
37+
flag.BoolVar(&config.Debug, "debug", false, "Print debug logs to stderr.")
38+
flag.BoolVar(&config.Progress, "progress", false, "Print a progress bar to stderr.")
39+
flag.Parse()
40+
log.SetOutput(os.Stderr)
41+
if !config.Debug {
42+
log.SetOutput(ioutil.Discard)
43+
}
44+
}
45+
46+
func main() {
47+
var output output
48+
var mu sync.Mutex
49+
var wg sync.WaitGroup
50+
ctx := context.Background()
51+
limit := semaphore.NewWeighted(int64(config.Parallel))
52+
var bar *progressbar.ProgressBar
53+
if config.Progress {
54+
bar = progressbar.New(config.N)
55+
bar.SetWriter(os.Stderr)
56+
}
57+
58+
for i := 0; i < config.N; i++ {
59+
wg.Add(1)
60+
go func() {
61+
defer wg.Done()
62+
if config.Progress {
63+
defer bar.Add(1)
64+
}
65+
limit.Acquire(ctx, 1)
66+
defer limit.Release(1)
67+
d, err := connectDuration(config.Target)
68+
mu.Lock()
69+
defer mu.Unlock()
70+
output.Measurements.append(sample{
71+
Valid: err == nil,
72+
Duration: d,
73+
})
74+
}()
75+
}
76+
wg.Wait()
77+
output.Summary = output.Measurements.summary()
78+
enc := json.NewEncoder(os.Stdout)
79+
enc.Encode(output)
80+
}

cmd/tcp-time/measure.go

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
package main
2+
3+
import (
4+
"sort"
5+
"time"
6+
)
7+
8+
type sample struct {
9+
Valid bool
10+
Duration time.Duration
11+
}
12+
13+
type measurements []sample
14+
15+
func (m *measurements) append(s sample) {
16+
*m = append(*m, s)
17+
}
18+
19+
func (m *measurements) invalidCount() (out int) {
20+
for _, s := range *m {
21+
if !s.Valid {
22+
out++
23+
}
24+
}
25+
return
26+
}
27+
func (m *measurements) allSeconds() []float64 {
28+
out := make([]float64, len(*m))
29+
for i, s := range *m {
30+
out[i] = float64(s.Duration)
31+
}
32+
sort.Float64s(out)
33+
return out
34+
}
35+
36+
func (m *measurements) validSeconds() []float64 {
37+
out := make([]float64, 0, len(*m))
38+
for _, s := range *m {
39+
if s.Valid {
40+
out = append(out, float64(s.Duration))
41+
}
42+
}
43+
sort.Float64s(out)
44+
return out
45+
}

0 commit comments

Comments
 (0)