Skip to content

Commit

Permalink
refactor(perf): expose single latency measurement (#207)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxinden authored Jun 26, 2023
1 parent 81b6e7c commit cdf7820
Show file tree
Hide file tree
Showing 8 changed files with 958 additions and 2,512 deletions.
4 changes: 3 additions & 1 deletion perf/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ _WARNING_: Running the perf tests might take a while.
- Logging MUST go to stderr.
- Measurement output is printed to stdout as JSON in the form of:
```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.
3. Reference implementation in `runner/src/versions.ts`.
11 changes: 3 additions & 8 deletions perf/impl/go-libp2p/v0.27/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -82,17 +82,14 @@ func main() {
if err != nil {
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 {
log.Fatalf("failed to execute perf: %s", err)
}

jsonB, err := json.Marshal(Result{
ConnectionEstablishedSeconds: connectionEstablished.Seconds(),
UploadSeconds: upload.Seconds(),
DownloadSeconds: download.Seconds(),
Latency: time.Since(start).Seconds(),
})
if err != nil {
log.Fatalf("failed to marshal perf result: %s", err)
Expand All @@ -102,9 +99,7 @@ func main() {
}

type Result struct {
ConnectionEstablishedSeconds float64 `json:"connectionEstablishedSeconds"`
UploadSeconds float64 `json:"uploadSeconds"`
DownloadSeconds float64 `json:"downloadSeconds"`
Latency float64 `json:"latency"`
}

type simpleReader struct {
Expand Down
19 changes: 7 additions & 12 deletions perf/impl/go-libp2p/v0.27/perf.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import (
"encoding/binary"
"fmt"
"io"
"time"

logging "github.com/ipfs/go-log/v2"
pool "github.com/libp2p/go-buffer-pool"
Expand Down Expand Up @@ -55,39 +54,35 @@ func (ps *PerfService) PerfHandler(s network.Stream) {
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)
if err != nil {
return 0, 0, err
return err
}

sizeBuf := make([]byte, 8)
binary.BigEndian.PutUint64(sizeBuf, bytesToRecv)

_, err = s.Write(sizeBuf)
if err != nil {
return 0, 0, err
return err
}

sendStart := time.Now()
if err := sendBytes(s, bytesToSend); err != nil {
return 0, 0, err
return err
}
s.CloseWrite()
sendDuration := time.Since(sendStart)

recvStart := time.Now()
recvd, err := drainStream(s)
if err != nil {
return sendDuration, 0, err
return err
}
recvDuration := time.Since(recvStart)

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 {
Expand Down
26 changes: 10 additions & 16 deletions perf/impl/https/v0.1/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func (r *nullReader) Read(b []byte) (int, error) {
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{
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
Expand All @@ -88,7 +88,7 @@ func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Durat
),
)
if err != nil {
return 0, 0, err
return 0, err
}

req.Header.Set("Content-Type", "application/octet-stream")
Expand All @@ -97,23 +97,22 @@ func runClient(serverAddr string, uploadBytes, downloadBytes uint64) (time.Durat
startTime := time.Now()
resp, err := client.Do(req)
if err != nil {
return 0, 0, err
return 0, err
}
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()

n, err := drainStream(resp.Body)
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 {
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) {
Expand Down Expand Up @@ -168,9 +167,7 @@ func generateEphemeralCertificate() (tls.Certificate, error) {
}

type Result struct {
ConnectionEstablishedSeconds float64 `json:"connectionEstablishedSeconds"`
UploadSeconds float64 `json:"uploadSeconds"`
DownloadSeconds float64 `json:"downloadSeconds"`
Latency float64 `json:"latency"`
}

func main() {
Expand Down Expand Up @@ -217,16 +214,13 @@ func main() {
}

// Run the client and print the results
upload, download, err := runClient(*serverAddr, *uploadBytes, *downloadBytes)
latency, err := runClient(*serverAddr, *uploadBytes, *downloadBytes)
if err != nil {
log.Fatal(err)
}

jsonB, err := json.Marshal(Result{
// TODO: Ideally we would be able to measure the Go std TCP+TLS connection establishment time.
ConnectionEstablishedSeconds: 0,
UploadSeconds: upload.Seconds(),
DownloadSeconds: download.Seconds(),
Latency: latency.Seconds(),
})
if err != nil {
log.Fatalf("failed to marshal perf result: %s", err)
Expand Down
2 changes: 1 addition & 1 deletion perf/impl/quic-go/v0.34/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
commitSha := bdfafffc8b7ec786ff41ea245f24920930eec720
commitSha := a5cd126c97b6d8d8328141bfa84cc57e74ebc57c

all: perf

Expand Down
2 changes: 1 addition & 1 deletion perf/impl/rust-libp2p-quinn/v0.52/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
commitSha := 84d29b34b19aef161a8583daffb9f63a385a613b
commitSha := 3287f079a8faf5e633a85edae2e76bf490ef1e51

all: perf

Expand Down
2 changes: 1 addition & 1 deletion perf/impl/rust-libp2p/v0.52/Makefile
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
commitSha := ed14630672b66958d1da52ecbff03004f0c057c0
commitSha := 73dbde1519f71aa8d76f4c5fa018860ddcd2a8ea

all: perf

Expand Down
Loading

0 comments on commit cdf7820

Please sign in to comment.