Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add src gateway benchmark command #1124

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

vdavid
Copy link

@vdavid vdavid commented Nov 11, 2024

Adds the src gateway benchmark command to the tool.

This is a WIP.

Missing work to be done:

  • Add a direct call to Cody Gateway. Endpoints are at:
    • {codyGatewayUrl}/v1/hello-http and
    • {codyGatewayUrl}/v1/hello-websocket.
  • Docs?

Test plan

Tested manually:

  1. go run ./cmd/src lists the new gateway command correctly.
  2. go run ./cmd/src gateway lists the benchmark subcommand correctly.
  3. go run ./cmd/src gateway benchmark runs the benchmarks against the endpoint set in the SRC_ENDPOINT env var correctly.
  4. go run ./cmd/src gateway benchmark --requests 2 sets the number of requests correctly.
  5. SRC_ENDPOINT=http://localhost:3080 go run ./cmd/src gateway benchmark --requests 2 sets the endpoint to my localhost and works correctly.

@vdavid vdavid requested a review from slimsag November 11, 2024 13:34
var gatewayCommands commander

func init() {
usage := `'src gateway' manages Cody Gateway operations on a Sourcegraph instance.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since Cody Gateway doesn't run as part of a Sourcegraph instance, I think this phrasing is maybe a bit confusing?

Perhaps "interacts with Cody Gateway directly or through a Sourcegraph instance" may be better?

green = "\033[32m"
yellow = "\033[33m"
red = "\033[31m"
reset = "\033[0m"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flagSet := flag.NewFlagSet("benchmark", flag.ExitOnError)

var (
requestCount = flagSet.Int("requests", defaultRequestCount, "Number of requests to make per endpoint")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe just write defaultRequestCount inline here instead of a constant (easier to see what the defautl is that way, less likely to conflict with other constants / files in the folder)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also may want to bump this to something statistically significant (e.x. 1000)

@@ -53,6 +53,7 @@ The commands are:
config manages global, org, and user settings
extensions,ext manages extensions (experimental)
extsvc manages external services
gateway manages Cody Gateway
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
gateway manages Cody Gateway
gateway interact with Cody Gateway

Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
},
}
Copy link
Member

@slimsag slimsag Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's fine if we have a CLI option for --insecure to disable TLS for testing against local dev, but this wouldn't match a real prod environment (where TLS verification may be a substantial overhead) so let's make sure we have TLS verification enabled by default here


endpoints := map[string]string{
"HTTP": fmt.Sprintf("%s/cody-gateway-call-http", cfg.Endpoint),
"HTTP then WebSocket": fmt.Sprintf("%s/cody-gateway-call-http-then-websocket", cfg.Endpoint),
Copy link
Member

@slimsag slimsag Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's work torwards naming these endpoints whatever the real V2 API endpoint would be named (esp. before merging)

if duration > 0 {
durations = append(durations, duration)
}
fmt.Printf("\rTesting %s: %d/%d", name, i+1, *requestCount)
Copy link
Member

@slimsag slimsag Nov 14, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's drop this print statement, or make it only print on every 1/10th of the requestCount - to reduce the chance that printing each request adds non-deterministic latency.

}
fmt.Println()

avg, p5, p95, median, total := calculateStats(durations)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's make calculateStats return a struct with these as fields, so there's no chance we get the order wrong here and look at the wrong thing by accident.

fmt.Printf("Error reading response body: %v\n", err)
return 0
}
fmt.Printf("Response from %s: %s\n", url, body)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

similarly, let's drop this print statement in the success path

}

sort.Slice(durations, func(i, j int) bool {
return durations[i] < durations[j]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

adding a note here for me to triple check we got the order right here; just don't want any chance we've got p95 and p5 inverted.

Actually; could you add p80 and p75 as well? that'd make it clear and might be useful to collect anyway.

return yellow + value + reset
}

func printResults(results []endpointResult, requestCount *int) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we add a CLI flag to dump the results as e.g. a CSV as well? When we hand this out to ~10 people to collect results it might be nicer when we try to import them into e.g. a google sheet

@slimsag
Copy link
Member

slimsag commented Nov 14, 2024

Cool, great starting point! can you get this client talking to / benchmarking 4 endpoints?

e.g. with one test src gateway benchmark -endpoint=$CODY_GATEWAY_URL -sourcegraph=$SG_INSTANCE_URL I'd love for it to benchmark:

  1. {CODY_GATEWAY_URL}/v2 (HTTP)
  2. {CODY_GATEWAY_URL}/v2/websocket (websocket)
  3. {SG_INSTANCE_URL}/.api/gateway (HTTP)
  4. {SG_INSTANCE_URL}/.api/gateway/websocket (websocket)

i.e. if the user passes -endpoint then run (1) and (2), if the user passes -sourcegraph then run (3) and (4), if they pass both then run all 4.

Then the default if you pass nothing can be to run against Cody Gateway prod and Sourcegraph.com

For (2) and (4) you'll need to add a websocket client to this PR, you should be able to do that testing against any websocket server until I have a chance to debug the issue you brought up with doing it in the SG instance.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants