Skip to content

Commit 947f4b2

Browse files
Emi Gutekanstvdavid
andauthored
gateway: benchmark: use POST, improve logging slightly (#1129)
* gateway: benchmark: use POST, improve logging slightly Signed-off-by: Stephen Gutekanst <[email protected]> * Add Authorization header --------- Signed-off-by: Stephen Gutekanst <[email protected]> Co-authored-by: David Veszelovszki <[email protected]>
1 parent a441021 commit 947f4b2

File tree

1 file changed

+64
-19
lines changed

1 file changed

+64
-19
lines changed

cmd/src/gateway_benchmark.go

Lines changed: 64 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,23 @@ type Stats struct {
2626
Total time.Duration
2727
}
2828

29+
// httpEndpointConfig represents the configuration for an HTTP endpoint.
30+
type httpEndpointConfig struct {
31+
client *http.Client
32+
url string
33+
}
34+
35+
// sgAuthTransport is an http.RoundTripper that adds an Authorization header to requests.
36+
// It is used to add the Sourcegraph access token to requests to Sourcegraph endpoints.
37+
type sgAuthTransport struct {
38+
token string
39+
base http.RoundTripper
40+
}
41+
func (t *sgAuthTransport) RoundTrip(req *http.Request) (*http.Response, error) {
42+
req.Header.Add("Authorization", "token "+t.token)
43+
return t.base.RoundTrip(req)
44+
}
45+
2946
func init() {
3047
usage := `
3148
'src gateway benchmark' runs performance benchmarks against Cody Gateway endpoints.
@@ -38,7 +55,7 @@ Examples:
3855
3956
$ src gateway benchmark
4057
$ src gateway benchmark --requests 50
41-
$ src gateway benchmark --gateway http://localhost:9992 --sourcegraph http://localhost:3082
58+
$ src gateway benchmark --gateway http://localhost:9992 --sourcegraph http://localhost:3082 --sgp sgp_***** --requests 50
4259
$ src gateway benchmark --requests 50 --csv results.csv
4360
`
4461

@@ -49,6 +66,7 @@ Examples:
4966
csvOutput = flagSet.String("csv", "", "Export results to CSV file (provide filename)")
5067
gatewayEndpoint = flagSet.String("gateway", "https://cody-gateway.sourcegraph.com", "Cody Gateway endpoint")
5168
sgEndpoint = flagSet.String("sourcegraph", "https://sourcegraph.com", "Sourcegraph endpoint")
69+
sgpToken = flagSet.String("sgp", "sgp_*****", "Sourcegraph personal access token for the called instance")
5270
)
5371

5472
handler := func(args []string) error {
@@ -63,43 +81,76 @@ Examples:
6381
var (
6482
gatewayWebsocket, sourcegraphWebsocket *websocket.Conn
6583
err error
66-
httpClient = &http.Client{}
84+
gatewayClient = &http.Client{}
85+
sourcegraphClient = &http.Client{}
6786
endpoints = map[string]any{} // Values: URL `string`s or `*websocket.Conn`s
6887
)
88+
89+
// Connect to endpoints
6990
if *gatewayEndpoint != "" {
91+
fmt.Println("Benchmarking Cody Gateway instance:", *gatewayEndpoint)
7092
wsURL := strings.Replace(fmt.Sprint(*gatewayEndpoint, "/v2/websocket"), "http", "ws", 1)
93+
fmt.Println("Connecting to Cody Gateway via WebSocket..", wsURL)
7194
gatewayWebsocket, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
7295
if err != nil {
7396
return fmt.Errorf("WebSocket dial(%s): %v", wsURL, err)
7497
}
98+
fmt.Println("Connected!")
7599
endpoints["ws(s): gateway"] = gatewayWebsocket
76-
endpoints["http(s): gateway"] = fmt.Sprint(*gatewayEndpoint, "/v2/http")
100+
endpoints["http(s): gateway"] = &httpEndpointConfig{
101+
client: gatewayClient,
102+
url: fmt.Sprint(*gatewayEndpoint, "/v2/http"),
103+
}
104+
} else {
105+
fmt.Println("warning: not benchmarking Cody Gateway (-gateway endpoint not provided)")
77106
}
78107
if *sgEndpoint != "" {
108+
// Add auth header to sourcegraphClient transport
109+
if *sgpToken != "" {
110+
sourcegraphClient.Transport = &sgAuthTransport{
111+
token: *sgpToken,
112+
base: http.DefaultTransport,
113+
}
114+
}
115+
fmt.Println("Benchmarking Sourcegraph instance:", *sgEndpoint)
79116
wsURL := strings.Replace(fmt.Sprint(*sgEndpoint, "/.api/gateway/websocket"), "http", "ws", 1)
80-
sourcegraphWebsocket, _, err = websocket.DefaultDialer.Dial(wsURL, nil)
117+
header := http.Header{}
118+
header.Add("Authorization", "token "+*sgpToken)
119+
fmt.Println("Connecting to Sourcegraph instance via WebSocket..", wsURL)
120+
sourcegraphWebsocket, _, err = websocket.DefaultDialer.Dial(wsURL, header)
81121
if err != nil {
82122
return fmt.Errorf("WebSocket dial(%s): %v", wsURL, err)
83123
}
124+
fmt.Println("Connected!")
125+
84126
endpoints["ws(s): sourcegraph"] = sourcegraphWebsocket
85-
endpoints["http(s): sourcegraph"] = fmt.Sprint(*sgEndpoint, "/.api/gateway/http")
127+
endpoints["http(s): sourcegraph"] = &httpEndpointConfig{
128+
client: sourcegraphClient,
129+
url: fmt.Sprint(*sgEndpoint, "/.api/gateway/http"),
130+
}
131+
endpoints["http(s): http-then-ws"] = &httpEndpointConfig{
132+
client: sourcegraphClient,
133+
url: fmt.Sprint(*sgEndpoint, "/.api/gateway/http-then-websocket"),
134+
}
135+
} else {
136+
fmt.Println("warning: not benchmarking Sourcegraph instance (-sourcegraph endpoint not provided)")
86137
}
87138

88139
fmt.Printf("Starting benchmark with %d requests per endpoint...\n", *requestCount)
89140

90141
var results []endpointResult
91-
for name, clientOrURL := range endpoints {
142+
for name, clientOrEndpointConfig := range endpoints {
92143
durations := make([]time.Duration, 0, *requestCount)
93144
fmt.Printf("\nTesting %s...", name)
94145

95146
for i := 0; i < *requestCount; i++ {
96-
if ws, ok := clientOrURL.(*websocket.Conn); ok {
147+
if ws, ok := clientOrEndpointConfig.(*websocket.Conn); ok {
97148
duration := benchmarkEndpointWebSocket(ws)
98149
if duration > 0 {
99150
durations = append(durations, duration)
100151
}
101-
} else if url, ok := clientOrURL.(string); ok {
102-
duration := benchmarkEndpointHTTP(httpClient, url)
152+
} else if epConf, ok := clientOrEndpointConfig.(httpEndpointConfig); ok {
153+
duration := benchmarkEndpointHTTP(epConf)
103154
if duration > 0 {
104155
durations = append(durations, duration)
105156
}
@@ -161,11 +212,11 @@ type endpointResult struct {
161212
successful int
162213
}
163214

164-
func benchmarkEndpointHTTP(client *http.Client, url string) time.Duration {
215+
func benchmarkEndpointHTTP(epConfig httpEndpointConfig) time.Duration {
165216
start := time.Now()
166-
resp, err := client.Get(url)
217+
resp, err := epConfig.client.Post(epConfig.url, "application/json", strings.NewReader("ping"))
167218
if err != nil {
168-
fmt.Printf("Error calling %s: %v\n", url, err)
219+
fmt.Printf("Error calling %s: %v\n", epConfig.url, err)
169220
return 0
170221
}
171222
defer func() {
@@ -174,12 +225,6 @@ func benchmarkEndpointHTTP(client *http.Client, url string) time.Duration {
174225
fmt.Printf("Error closing response body: %v\n", err)
175226
}
176227
}()
177-
178-
_, err = io.ReadAll(resp.Body)
179-
if err != nil {
180-
fmt.Printf("Error reading response body: %v\n", err)
181-
return 0
182-
}
183228
if resp.StatusCode != http.StatusOK {
184229
fmt.Printf("non-200 response: %v\n", resp.Status)
185230
return 0
@@ -267,7 +312,7 @@ func formatSuccessRate(successful, total int, best bool, worst bool) string {
267312

268313
func printResults(results []endpointResult, requestCount *int) {
269314
// Print header
270-
headerFmt := ansiColors["blue"] + "%-20s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s" + ansiColors["nc"] + "\n"
315+
headerFmt := ansiColors["blue"] + "%-25s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s | %-10s" + ansiColors["nc"] + "\n"
271316
fmt.Printf("\n"+headerFmt,
272317
"Endpoint ", "Average", "Median", "P5", "P75", "P80", "P95", "Total", "Success")
273318
fmt.Println(ansiColors["blue"] + strings.Repeat("-", 121) + ansiColors["nc"])

0 commit comments

Comments
 (0)