refactor(perf): expose single latency measurement (#207)
This commit is contained in:
parent
81b6e7c370
commit
cdf7820037
|
@ -51,7 +51,9 @@ _WARNING_: Running the perf tests might take a while.
|
||||||
- Logging MUST go to stderr.
|
- Logging MUST go to stderr.
|
||||||
- Measurement output is printed to stdout as JSON in the form of:
|
- Measurement output is printed to stdout as JSON in the form of:
|
||||||
```json
|
```json
|
||||||
{"connectionEstablishedSeconds":0.246442851,"uploadSeconds":0.000002077,"downloadSeconds":0.060712241}
|
{"latency": 0.246442851}
|
||||||
```
|
```
|
||||||
|
Note that the measurement includes the time to (1) establish the
|
||||||
|
connection, (2) upload the bytes and (3) download the bytes.
|
||||||
2. In `impl/Makefile` include your implementation in the `all` target.
|
2. In `impl/Makefile` include your implementation in the `all` target.
|
||||||
3. Reference implementation in `runner/src/versions.ts`.
|
3. Reference implementation in `runner/src/versions.ts`.
|
||||||
|
|
|
@ -82,17 +82,14 @@ func main() {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to dial peer: %s", err)
|
log.Fatalf("failed to dial peer: %s", err)
|
||||||
}
|
}
|
||||||
connectionEstablished := time.Since(start)
|
|
||||||
|
|
||||||
upload, download, err := perf.RunPerf(context.Background(), serverInfo.ID, uint64(*uploadBytes), uint64(*downloadBytes))
|
err = perf.RunPerf(context.Background(), serverInfo.ID, uint64(*uploadBytes), uint64(*downloadBytes))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to execute perf: %s", err)
|
log.Fatalf("failed to execute perf: %s", err)
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonB, err := json.Marshal(Result{
|
jsonB, err := json.Marshal(Result{
|
||||||
ConnectionEstablishedSeconds: connectionEstablished.Seconds(),
|
Latency: time.Since(start).Seconds(),
|
||||||
UploadSeconds: upload.Seconds(),
|
|
||||||
DownloadSeconds: download.Seconds(),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to marshal perf result: %s", err)
|
log.Fatalf("failed to marshal perf result: %s", err)
|
||||||
|
@ -102,9 +99,7 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
ConnectionEstablishedSeconds float64 `json:"connectionEstablishedSeconds"`
|
Latency float64 `json:"latency"`
|
||||||
UploadSeconds float64 `json:"uploadSeconds"`
|
|
||||||
DownloadSeconds float64 `json:"downloadSeconds"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
type simpleReader struct {
|
type simpleReader struct {
|
||||||
|
|
|
@ -5,7 +5,6 @@ import (
|
||||||
"encoding/binary"
|
"encoding/binary"
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"time"
|
|
||||||
|
|
||||||
logging "github.com/ipfs/go-log/v2"
|
logging "github.com/ipfs/go-log/v2"
|
||||||
pool "github.com/libp2p/go-buffer-pool"
|
pool "github.com/libp2p/go-buffer-pool"
|
||||||
|
@ -55,10 +54,10 @@ func (ps *PerfService) PerfHandler(s network.Stream) {
|
||||||
s.CloseWrite()
|
s.CloseWrite()
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ps *PerfService) RunPerf(ctx context.Context, p peer.ID, bytesToSend uint64, bytesToRecv uint64) (time.Duration, time.Duration, error) {
|
func (ps *PerfService) RunPerf(ctx context.Context, p peer.ID, bytesToSend uint64, bytesToRecv uint64) error {
|
||||||
s, err := ps.Host.NewStream(ctx, p, ID)
|
s, err := ps.Host.NewStream(ctx, p, ID)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeBuf := make([]byte, 8)
|
sizeBuf := make([]byte, 8)
|
||||||
|
@ -66,28 +65,24 @@ func (ps *PerfService) RunPerf(ctx context.Context, p peer.ID, bytesToSend uint6
|
||||||
|
|
||||||
_, err = s.Write(sizeBuf)
|
_, err = s.Write(sizeBuf)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
sendStart := time.Now()
|
|
||||||
if err := sendBytes(s, bytesToSend); err != nil {
|
if err := sendBytes(s, bytesToSend); err != nil {
|
||||||
return 0, 0, err
|
return err
|
||||||
}
|
}
|
||||||
s.CloseWrite()
|
s.CloseWrite()
|
||||||
sendDuration := time.Since(sendStart)
|
|
||||||
|
|
||||||
recvStart := time.Now()
|
|
||||||
recvd, err := drainStream(s)
|
recvd, err := drainStream(s)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return sendDuration, 0, err
|
return err
|
||||||
}
|
}
|
||||||
recvDuration := time.Since(recvStart)
|
|
||||||
|
|
||||||
if recvd != bytesToRecv {
|
if recvd != bytesToRecv {
|
||||||
return sendDuration, recvDuration, fmt.Errorf("expected to recv %d bytes, got %d", bytesToRecv, recvd)
|
return fmt.Errorf("expected to recv %d bytes, got %d", bytesToRecv, recvd)
|
||||||
}
|
}
|
||||||
|
|
||||||
return sendDuration, recvDuration, nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func sendBytes(s io.Writer, bytesToSend uint64) error {
|
func sendBytes(s io.Writer, bytesToSend uint64) error {
|
||||||
|
|
|
@ -69,7 +69,7 @@ func (r *nullReader) Read(b []byte) (int, error) {
|
||||||
return int(l), nil
|
return int(l), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Duration, time.Duration, error) {
|
func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Duration, error) {
|
||||||
client := &http.Client{
|
client := &http.Client{
|
||||||
Transport: &http.Transport{
|
Transport: &http.Transport{
|
||||||
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
|
||||||
|
@ -88,7 +88,7 @@ func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Durat
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
|
|
||||||
req.Header.Set("Content-Type", "application/octet-stream")
|
req.Header.Set("Content-Type", "application/octet-stream")
|
||||||
|
@ -97,23 +97,22 @@ func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Durat
|
||||||
startTime := time.Now()
|
startTime := time.Now()
|
||||||
resp, err := client.Do(req)
|
resp, err := client.Do(req)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, err
|
return 0, err
|
||||||
}
|
}
|
||||||
if resp.StatusCode != http.StatusOK {
|
if resp.StatusCode != http.StatusOK {
|
||||||
return 0, 0, fmt.Errorf("server returned non-OK status: %d %s", resp.StatusCode, resp.Status)
|
return 0, fmt.Errorf("server returned non-OK status: %d %s", resp.StatusCode, resp.Status)
|
||||||
}
|
}
|
||||||
uploadDoneTime := time.Now()
|
|
||||||
defer resp.Body.Close()
|
defer resp.Body.Close()
|
||||||
|
|
||||||
n, err := drainStream(resp.Body)
|
n, err := drainStream(resp.Body)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return 0, 0, fmt.Errorf("error reading response: %w", err)
|
return 0, fmt.Errorf("error reading response: %w", err)
|
||||||
}
|
}
|
||||||
if n != downloadBytes {
|
if n != downloadBytes {
|
||||||
return 0, 0, fmt.Errorf("expected %d bytes in response, but received %d", downloadBytes, n)
|
return 0, fmt.Errorf("expected %d bytes in response, but received %d", downloadBytes, n)
|
||||||
}
|
}
|
||||||
|
|
||||||
return uploadDoneTime.Sub(startTime), time.Since(uploadDoneTime), nil
|
return time.Since(startTime), nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func generateEphemeralCertificate() (tls.Certificate, error) {
|
func generateEphemeralCertificate() (tls.Certificate, error) {
|
||||||
|
@ -168,9 +167,7 @@ func generateEphemeralCertificate() (tls.Certificate, error) {
|
||||||
}
|
}
|
||||||
|
|
||||||
type Result struct {
|
type Result struct {
|
||||||
ConnectionEstablishedSeconds float64 `json:"connectionEstablishedSeconds"`
|
Latency float64 `json:"latency"`
|
||||||
UploadSeconds float64 `json:"uploadSeconds"`
|
|
||||||
DownloadSeconds float64 `json:"downloadSeconds"`
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
|
@ -217,16 +214,13 @@ func main() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Run the client and print the results
|
// Run the client and print the results
|
||||||
upload, download, err := runClient(*serverAddr, *uploadBytes, *downloadBytes)
|
latency, err := runClient(*serverAddr, *uploadBytes, *downloadBytes)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatal(err)
|
log.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
jsonB, err := json.Marshal(Result{
|
jsonB, err := json.Marshal(Result{
|
||||||
// TODO: Ideally we would be able to measure the Go std TCP+TLS connection establishment time.
|
Latency: latency.Seconds(),
|
||||||
ConnectionEstablishedSeconds: 0,
|
|
||||||
UploadSeconds: upload.Seconds(),
|
|
||||||
DownloadSeconds: download.Seconds(),
|
|
||||||
})
|
})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("failed to marshal perf result: %s", err)
|
log.Fatalf("failed to marshal perf result: %s", err)
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
commitSha := bdfafffc8b7ec786ff41ea245f24920930eec720
|
commitSha := a5cd126c97b6d8d8328141bfa84cc57e74ebc57c
|
||||||
|
|
||||||
all: perf
|
all: perf
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
commitSha := 84d29b34b19aef161a8583daffb9f63a385a613b
|
commitSha := 3287f079a8faf5e633a85edae2e76bf490ef1e51
|
||||||
|
|
||||||
all: perf
|
all: perf
|
||||||
|
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
commitSha := ed14630672b66958d1da52ecbff03004f0c057c0
|
commitSha := 73dbde1519f71aa8d76f4c5fa018860ddcd2a8ea
|
||||||
|
|
||||||
all: perf
|
all: perf
|
||||||
|
|
||||||
|
|
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue