Skip to content

Commit be3d5fa

Browse files
Rewrite metrics calculation and retrieval
This commit moves most of the aggregation logic into the cli leaving the goad runners with a cleaner implementation of the metrics to transmit to the cli. We introduce a runner id that allows tracking of the individual lambdas being executed on aws and later aggregation of results for different aws regions. The infrastructure package has been restructured to move more of the aws specific functionality into the corresponding packages. A VSCode debug configuration has been added to version control. Closes goadapp#143
1 parent 1d56f40 commit be3d5fa

File tree

13 files changed

+495
-399
lines changed

13 files changed

+495
-399
lines changed

.vscode/launch.json

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
{
2+
"version": "0.2.0",
3+
"configurations": [
4+
5+
{
6+
"name": "Launch Cli",
7+
"type": "go",
8+
"request": "launch",
9+
"mode": "debug",
10+
"remotePath": "",
11+
"port": 2345,
12+
"host": "127.0.0.1",
13+
"program": "${workspaceRoot}",
14+
"env": {},
15+
"args": [],
16+
"showLog": true
17+
}
18+
]
19+
}

api/api.go

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package api
2+
3+
import "time"
4+
5+
// RunnerResult defines the common API for goad runners to send data back to the
6+
// cli.
7+
type RunnerResult struct {
8+
AveTimeForReq int64 `json:"ave-time-for-req"`
9+
AveTimeToFirst int64 `json:"ave-time-to-first"`
10+
Fastest int64 `json:"fastest"`
11+
FatalError string `json:"fatal-error"`
12+
Finished bool `json:"finished"`
13+
Region string `json:"region"`
14+
RunnerID int `json:"runner-id"`
15+
Slowest int64 `json:"slowest"`
16+
Statuses map[string]int `json:"statuses"`
17+
TimeDelta time.Duration `json:"time-delta"`
18+
BytesRead int `json:"bytes-read"`
19+
ConnectionErrors int `json:"connection-errors"`
20+
RequestCount int `json:"request-count"`
21+
TimedOut int `json:"timed-out"`
22+
}

cli/cli.go

Lines changed: 32 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ import (
1010
"os"
1111
"os/signal"
1212
"reflect"
13-
"sort"
1413
"strconv"
1514
"strings"
1615
"syscall"
@@ -21,7 +20,7 @@ import (
2120

2221
"github.com/dustin/go-humanize"
2322
"github.com/goadapp/goad/goad"
24-
"github.com/goadapp/goad/queue"
23+
"github.com/goadapp/goad/result"
2524
"github.com/goadapp/goad/version"
2625
"github.com/nsf/termbox-go"
2726
)
@@ -82,17 +81,14 @@ func Run() {
8281
config := aggregateConfiguration()
8382
test := createGoadTest(config)
8483

85-
var finalResult queue.RegionsAggData
86-
defer printSummary(&finalResult)
87-
88-
if config.Output != "" {
89-
defer saveJSONSummary(*outputFile, &finalResult)
90-
}
91-
9284
sigChan := make(chan os.Signal, 1)
9385
signal.Notify(sigChan, syscall.SIGINT, syscall.SIGTERM) // but interrupts from kbd are blocked by termbox
9486

95-
start(test, &finalResult, sigChan)
87+
result := start(test, sigChan)
88+
defer printSummary(result)
89+
if config.Output != "" {
90+
defer saveJSONSummary(*outputFile, result)
91+
}
9692
}
9793

9894
func writeIniFile() {
@@ -298,7 +294,8 @@ func createGoadTest(config *goad.TestConfig) *goad.Test {
298294
return test
299295
}
300296

301-
func start(test *goad.Test, finalResult *queue.RegionsAggData, sigChan chan os.Signal) {
297+
func start(test *goad.Test, sigChan chan os.Signal) result.LambdaResults {
298+
var currentResult result.LambdaResults
302299
resultChan, teardown := test.Start()
303300
defer teardown()
304301

@@ -337,43 +334,37 @@ outer:
337334
if !ok {
338335
break outer
339336
}
340-
337+
currentResult = *result
341338
if firstTime {
342339
clearLogo()
343340
firstTime = false
344341
}
345342

346-
// sort so that regions always appear in the same order
347-
var regions []string
348-
for key := range result.Regions {
349-
regions = append(regions, key)
350-
}
351-
sort.Strings(regions)
352343
y := 3
353344
totalReqs := 0
354-
for _, region := range regions {
355-
data := result.Regions[region]
356-
totalReqs += data.TotalReqs
357-
y = renderRegion(data, y)
345+
regionsData := currentResult.RegionsData()
346+
for _, region := range currentResult.Regions() {
347+
totalReqs += regionsData[region].TotalReqs
348+
y = renderRegion(regionsData[region], y)
358349
y++
359350
}
360351

361352
y = 0
362353
var percentDone float64
363-
if result.TotalExpectedRequests > 0 {
364-
percentDone = float64(totalReqs) / float64(result.TotalExpectedRequests)
354+
if test.Config.Requests > 0 {
355+
percentDone = float64(totalReqs) / float64(test.Config.Requests)
365356
} else {
366357
percentDone = math.Min(float64(time.Since(startTime).Seconds())/float64(test.Config.Timelimit), 1.0)
367358
}
368359
drawProgressBar(percentDone, y)
369360

370361
termbox.Flush()
371-
finalResult.Regions = result.Regions
372362

373363
case <-sigChan:
374364
break outer
375365
}
376366
}
367+
return currentResult
377368
}
378369

379370
func renderLogo() {
@@ -400,7 +391,7 @@ func clearLogo() {
400391
}
401392

402393
// renderRegion returns the y for the next empty line
403-
func renderRegion(data queue.AggData, y int) int {
394+
func renderRegion(data result.AggData, y int) int {
404395
x := 0
405396
renderString(x, y, "Region: ", termbox.ColorWhite, termbox.ColorBlue)
406397
x += 8
@@ -417,14 +408,14 @@ func renderRegion(data queue.AggData, y int) int {
417408
headingStr = " Slowest Fastest Timeouts TotErrors"
418409
renderString(x, y, headingStr, coldef|termbox.AttrBold, coldef)
419410
y++
420-
resultStr = fmt.Sprintf(" %7.3fs %7.3fs %10d %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, data.TotalTimedOut, totErrors(&data))
411+
resultStr = fmt.Sprintf(" %7.3fs %7.3fs %10d %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, data.TotalTimedOut, totErrors(data))
421412
renderString(x, y, resultStr, coldef, coldef)
422413
y++
423414

424415
return y
425416
}
426417

427-
func totErrors(data *queue.AggData) int {
418+
func totErrors(data result.AggData) int {
428419
var okReqs int
429420
for statusStr, value := range data.Statuses {
430421
status, _ := strconv.Atoi(statusStr)
@@ -463,28 +454,29 @@ func boldPrintln(msg string) {
463454
fmt.Printf("\033[1m%s\033[0m\n", msg)
464455
}
465456

466-
func printData(data *queue.AggData) {
457+
func printData(data result.AggData) {
467458
boldPrintln(" TotReqs TotBytes AvgTime AvgReq/s (post)unzip")
468459
fmt.Printf("%10d %10s %7.3fs %10.2f %10s/s\n", data.TotalReqs, humanize.Bytes(uint64(data.TotBytesRead)), float64(data.AveTimeForReq)/nano, data.AveReqPerSec, humanize.Bytes(uint64(data.AveKBytesPerSec)))
469460
boldPrintln(" Slowest Fastest Timeouts TotErrors")
470461
fmt.Printf(" %7.3fs %7.3fs %10d %10d", float64(data.Slowest)/nano, float64(data.Fastest)/nano, data.TotalTimedOut, totErrors(data))
471462
fmt.Println("")
472463
}
473464

474-
func printSummary(result *queue.RegionsAggData) {
475-
if len(result.Regions) == 0 {
465+
func printSummary(results result.LambdaResults) {
466+
if len(results.Regions()) == 0 {
476467
boldPrintln("No results received")
477468
return
478469
}
479470
boldPrintln("Regional results")
480471
fmt.Println("")
481472

482-
for region, data := range result.Regions {
473+
regionsData := results.RegionsData()
474+
for _, region := range results.Regions() {
483475
fmt.Println("Region: " + region)
484-
printData(&data)
476+
printData(regionsData[region])
485477
}
486478

487-
overall := queue.SumRegionResults(result)
479+
overall := results.SumAllLambdas()
488480

489481
fmt.Println("")
490482
boldPrintln("Overall")
@@ -498,20 +490,16 @@ func printSummary(result *queue.RegionsAggData) {
498490
fmt.Println("")
499491
}
500492

501-
func saveJSONSummary(path string, result *queue.RegionsAggData) {
502-
if len(result.Regions) == 0 {
493+
func saveJSONSummary(path string, results result.LambdaResults) {
494+
if len(results.Regions()) == 0 {
503495
return
504496
}
505-
results := make(map[string]queue.AggData)
506-
507-
for region, data := range result.Regions {
508-
results[region] = data
509-
}
497+
dataForRegions := results.RegionsData()
510498

511-
overall := queue.SumRegionResults(result)
499+
overall := results.SumAllLambdas()
512500

513-
results["overall"] = *overall
514-
b, err := json.MarshalIndent(results, "", " ")
501+
dataForRegions["overall"] = overall
502+
b, err := json.MarshalIndent(dataForRegions, "", " ")
515503
if err != nil {
516504
fmt.Println(err)
517505
return

goad/goad.go

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
"github.com/goadapp/goad/infrastructure"
1313
"github.com/goadapp/goad/infrastructure/aws"
1414
"github.com/goadapp/goad/infrastructure/docker"
15-
"github.com/goadapp/goad/queue"
15+
"github.com/goadapp/goad/result"
1616
)
1717

1818
// TestConfig type
@@ -57,9 +57,10 @@ var supportedRegions = []string{
5757

5858
// Test type
5959
type Test struct {
60-
Config *TestConfig
61-
infra infrastructure.Infrastructure
62-
lambdas int
60+
Config *TestConfig
61+
infra infrastructure.Infrastructure
62+
lambdas int
63+
currentID int
6364
}
6465

6566
// NewTest returns a configured Test
@@ -72,7 +73,7 @@ func NewTest(config *TestConfig) (*Test, error) {
7273
}
7374

7475
// Start a test
75-
func (t *Test) Start() (<-chan queue.RegionsAggData, func()) {
76+
func (t *Test) Start() (<-chan *result.LambdaResults, func()) {
7677
awsConfig := aws.NewConfig().WithRegion(t.Config.Regions[0])
7778

7879
if t.Config.RunDocker {
@@ -87,10 +88,10 @@ func (t *Test) Start() (<-chan queue.RegionsAggData, func()) {
8788
t.lambdas = numberOfLambdas(t.Config.Concurrency, len(t.Config.Regions))
8889
t.invokeLambdas()
8990

90-
results := make(chan queue.RegionsAggData)
91+
results := make(chan *result.LambdaResults)
9192

9293
go func() {
93-
for result := range queue.Aggregate(awsConfig, t.infra.GetQueueURL(), t.Config.Requests, t.lambdas) {
94+
for result := range result.Aggregate(awsConfig, t.infra.GetQueueURL(), t.Config.Requests, t.lambdas) {
9495
results <- result
9596
}
9697
close(results)
@@ -121,8 +122,10 @@ func (t *Test) invokeLambdas() {
121122
fmt.Sprintf("--frequency=%s", reportingFrequency(t.lambdas).String()),
122123
fmt.Sprintf("--aws-region=%s", region),
123124
fmt.Sprintf("--method=%s", c.Method),
125+
fmt.Sprintf("--runner-id=%d", t.currentID),
124126
fmt.Sprintf("--body=%s", c.Body),
125127
}
128+
t.currentID++
126129
for _, v := range t.Config.Headers {
127130
args = append(args, fmt.Sprintf("--header=%s", v))
128131
}

goad/util/util.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package util
2+
3+
func RemoveDuplicates(strs []string) []string {
4+
strsMap := make(map[string]bool)
5+
for _, str := range strs {
6+
strsMap[str] = true
7+
}
8+
returnStrs := make([]string, 0)
9+
for str := range strsMap {
10+
returnStrs = append(returnStrs, str)
11+
}
12+
return returnStrs
13+
}

0 commit comments

Comments
 (0)