diff options
| author | Will Hawkins <[email protected]> | 2023-07-19 10:45:53 -0400 |
|---|---|---|
| committer | Will Hawkins <[email protected]> | 2023-07-19 10:45:53 -0400 |
| commit | 4a3b5c9ab262a6c029c04a6d1e7f6fe038ee9e63 (patch) | |
| tree | 2648458225ee1c37e2e5f6743b2aab77ff3bcc63 | |
| parent | cca033fe0d7389bfa647afa47a47de2a3f6af47d (diff) | |
[Feature] Add extended-stats for uploads
Now that tests are run in sequence, it seems like a good idea to support
extended statistics in both directions.
Fixes #58
h/t @moeller0
Signed-off-by: Will Hawkins <[email protected]>
| -rw-r--r-- | lgc/download.go | 1 | ||||
| -rw-r--r-- | lgc/upload.go | 160 | ||||
| -rw-r--r-- | networkQuality.go | 21 |
3 files changed, 170 insertions, 12 deletions
diff --git a/lgc/download.go b/lgc/download.go index c13a1b1..3ce4389 100644 --- a/lgc/download.go +++ b/lgc/download.go @@ -39,7 +39,6 @@ type LoadGeneratingConnectionDownload struct { ConnectToAddr string URL string downloadStartTime time.Time - lastDownloaded uint64 client *http.Client debug debug.DebugLevel InsecureSkipVerify bool diff --git a/lgc/upload.go b/lgc/upload.go index e4518b8..32dd86a 100644 --- a/lgc/upload.go +++ b/lgc/upload.go @@ -20,12 +20,14 @@ import ( "fmt" "io" "net/http" + "net/http/httptrace" "sync" "sync/atomic" "time" "github.com/network-quality/goresponsiveness/debug" "github.com/network-quality/goresponsiveness/stats" + "github.com/network-quality/goresponsiveness/traceable" "github.com/network-quality/goresponsiveness/utilities" ) @@ -37,12 +39,13 @@ type LoadGeneratingConnectionUpload struct { URL string ConnectToAddr string uploadStartTime time.Time - lastUploaded uint64 client *http.Client debug debug.DebugLevel InsecureSkipVerify bool KeyLogger io.Writer clientId uint64 + tracer *httptrace.ClientTrace + stats stats.TraceStats status LgcStatus statusLock *sync.Mutex statusWaiter *sync.Cond @@ -67,6 +70,154 @@ func (lgu *LoadGeneratingConnectionUpload) WaitUntilStarted(ctxt context.Context return utilities.WaitWithContext(ctxt, &conditional, lgu.statusLock, lgu.statusWaiter) } +func (lgu *LoadGeneratingConnectionUpload) SetDnsStartTimeInfo( + now time.Time, + dnsStartInfo httptrace.DNSStartInfo, +) { + lgu.stats.DnsStartTime = now + lgu.stats.DnsStart = dnsStartInfo + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "DNS Start for %v: %v\n", + lgu.ClientId(), + dnsStartInfo, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetDnsDoneTimeInfo( + now time.Time, + dnsDoneInfo httptrace.DNSDoneInfo, +) { + lgu.stats.DnsDoneTime = now + lgu.stats.DnsDone = dnsDoneInfo + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "DNS Done for %v: %v\n", + lgu.ClientId(), + lgu.stats.DnsDone, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetConnectStartTime( + now time.Time, +) { + lgu.stats.ConnectStartTime = now + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "TCP Start for %v at %v\n", + lgu.ClientId(), + lgu.stats.ConnectStartTime, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetConnectDoneTimeError( + now time.Time, + err error, +) { + lgu.stats.ConnectDoneTime = now + lgu.stats.ConnectDoneError = err + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "TCP Done for %v (with error %v) @ %v\n", + lgu.ClientId(), + lgu.stats.ConnectDoneError, + lgu.stats.ConnectDoneTime, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetGetConnTime(now time.Time) { + lgu.stats.GetConnectionStartTime = now + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "Started getting connection for %v @ %v\n", + lgu.ClientId(), + lgu.stats.GetConnectionStartTime, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetGotConnTimeInfo( + now time.Time, + gotConnInfo httptrace.GotConnInfo, +) { + if gotConnInfo.Reused { + fmt.Printf("Unexpectedly reusing a connection!\n") + panic(!gotConnInfo.Reused) + } + lgu.stats.GetConnectionDoneTime = now + lgu.stats.ConnInfo = gotConnInfo + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "Got connection for %v at %v with info %v\n", + lgu.ClientId(), + lgu.stats.GetConnectionDoneTime, + lgu.stats.ConnInfo, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetTLSHandshakeStartTime( + now time.Time, +) { + lgu.stats.TLSStartTime = utilities.Some(now) + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "Started TLS Handshake for %v @ %v\n", + lgu.ClientId(), + lgu.stats.TLSStartTime, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetTLSHandshakeDoneTimeState( + now time.Time, + connectionState tls.ConnectionState, +) { + lgu.stats.TLSDoneTime = utilities.Some(now) + lgu.stats.TLSConnInfo = connectionState + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "Completed TLS handshake for %v at %v with info %v\n", + lgu.ClientId(), + lgu.stats.TLSDoneTime, + lgu.stats.TLSConnInfo, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetHttpWroteRequestTimeInfo( + now time.Time, + info httptrace.WroteRequestInfo, +) { + lgu.stats.HttpWroteRequestTime = now + lgu.stats.HttpInfo = info + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "(lgu) Http finished writing request for %v at %v with info %v\n", + lgu.ClientId(), + lgu.stats.HttpWroteRequestTime, + lgu.stats.HttpInfo, + ) + } +} + +func (lgu *LoadGeneratingConnectionUpload) SetHttpResponseReadyTime( + now time.Time, +) { + lgu.stats.HttpResponseReadyTime = now + if debug.IsDebug(lgu.debug) { + fmt.Printf( + "Got the first byte of HTTP response headers for %v at %v\n", + lgu.ClientId(), + lgu.stats.HttpResponseReadyTime, + ) + } +} + func (lgu *LoadGeneratingConnectionUpload) ClientId() uint64 { return lgu.clientId } @@ -124,7 +275,8 @@ func (lgu *LoadGeneratingConnectionUpload) doUpload(ctx context.Context) error { var request *http.Request = nil var err error - if request, err = http.NewRequest( + if request, err = http.NewRequestWithContext( + httptrace.WithClientTrace(ctx, lgu.tracer), "POST", lgu.URL, s, @@ -195,6 +347,7 @@ func (lgu *LoadGeneratingConnectionUpload) Start( utilities.OverrideHostTransport(transport, lgu.ConnectToAddr) lgu.client = &http.Client{Transport: transport} + lgu.tracer = traceable.GenerateHttpTimingTracer(lgu, lgu.debug) if debug.IsDebug(lgu.debug) { fmt.Printf("Started a load-generating upload (id: %v).\n", lgu.clientId) @@ -205,6 +358,5 @@ func (lgu *LoadGeneratingConnectionUpload) Start( } func (lgu *LoadGeneratingConnectionUpload) Stats() *stats.TraceStats { - // Get all your stats from the download side of the LGC. - return nil + return &lgu.stats } diff --git a/networkQuality.go b/networkQuality.go index ed9dcfa..1e6590b 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -432,8 +432,7 @@ func main() { downloadDirection.Lgcc = lgc.NewLoadGeneratingConnectionCollection() uploadDirection.Lgcc = lgc.NewLoadGeneratingConnectionCollection() - // We do not do tracing on upload connections so there are no extended stats for those connections! - uploadDirection.ExtendedStatsEligible = false + uploadDirection.ExtendedStatsEligible = true downloadDirection.ExtendedStatsEligible = true generateSelfProbeConfiguration := func() probe.ProbeConfiguration { @@ -956,24 +955,32 @@ func main() { direction.Lgcc.Lock.Lock() defer direction.Lgcc.Lock.Unlock() - // Note: We do not trace upload connections! - downloadLgcCount, err := direction.Lgcc.Len() + lgcCount, err := direction.Lgcc.Len() if err != nil { fmt.Fprintf( os.Stderr, - "Warning: Could not calculate the number of download load-generating connections; aborting extended stats preparation.\n", + "Warning: Could not calculate the number of %v load-generating connections; aborting extended stats preparation.\n", direction.DirectionLabel, ) return } - for i := 0; i < downloadLgcCount; i++ { + + for i := 0; i < lgcCount; i++ { // Assume that extended statistics are available -- the check was done explicitly at // program startup if the calculateExtendedStats flag was set by the user on the command line. currentLgc, _ := direction.Lgcc.Get(i) + + if currentLgc == nil || (*currentLgc).Stats() == nil { + fmt.Fprintf( + os.Stderr, + "Warning: Could not add extended stats for the connection: The LGC was nil or there were no stats available.\n", + ) + continue + } if err := extendedStats.IncorporateConnectionStats( (*currentLgc).Stats().ConnInfo.Conn); err != nil { fmt.Fprintf( os.Stderr, - "Warning: Could not add extended stats for the connection: %v\n", + "Warning: Could not add extended stats for the connection: %v.\n", err, ) } |
