diff options
| -rw-r--r-- | config/config.go | 134 | ||||
| -rw-r--r-- | constants/constants.go | 7 | ||||
| -rwxr-xr-x | data-analysis1/data.sh | 60 | ||||
| -rwxr-xr-x | data-analysis1/gather.sh | 14 | ||||
| -rw-r--r-- | data-analysis1/go.log.FriMay6121542EDT2022 | 603 | ||||
| -rw-r--r-- | data-analysis1/nq.log.FriMay6121542EDT2022 | 706 | ||||
| -rw-r--r-- | extendedstats/other.go | 22 | ||||
| -rw-r--r-- | extendedstats/unix.go | 72 | ||||
| -rw-r--r-- | go.mod | 5 | ||||
| -rw-r--r-- | go.sum | 2 | ||||
| -rw-r--r-- | lgc/lgc.go | 108 | ||||
| -rw-r--r-- | networkQuality.go | 476 | ||||
| -rw-r--r-- | rpm/rpm.go | 404 | ||||
| -rw-r--r-- | stats/stats.go | 2 | ||||
| -rw-r--r-- | traceable/traceable.go | 3 | ||||
| -rw-r--r-- | utilities/utilities.go | 25 |
16 files changed, 2132 insertions, 511 deletions
diff --git a/config/config.go b/config/config.go new file mode 100644 index 0000000..05ec61d --- /dev/null +++ b/config/config.go @@ -0,0 +1,134 @@ +package config + +import ( + "crypto/tls" + "encoding/json" + "fmt" + "io/ioutil" + "net/http" + "net/url" + "strings" + + "github.com/network-quality/goresponsiveness/utilities" + "golang.org/x/net/http2" +) + +type ConfigUrls struct { + SmallUrl string `json:"small_https_download_url"` + LargeUrl string `json:"large_https_download_url"` + UploadUrl string `json:"https_upload_url"` +} + +type Config struct { + Version int + Urls ConfigUrls `json:"urls"` + Source string + Test_Endpoint string +} + +func (c *Config) Get(configHost string, configPath string) error { + configTransport := http2.Transport{} + configTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} + configClient := &http.Client{Transport: &configTransport} + // Extraneous /s in URLs is normally okay, but the Apple CDN does not + // like them. Make sure that we put exactly one (1) / between the host + // and the path. + if !strings.HasPrefix(configPath, "/") { + configPath = "/" + configPath + } + c.Source = fmt.Sprintf("https://%s%s", configHost, configPath) + resp, err := configClient.Get(c.Source) + if err != nil { + return fmt.Errorf( + "Error: Could not connect to configuration host %s: %v\n", + configHost, + err, + ) + } + + jsonConfig, err := ioutil.ReadAll(resp.Body) + if err != nil { + return fmt.Errorf( + "Error: Could not read configuration content downloaded from %s: %v\n", + c.Source, + err, + ) + } + + err = json.Unmarshal(jsonConfig, c) + if err != nil { + return fmt.Errorf( + "Error: Could not parse configuration returned from %s: %v\n", + c.Source, + err, + ) + } + + //if len(c.Test_Endpoint) != 0 { + if false { + tempUrl, err := url.Parse(c.Urls.LargeUrl) + if err != nil { + return fmt.Errorf("Error parsing large_https_download_url: %v", err) + } + c.Urls.LargeUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path + tempUrl, err = url.Parse(c.Urls.SmallUrl) + if err != nil { + return fmt.Errorf("Error parsing small_https_download_url: %v", err) + } + c.Urls.SmallUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path + tempUrl, err = url.Parse(c.Urls.UploadUrl) + if err != nil { + return fmt.Errorf("Error parsing https_upload_url: %v", err) + } + c.Urls.UploadUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path + } + return nil +} + +func (c *Config) String() string { + return fmt.Sprintf( + "Version: %d\nSmall URL: %s\nLarge URL: %s\nUpload URL: %s\nEndpoint: %s\n", + c.Version, + c.Urls.SmallUrl, + c.Urls.LargeUrl, + c.Urls.UploadUrl, + c.Test_Endpoint, + ) +} + +func (c *Config) IsValid() error { + if parsedUrl, err := url.ParseRequestURI(c.Urls.LargeUrl); err != nil || + parsedUrl.Scheme != "https" { + return fmt.Errorf( + "Configuration url large_https_download_url is invalid: %s", + utilities.Conditional( + len(c.Urls.LargeUrl) != 0, + c.Urls.LargeUrl, + "Missing", + ), + ) + } + if parsedUrl, err := url.ParseRequestURI(c.Urls.SmallUrl); err != nil || + parsedUrl.Scheme != "https" { + return fmt.Errorf( + "Configuration url small_https_download_url is invalid: %s", + utilities.Conditional( + len(c.Urls.SmallUrl) != 0, + c.Urls.SmallUrl, + "Missing", + ), + ) + } + if parsedUrl, err := url.ParseRequestURI(c.Urls.UploadUrl); err != nil || + parsedUrl.Scheme != "https" { + return fmt.Errorf( + "Configuration url https_upload_url is invalid: %s", + utilities.Conditional( + len(c.Urls.UploadUrl) != 0, + c.Urls.UploadUrl, + "Missing", + ), + ) + } + return nil +} diff --git a/constants/constants.go b/constants/constants.go index 1a060dd..a015f14 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -9,7 +9,7 @@ var ( // calculation. MovingAverageIntervalCount int = 4 // The number of intervals across which to consider a moving average stable. - MovingAverageStabilitySpan int = 4 + MovingAverageStabilitySpan uint64 = 4 // The number of connections to add to a LBC when unsaturated. AdditiveNumberOfLoadGeneratingConnections uint64 = 4 // The cutoff of the percent difference that defines instability. @@ -18,7 +18,7 @@ var ( // The amount of time that the client will cooldown if it is in debug mode. CooldownPeriod time.Duration = 4 * time.Second // The number of probes to send when calculating RTT. - RPMProbeCount int = 5 + MeasurementProbeCount int = 5 // The amount of time that we give ourselves to calculate the RPM. RPMCalculationTime time.Duration = 10 * time.Second @@ -30,4 +30,7 @@ var ( DefaultDebug bool = false // The default URL for the config host. DefaultConfigHost string = "networkquality.example.com" + + // The default decision about whether to run the test in strict mode. + DefaultStrict bool = false ) diff --git a/data-analysis1/data.sh b/data-analysis1/data.sh new file mode 100755 index 0000000..dfa0499 --- /dev/null +++ b/data-analysis1/data.sh @@ -0,0 +1,60 @@ +#!/bin/bash + +# In order to run this script to generate data, you will need the ziplines +# utility: https://github.com/hawkinsw/ziplines + +NQRAWDATA=nq.log.FriMay6121542EDT2022 +GORAWDATA=go.log.FriMay6121542EDT2022 + +# Clean up all the CSV files. +rm -rf *.csv + +# Create the Go RPM csv file. +cat ${GORAWDATA} | grep RPM | sed 's/RPM:[[:space:]]\+//' > go.csv + +# Create the NQ RPM csv file. +cat ${NQRAWDATA} | grep RPM | awk '{print $3;}' | tr -d \( > nq.csv + +# Create the Go upload csv file +cat ${GORAWDATA} | grep Upload | sed 's/Upload: //' | awk '{print $1 " " $2;}' | sed 's/Mbps//' > go.upload.csv + +# Create the NQ upload csv file +cat ${NQRAWDATA} | grep 'Upload capacity' | awk --field-separator=: '{ print $2; }' | sed 's/ //'| sed 's/Mbps//' > nq.upload.csv + +# Create the Go download csv file +cat ${GORAWDATA} | grep Download | sed 's/Download: //' | awk '{print $1 " " $2;}'| sed 's/Mbps//' > go.download.csv + +# Create the NQ download csv file +cat ${NQRAWDATA} | grep 'Download capacity' | awk --field-separator=: '{ print $2; }' | sed 's/ //'| sed 's/Mbps//' > nq.download.csv + +# Create the Go upload flows csv file +cat ${GORAWDATA} | grep 'Upload.*using' | sed 's/Upload.*using \([[:digit:]]\+\) parallel connections./\1/' > go.upload.flows.csv + +# Create the NQ upload flows csv file +cat ${NQRAWDATA} | grep -i 'upload flows' | awk --field-separator=: '{print $2}' | tr -d ' ' > nq.upload.flows.csv + +# Create the Go download flows csv file +cat ${GORAWDATA} | grep 'Download.*using' | sed 's/Download.*using \([[:digit:]]\+\) parallel connections./\1/' > go.download.flows.csv + +# Create the NQ download flows csv file +cat ${NQRAWDATA} | grep -i 'download flows' | awk --field-separator=: '{print $2}' | tr -d ' ' > nq.download.flows.csv + +# Create the overall rpm.csv file +echo "Go, Network Quality" > rpm.csv +ziplines , go.csv nq.csv >> rpm.csv + +# Create the overall download.csv file +echo "Go, Network Quality" > download.csv +ziplines , go.download.csv nq.download.csv >> download.csv + +# Create the overall upload.csv file +echo "Go, Network Quality" > upload.csv +ziplines , go.upload.csv nq.upload.csv >> upload.csv + +# Create the overall download.flows.csv file +echo "Go, Network Quality" > download.flows.csv +ziplines , go.download.flows.csv nq.download.flows.csv >> download.flows.csv + +# Create the overall upload.flows.csv file +echo "Go, Network Quality" > upload.flows.csv +ziplines , go.upload.flows.csv nq.upload.flows.csv >> upload.flows.csv diff --git a/data-analysis1/gather.sh b/data-analysis1/gather.sh new file mode 100755 index 0000000..596e2f4 --- /dev/null +++ b/data-analysis1/gather.sh @@ -0,0 +1,14 @@ +#!/bin/bash + +UUID=`date | sed 's/[ :]//g'` +GOLOG="go.log.${UUID}" +NQLOG="nq.log.${UUID}" + +for i in `seq 1 100`; do + date >> ${GOLOG} + ./networkQuality -config rpm.obs.cr -path config -port 4043 >> ${GOLOG} + echo "Done with Go test (#${i})" + date >> ${NQLOG} + /usr/bin/networkQuality -C https://rpm.obs.cr:4043/config >> ${NQLOG} + echo "Done with networkQuality test (#${i})" +done diff --git a/data-analysis1/go.log.FriMay6121542EDT2022 b/data-analysis1/go.log.FriMay6121542EDT2022 new file mode 100644 index 0000000..8fd1d9a --- /dev/null +++ b/data-analysis1/go.log.FriMay6121542EDT2022 @@ -0,0 +1,603 @@ +Fri May 6 12:15:42 EDT 2022 +05-06-2022 16:15:42 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 192.469 Mbps ( 24.059 MBps), using 12 parallel connections. +Upload: 93.469 Mbps ( 11.684 MBps), using 24 parallel connections. +Total RTTs measured: 25 +RPM: 917 +Fri May 6 12:16:08 EDT 2022 +05-06-2022 16:16:08 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 227.406 Mbps ( 28.426 MBps), using 16 parallel connections. +Upload: 100.562 Mbps ( 12.570 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1205 +Fri May 6 12:16:37 EDT 2022 +05-06-2022 16:16:38 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 214.812 Mbps ( 26.852 MBps), using 16 parallel connections. +Upload: 100.250 Mbps ( 12.531 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1373 +Fri May 6 12:17:05 EDT 2022 +05-06-2022 16:17:05 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 232.844 Mbps ( 29.105 MBps), using 20 parallel connections. +Upload: 93.938 Mbps ( 11.742 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1436 +Fri May 6 12:17:35 EDT 2022 +05-06-2022 16:17:35 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 241.719 Mbps ( 30.215 MBps), using 24 parallel connections. +Upload: 95.719 Mbps ( 11.965 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1269 +Fri May 6 12:18:05 EDT 2022 +05-06-2022 16:18:05 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 222.031 Mbps ( 27.754 MBps), using 20 parallel connections. +Upload: 100.125 Mbps ( 12.516 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1442 +Fri May 6 12:18:34 EDT 2022 +05-06-2022 16:18:35 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 241.500 Mbps ( 30.188 MBps), using 16 parallel connections. +Upload: 97.656 Mbps ( 12.207 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1416 +Fri May 6 12:18:59 EDT 2022 +05-06-2022 16:19:00 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 182.531 Mbps ( 22.816 MBps), using 12 parallel connections. +Upload: 97.188 Mbps ( 12.148 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1297 +Fri May 6 12:19:24 EDT 2022 +05-06-2022 16:19:24 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 231.781 Mbps ( 28.973 MBps), using 24 parallel connections. +Upload: 100.625 Mbps ( 12.578 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1380 +Fri May 6 12:19:54 EDT 2022 +05-06-2022 16:19:54 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 209.500 Mbps ( 26.188 MBps), using 16 parallel connections. +Upload: 100.406 Mbps ( 12.551 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1324 +Fri May 6 12:20:17 EDT 2022 +05-06-2022 16:20:17 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 230.969 Mbps ( 28.871 MBps), using 28 parallel connections. +Upload: 100.750 Mbps ( 12.594 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1365 +Fri May 6 12:20:50 EDT 2022 +05-06-2022 16:20:50 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 234.312 Mbps ( 29.289 MBps), using 16 parallel connections. +Upload: 99.125 Mbps ( 12.391 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1449 +Fri May 6 12:21:19 EDT 2022 +05-06-2022 16:21:20 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 243.469 Mbps ( 30.434 MBps), using 20 parallel connections. +Upload: 100.781 Mbps ( 12.598 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1438 +Fri May 6 12:21:47 EDT 2022 +05-06-2022 16:21:47 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 212.156 Mbps ( 26.520 MBps), using 16 parallel connections. +Upload: 97.938 Mbps ( 12.242 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1089 +Fri May 6 12:22:18 EDT 2022 +05-06-2022 16:22:18 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 227.562 Mbps ( 28.445 MBps), using 16 parallel connections. +Upload: 100.875 Mbps ( 12.609 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1419 +Fri May 6 12:22:45 EDT 2022 +05-06-2022 16:22:45 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 241.906 Mbps ( 30.238 MBps), using 20 parallel connections. +Upload: 99.000 Mbps ( 12.375 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1320 +Fri May 6 12:23:16 EDT 2022 +05-06-2022 16:23:16 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 215.562 Mbps ( 26.945 MBps), using 16 parallel connections. +Upload: 94.000 Mbps ( 11.750 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1361 +Fri May 6 12:23:43 EDT 2022 +05-06-2022 16:23:43 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 187.125 Mbps ( 23.391 MBps), using 16 parallel connections. +Upload: 99.438 Mbps ( 12.430 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1213 +Fri May 6 12:24:10 EDT 2022 +05-06-2022 16:24:10 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 212.516 Mbps ( 26.564 MBps), using 20 parallel connections. +Upload: 101.156 Mbps ( 12.645 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1365 +Fri May 6 12:24:37 EDT 2022 +05-06-2022 16:24:38 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 225.000 Mbps ( 28.125 MBps), using 16 parallel connections. +Upload: 98.062 Mbps ( 12.258 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1448 +Fri May 6 12:25:02 EDT 2022 +05-06-2022 16:25:03 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 236.938 Mbps ( 29.617 MBps), using 16 parallel connections. +Upload: 99.438 Mbps ( 12.430 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1518 +Fri May 6 12:25:32 EDT 2022 +05-06-2022 16:25:32 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 213.156 Mbps ( 26.645 MBps), using 16 parallel connections. +Upload: 93.375 Mbps ( 11.672 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1399 +Fri May 6 12:26:02 EDT 2022 +05-06-2022 16:26:03 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 235.938 Mbps ( 29.492 MBps), using 24 parallel connections. +Upload: 96.125 Mbps ( 12.016 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1375 +Fri May 6 12:26:30 EDT 2022 +05-06-2022 16:26:31 UTC Go Responsiveness to rpm.obs.cr:4043... +Failed to calculate a time for sequential RTTs: Get "https://rpm.obs.cr:4043/small": dial tcp: lookup rpm.obs.cr: no such host +Failed to calculate a time for sequential RTTs: Get "https://rpm.obs.cr:4043/small": dial tcp: lookup rpm.obs.cr: no such host +Failed to calculate a time for sequential RTTs: Get "https://rpm.obs.cr:4043/small": dial tcp: lookup rpm.obs.cr: no such host +Failed to calculate a time for sequential RTTs: Get "https://rpm.obs.cr:4043/small": dial tcp: lookup rpm.obs.cr: no such host +Download: 126.656 Mbps ( 15.832 MBps), using 20 parallel connections. +Upload: 96.188 Mbps ( 12.023 MBps), using 12 parallel connections. +Error occurred calculating RPM -- no probe measurements received. +Fri May 6 12:43:25 EDT 2022 +05-06-2022 16:43:25 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 201.500 Mbps ( 25.188 MBps), using 16 parallel connections. +Upload: 98.844 Mbps ( 12.355 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1392 +Fri May 6 12:43:53 EDT 2022 +05-06-2022 16:43:53 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 256.875 Mbps ( 32.109 MBps), using 20 parallel connections. +Upload: 62.469 Mbps ( 7.809 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 2162 +Fri May 6 13:00:14 EDT 2022 +05-06-2022 17:00:15 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 244.938 Mbps ( 30.617 MBps), using 16 parallel connections. +Upload: 99.500 Mbps ( 12.438 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1127 +Fri May 6 13:16:23 EDT 2022 +05-06-2022 17:16:23 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 238.062 Mbps ( 29.758 MBps), using 16 parallel connections. +Upload: 101.062 Mbps ( 12.633 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1446 +Fri May 6 13:16:51 EDT 2022 +05-06-2022 17:16:51 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 240.938 Mbps ( 30.117 MBps), using 20 parallel connections. +Upload: 98.094 Mbps ( 12.262 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1445 +Fri May 6 13:17:20 EDT 2022 +05-06-2022 17:17:20 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 246.375 Mbps ( 30.797 MBps), using 16 parallel connections. +Upload: 94.844 Mbps ( 11.855 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 2496 +Fri May 6 13:33:48 EDT 2022 +05-06-2022 17:33:48 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 155.938 Mbps ( 19.492 MBps), using 12 parallel connections. +Upload: 97.906 Mbps ( 12.238 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1118 +Fri May 6 13:34:13 EDT 2022 +05-06-2022 17:34:14 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 229.500 Mbps ( 28.688 MBps), using 24 parallel connections. +Upload: 99.062 Mbps ( 12.383 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1383 +Fri May 6 13:34:43 EDT 2022 +05-06-2022 17:34:44 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 227.531 Mbps ( 28.441 MBps), using 24 parallel connections. +Upload: 98.875 Mbps ( 12.359 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1438 +Fri May 6 13:35:13 EDT 2022 +05-06-2022 17:35:14 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 187.781 Mbps ( 23.473 MBps), using 12 parallel connections. +Upload: 97.562 Mbps ( 12.195 MBps), using 20 parallel connections. +Total RTTs measured: 25 +RPM: 1243 +Fri May 6 13:35:41 EDT 2022 +05-06-2022 17:35:42 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 226.625 Mbps ( 28.328 MBps), using 24 parallel connections. +Upload: 97.594 Mbps ( 12.199 MBps), using 24 parallel connections. +Total RTTs measured: 25 +RPM: 1021 +Fri May 6 13:36:12 EDT 2022 +05-06-2022 17:36:12 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 238.188 Mbps ( 29.773 MBps), using 16 parallel connections. +Upload: 98.969 Mbps ( 12.371 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1176 +Fri May 6 13:36:41 EDT 2022 +05-06-2022 17:36:41 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 224.719 Mbps ( 28.090 MBps), using 20 parallel connections. +Upload: 100.219 Mbps ( 12.527 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1110 +Fri May 6 13:37:10 EDT 2022 +05-06-2022 17:37:11 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 248.250 Mbps ( 31.031 MBps), using 28 parallel connections. +Upload: 100.375 Mbps ( 12.547 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1482 +Fri May 6 13:37:42 EDT 2022 +05-06-2022 17:37:42 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 230.094 Mbps ( 28.762 MBps), using 16 parallel connections. +Upload: 101.000 Mbps ( 12.625 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1428 +Fri May 6 13:38:09 EDT 2022 +05-06-2022 17:38:09 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 226.656 Mbps ( 28.332 MBps), using 16 parallel connections. +Upload: 95.625 Mbps ( 11.953 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1406 +Fri May 6 13:38:38 EDT 2022 +05-06-2022 17:38:38 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 216.188 Mbps ( 27.023 MBps), using 20 parallel connections. +Upload: 100.688 Mbps ( 12.586 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1429 +Fri May 6 13:39:08 EDT 2022 +05-06-2022 17:39:09 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 230.406 Mbps ( 28.801 MBps), using 24 parallel connections. +Upload: 99.875 Mbps ( 12.484 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1393 +Fri May 6 13:39:39 EDT 2022 +05-06-2022 17:39:40 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 217.469 Mbps ( 27.184 MBps), using 20 parallel connections. +Upload: 100.344 Mbps ( 12.543 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1346 +Fri May 6 13:40:09 EDT 2022 +05-06-2022 17:40:09 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 222.375 Mbps ( 27.797 MBps), using 16 parallel connections. +Upload: 100.375 Mbps ( 12.547 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1140 +Fri May 6 13:40:37 EDT 2022 +05-06-2022 17:40:37 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 221.031 Mbps ( 27.629 MBps), using 20 parallel connections. +Upload: 102.125 Mbps ( 12.766 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1432 +Fri May 6 13:41:06 EDT 2022 +05-06-2022 17:41:06 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 235.250 Mbps ( 29.406 MBps), using 16 parallel connections. +Upload: 100.562 Mbps ( 12.570 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1375 +Fri May 6 13:41:32 EDT 2022 +05-06-2022 17:41:32 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 205.750 Mbps ( 25.719 MBps), using 16 parallel connections. +Upload: 102.500 Mbps ( 12.812 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1196 +Fri May 6 13:42:01 EDT 2022 +05-06-2022 17:42:01 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 204.562 Mbps ( 25.570 MBps), using 16 parallel connections. +Upload: 91.250 Mbps ( 11.406 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1343 +Fri May 6 13:42:27 EDT 2022 +05-06-2022 17:42:27 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 240.062 Mbps ( 30.008 MBps), using 28 parallel connections. +Upload: 97.719 Mbps ( 12.215 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1307 +Fri May 6 13:42:59 EDT 2022 +05-06-2022 17:42:59 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 244.531 Mbps ( 30.566 MBps), using 28 parallel connections. +Upload: 83.438 Mbps ( 10.430 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 989 +Fri May 6 13:43:30 EDT 2022 +05-06-2022 17:43:31 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 242.500 Mbps ( 30.312 MBps), using 16 parallel connections. +Upload: 100.500 Mbps ( 12.562 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1211 +Fri May 6 13:57:25 EDT 2022 +05-06-2022 17:57:27 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 228.188 Mbps ( 28.523 MBps), using 20 parallel connections. +Upload: 92.562 Mbps ( 11.570 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1377 +Fri May 6 13:57:55 EDT 2022 +05-06-2022 17:57:55 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 229.875 Mbps ( 28.734 MBps), using 24 parallel connections. +Upload: 100.031 Mbps ( 12.504 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1330 +Fri May 6 13:58:28 EDT 2022 +05-06-2022 17:58:28 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 243.125 Mbps ( 30.391 MBps), using 16 parallel connections. +Upload: 99.812 Mbps ( 12.477 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1358 +Fri May 6 13:58:58 EDT 2022 +05-06-2022 17:58:58 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 214.531 Mbps ( 26.816 MBps), using 24 parallel connections. +Upload: 99.969 Mbps ( 12.496 MBps), using 20 parallel connections. +Total RTTs measured: 25 +RPM: 1229 +Fri May 6 13:59:26 EDT 2022 +05-06-2022 17:59:26 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 224.938 Mbps ( 28.117 MBps), using 16 parallel connections. +Upload: 97.812 Mbps ( 12.227 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1416 +Fri May 6 13:59:53 EDT 2022 +05-06-2022 17:59:53 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 219.875 Mbps ( 27.484 MBps), using 16 parallel connections. +Upload: 97.375 Mbps ( 12.172 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1310 +Fri May 6 14:00:15 EDT 2022 +05-06-2022 18:00:16 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 244.062 Mbps ( 30.508 MBps), using 28 parallel connections. +Upload: 100.438 Mbps ( 12.555 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1210 +Fri May 6 14:00:48 EDT 2022 +05-06-2022 18:00:48 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 214.438 Mbps ( 26.805 MBps), using 20 parallel connections. +Upload: 99.844 Mbps ( 12.480 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1287 +Fri May 6 14:01:18 EDT 2022 +05-06-2022 18:01:18 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 244.281 Mbps ( 30.535 MBps), using 32 parallel connections. +Upload: 100.469 Mbps ( 12.559 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1435 +Fri May 6 14:01:51 EDT 2022 +05-06-2022 18:01:51 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 226.938 Mbps ( 28.367 MBps), using 16 parallel connections. +Upload: 100.625 Mbps ( 12.578 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1356 +Fri May 6 14:02:19 EDT 2022 +05-06-2022 18:02:19 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 231.438 Mbps ( 28.930 MBps), using 16 parallel connections. +Upload: 99.312 Mbps ( 12.414 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1236 +Fri May 6 14:02:46 EDT 2022 +05-06-2022 18:02:46 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 173.406 Mbps ( 21.676 MBps), using 12 parallel connections. +Upload: 94.438 Mbps ( 11.805 MBps), using 24 parallel connections. +Total RTTs measured: 25 +RPM: 1213 +Fri May 6 14:03:09 EDT 2022 +05-06-2022 18:03:10 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 242.594 Mbps ( 30.324 MBps), using 24 parallel connections. +Upload: 99.562 Mbps ( 12.445 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 977 +Fri May 6 14:03:41 EDT 2022 +05-06-2022 18:03:41 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 233.078 Mbps ( 29.135 MBps), using 16 parallel connections. +Upload: 101.250 Mbps ( 12.656 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1409 +Fri May 6 14:04:09 EDT 2022 +05-06-2022 18:04:09 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 228.562 Mbps ( 28.570 MBps), using 20 parallel connections. +Upload: 96.312 Mbps ( 12.039 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1309 +Fri May 6 14:04:39 EDT 2022 +05-06-2022 18:04:39 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 230.281 Mbps ( 28.785 MBps), using 24 parallel connections. +Upload: 99.625 Mbps ( 12.453 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1450 +Fri May 6 14:05:09 EDT 2022 +05-06-2022 18:05:09 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 243.031 Mbps ( 30.379 MBps), using 16 parallel connections. +Upload: 98.906 Mbps ( 12.363 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1345 +Fri May 6 14:05:39 EDT 2022 +05-06-2022 18:05:39 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 228.266 Mbps ( 28.533 MBps), using 16 parallel connections. +Upload: 98.844 Mbps ( 12.355 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1327 +Fri May 6 14:06:10 EDT 2022 +05-06-2022 18:06:10 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 227.969 Mbps ( 28.496 MBps), using 24 parallel connections. +Upload: 97.094 Mbps ( 12.137 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1387 +Fri May 6 14:06:40 EDT 2022 +05-06-2022 18:06:40 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 181.312 Mbps ( 22.664 MBps), using 12 parallel connections. +Upload: 98.156 Mbps ( 12.270 MBps), using 24 parallel connections. +Total RTTs measured: 25 +RPM: 1349 +Fri May 6 14:07:06 EDT 2022 +05-06-2022 18:07:06 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 205.469 Mbps ( 25.684 MBps), using 16 parallel connections. +Upload: 99.906 Mbps ( 12.488 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1297 +Fri May 6 14:07:33 EDT 2022 +05-06-2022 18:07:33 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 217.219 Mbps ( 27.152 MBps), using 24 parallel connections. +Upload: 96.906 Mbps ( 12.113 MBps), using 20 parallel connections. +Total RTTs measured: 15 +RPM: 960 +Fri May 6 14:23:25 EDT 2022 +05-06-2022 18:23:25 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 235.500 Mbps ( 29.438 MBps), using 16 parallel connections. +Upload: 100.062 Mbps ( 12.508 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1433 +Fri May 6 14:23:52 EDT 2022 +05-06-2022 18:23:52 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 228.000 Mbps ( 28.500 MBps), using 28 parallel connections. +Upload: 99.844 Mbps ( 12.480 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1158 +Fri May 6 14:24:24 EDT 2022 +05-06-2022 18:24:24 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 239.531 Mbps ( 29.941 MBps), using 24 parallel connections. +Upload: 96.969 Mbps ( 12.121 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1518 +Fri May 6 14:24:54 EDT 2022 +05-06-2022 18:24:54 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 236.281 Mbps ( 29.535 MBps), using 24 parallel connections. +Upload: 89.312 Mbps ( 11.164 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1388 +Fri May 6 14:25:23 EDT 2022 +05-06-2022 18:25:23 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 226.719 Mbps ( 28.340 MBps), using 20 parallel connections. +Upload: 99.938 Mbps ( 12.492 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1087 +Fri May 6 14:25:53 EDT 2022 +05-06-2022 18:25:54 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 237.906 Mbps ( 29.738 MBps), using 28 parallel connections. +Upload: 100.344 Mbps ( 12.543 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1349 +Fri May 6 14:26:27 EDT 2022 +05-06-2022 18:26:28 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 242.094 Mbps ( 30.262 MBps), using 20 parallel connections. +Upload: 102.312 Mbps ( 12.789 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1381 +Fri May 6 14:26:57 EDT 2022 +05-06-2022 18:26:58 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 208.688 Mbps ( 26.086 MBps), using 16 parallel connections. +Upload: 101.719 Mbps ( 12.715 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1368 +Fri May 6 14:27:23 EDT 2022 +05-06-2022 18:27:23 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 246.750 Mbps ( 30.844 MBps), using 24 parallel connections. +Upload: 97.812 Mbps ( 12.227 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1274 +Fri May 6 14:27:56 EDT 2022 +05-06-2022 18:27:56 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 226.812 Mbps ( 28.352 MBps), using 20 parallel connections. +Upload: 94.844 Mbps ( 11.855 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1081 +Fri May 6 14:28:24 EDT 2022 +05-06-2022 18:28:24 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 215.719 Mbps ( 26.965 MBps), using 16 parallel connections. +Upload: 99.750 Mbps ( 12.469 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1281 +Fri May 6 14:28:51 EDT 2022 +05-06-2022 18:28:52 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 206.875 Mbps ( 25.859 MBps), using 20 parallel connections. +Upload: 95.844 Mbps ( 11.980 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1417 +Fri May 6 14:29:19 EDT 2022 +05-06-2022 18:29:20 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 232.844 Mbps ( 29.105 MBps), using 20 parallel connections. +Upload: 100.062 Mbps ( 12.508 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1392 +Fri May 6 14:29:49 EDT 2022 +05-06-2022 18:29:50 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 237.094 Mbps ( 29.637 MBps), using 16 parallel connections. +Upload: 99.906 Mbps ( 12.488 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1420 +Fri May 6 14:30:18 EDT 2022 +05-06-2022 18:30:19 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 198.500 Mbps ( 24.812 MBps), using 20 parallel connections. +Upload: 98.719 Mbps ( 12.340 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1270 +Fri May 6 14:30:47 EDT 2022 +05-06-2022 18:30:48 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 237.750 Mbps ( 29.719 MBps), using 20 parallel connections. +Upload: 98.312 Mbps ( 12.289 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1435 +Fri May 6 14:31:17 EDT 2022 +05-06-2022 18:31:18 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 229.438 Mbps ( 28.680 MBps), using 16 parallel connections. +Upload: 101.406 Mbps ( 12.676 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1391 +Fri May 6 14:31:43 EDT 2022 +05-06-2022 18:31:43 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 237.781 Mbps ( 29.723 MBps), using 20 parallel connections. +Upload: 102.750 Mbps ( 12.844 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1131 +Fri May 6 14:32:11 EDT 2022 +05-06-2022 18:32:11 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 189.719 Mbps ( 23.715 MBps), using 16 parallel connections. +Upload: 94.750 Mbps ( 11.844 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1302 +Fri May 6 14:32:37 EDT 2022 +05-06-2022 18:32:37 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 210.438 Mbps ( 26.305 MBps), using 20 parallel connections. +Upload: 94.688 Mbps ( 11.836 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1372 +Fri May 6 14:33:05 EDT 2022 +05-06-2022 18:33:05 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 177.000 Mbps ( 22.125 MBps), using 12 parallel connections. +Upload: 98.719 Mbps ( 12.340 MBps), using 24 parallel connections. +Total RTTs measured: 25 +RPM: 1384 +Fri May 6 14:33:31 EDT 2022 +05-06-2022 18:33:31 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 249.922 Mbps ( 31.240 MBps), using 16 parallel connections. +Upload: 93.125 Mbps ( 11.641 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1400 +Fri May 6 14:33:59 EDT 2022 +05-06-2022 18:33:59 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 231.281 Mbps ( 28.910 MBps), using 24 parallel connections. +Upload: 99.125 Mbps ( 12.391 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1452 +Fri May 6 14:34:29 EDT 2022 +05-06-2022 18:34:29 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 235.219 Mbps ( 29.402 MBps), using 28 parallel connections. +Upload: 94.281 Mbps ( 11.785 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1102 +Fri May 6 14:34:59 EDT 2022 +05-06-2022 18:35:00 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 243.312 Mbps ( 30.414 MBps), using 16 parallel connections. +Upload: 92.750 Mbps ( 11.594 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1340 +Fri May 6 14:35:29 EDT 2022 +05-06-2022 18:35:29 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 233.578 Mbps ( 29.197 MBps), using 20 parallel connections. +Upload: 97.031 Mbps ( 12.129 MBps), using 16 parallel connections. +Total RTTs measured: 25 +RPM: 1222 +Fri May 6 14:35:55 EDT 2022 +05-06-2022 18:35:55 UTC Go Responsiveness to rpm.obs.cr:4043... +Download: 187.188 Mbps ( 23.398 MBps), using 16 parallel connections. +Upload: 94.469 Mbps ( 11.809 MBps), using 12 parallel connections. +Total RTTs measured: 25 +RPM: 1049 diff --git a/data-analysis1/nq.log.FriMay6121542EDT2022 b/data-analysis1/nq.log.FriMay6121542EDT2022 new file mode 100644 index 0000000..daf1ee8 --- /dev/null +++ b/data-analysis1/nq.log.FriMay6121542EDT2022 @@ -0,0 +1,706 @@ +Fri May 6 12:15:53 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.228 Mbps +Download capacity: 218.659 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (750 RPM) +Fri May 6 12:16:22 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.952 Mbps +Download capacity: 244.182 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (760 RPM) +Fri May 6 12:16:50 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.293 Mbps +Download capacity: 208.117 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (625 RPM) +Fri May 6 12:17:19 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.892 Mbps +Download capacity: 222.567 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (722 RPM) +Fri May 6 12:17:49 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.590 Mbps +Download capacity: 217.989 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (725 RPM) +Fri May 6 12:18:20 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.099 Mbps +Download capacity: 220.155 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (590 RPM) +Fri May 6 12:18:46 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.687 Mbps +Download capacity: 222.652 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (827 RPM) +Fri May 6 12:19:10 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 112.067 Mbps +Download capacity: 178.311 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (655 RPM) +Fri May 6 12:19:40 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.898 Mbps +Download capacity: 222.672 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (690 RPM) +Fri May 6 12:20:05 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.724 Mbps +Download capacity: 215.472 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (600 RPM) +Fri May 6 12:20:33 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 102.110 Mbps +Download capacity: 232.306 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (559 RPM) +Fri May 6 12:21:04 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.667 Mbps +Download capacity: 199.271 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (754 RPM) +Fri May 6 12:21:32 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.011 Mbps +Download capacity: 243.138 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (744 RPM) +Fri May 6 12:22:02 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.853 Mbps +Download capacity: 230.462 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (684 RPM) +Fri May 6 12:22:29 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.189 Mbps +Download capacity: 222.692 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (455 RPM) +Fri May 6 12:23:00 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.924 Mbps +Download capacity: 242.201 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (881 RPM) +Fri May 6 12:23:27 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.533 Mbps +Download capacity: 237.270 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (840 RPM) +Fri May 6 12:23:54 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.506 Mbps +Download capacity: 220.446 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (734 RPM) +Fri May 6 12:24:24 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.440 Mbps +Download capacity: 237.162 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (692 RPM) +Fri May 6 12:24:49 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.402 Mbps +Download capacity: 198.605 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (710 RPM) +Fri May 6 12:25:17 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.142 Mbps +Download capacity: 233.331 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (692 RPM) +Fri May 6 12:25:47 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.372 Mbps +Download capacity: 225.168 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (687 RPM) +Fri May 6 12:26:17 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.790 Mbps +Download capacity: 217.393 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (785 RPM) +Fri May 6 12:43:09 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 110.739 Mbps +Download capacity: 203.582 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (785 RPM) +Fri May 6 12:43:37 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.097 Mbps +Download capacity: 245.020 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (804 RPM) +Fri May 6 13:00:00 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.980 Mbps +Download capacity: 223.346 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (720 RPM) +Fri May 6 13:00:26 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.813 Mbps +Download capacity: 0.000 bps +Upload flows: 12 +Download flows: 0 +Responsiveness: Low (0 RPM) +Error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_kCFStreamErrorCodeKey=-2103, _NSURLErrorFailingURLSessionTaskErrorKey=LocalDataTask <30FA63FB-A969-412E-BE87-6AC0C78A1DDD>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( + "LocalDataTask <30FA63FB-A969-412E-BE87-6AC0C78A1DDD>.<1>" +), NSLocalizedDescription=The request timed out., NSErrorFailingURLStringKey=https://rpm.obs.cr:4043/large, NSErrorFailingURLKey=https://rpm.obs.cr:4043/large, _kCFStreamErrorDomainKey=4} +Fri May 6 13:16:35 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.245 Mbps +Download capacity: 206.718 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (739 RPM) +Fri May 6 13:17:04 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 113.983 Mbps +Download capacity: 211.784 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (778 RPM) +Fri May 6 13:33:35 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.902 Mbps +Download capacity: 220.833 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (781 RPM) +Fri May 6 13:33:58 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.517 Mbps +Download capacity: 235.952 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (787 RPM) +Fri May 6 13:34:28 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.434 Mbps +Download capacity: 195.913 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (834 RPM) +Fri May 6 13:34:58 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 99.899 Mbps +Download capacity: 194.734 Mbps +Upload flows: 20 +Download flows: 12 +Responsiveness: Medium (774 RPM) +Fri May 6 13:35:26 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.248 Mbps +Download capacity: 232.575 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (785 RPM) +Fri May 6 13:35:56 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.826 Mbps +Download capacity: 206.413 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (748 RPM) +Fri May 6 13:36:26 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.015 Mbps +Download capacity: 229.482 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (804 RPM) +Fri May 6 13:36:55 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 110.905 Mbps +Download capacity: 240.852 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (768 RPM) +Fri May 6 13:37:30 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 110.012 Mbps +Download capacity: 201.126 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (777 RPM) +Fri May 6 13:37:53 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.942 Mbps +Download capacity: 175.995 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (743 RPM) +Fri May 6 13:38:22 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.557 Mbps +Download capacity: 239.961 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (634 RPM) +Fri May 6 13:38:52 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.922 Mbps +Download capacity: 211.542 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (711 RPM) +Fri May 6 13:39:24 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.224 Mbps +Download capacity: 181.004 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (907 RPM) +Fri May 6 13:39:53 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 113.341 Mbps +Download capacity: 241.858 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (768 RPM) +Fri May 6 13:40:21 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.718 Mbps +Download capacity: 211.659 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (726 RPM) +Fri May 6 13:40:50 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.603 Mbps +Download capacity: 198.066 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: High (1018 RPM) +Fri May 6 13:41:18 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.938 Mbps +Download capacity: 191.725 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (706 RPM) +Fri May 6 13:41:45 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.099 Mbps +Download capacity: 234.977 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (786 RPM) +Fri May 6 13:42:11 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.811 Mbps +Download capacity: 246.472 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (818 RPM) +Fri May 6 13:42:43 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 102.009 Mbps +Download capacity: 216.726 Mbps +Upload flows: 20 +Download flows: 12 +Responsiveness: Medium (1000 RPM) +Fri May 6 13:43:15 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.341 Mbps +Download capacity: 229.436 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (691 RPM) +Fri May 6 13:43:43 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 0.000 bps +Download capacity: 0.000 bps +Upload flows: 0 +Download flows: 0 +Responsiveness: Low (0 RPM) +Error: Error Domain=NSURLErrorDomain Code=-1001 "The request timed out." UserInfo={_kCFStreamErrorCodeKey=-2103, _NSURLErrorFailingURLSessionTaskErrorKey=LocalUploadTask <A539CB65-6940-4113-9A91-803CF63DB7DC>.<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( + "LocalUploadTask <A539CB65-6940-4113-9A91-803CF63DB7DC>.<1>" +), NSLocalizedDescription=The request timed out., NSErrorFailingURLStringKey=https://rpm.obs.cr:4043/slurp, NSErrorFailingURLKey=https://rpm.obs.cr:4043/slurp, _kCFStreamErrorDomainKey=4} +Fri May 6 13:57:41 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.636 Mbps +Download capacity: 247.670 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (742 RPM) +Fri May 6 13:58:12 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 99.389 Mbps +Download capacity: 222.985 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (588 RPM) +Fri May 6 13:58:42 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.939 Mbps +Download capacity: 232.160 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (751 RPM) +Fri May 6 13:59:12 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.408 Mbps +Download capacity: 252.061 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (755 RPM) +Fri May 6 13:59:39 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.279 Mbps +Download capacity: 230.427 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (726 RPM) +Fri May 6 14:00:03 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.877 Mbps +Download capacity: 206.099 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (772 RPM) +Fri May 6 14:00:32 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.542 Mbps +Download capacity: 227.790 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (368 RPM) +Fri May 6 14:01:03 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.927 Mbps +Download capacity: 225.601 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (720 RPM) +Fri May 6 14:01:37 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.976 Mbps +Download capacity: 206.530 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (786 RPM) +Fri May 6 14:02:03 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.583 Mbps +Download capacity: 235.161 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (715 RPM) +Fri May 6 14:02:31 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.618 Mbps +Download capacity: 244.451 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (715 RPM) +Fri May 6 14:02:59 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 102.666 Mbps +Download capacity: 198.902 Mbps +Upload flows: 12 +Download flows: 12 +Responsiveness: Medium (695 RPM) +Fri May 6 14:03:25 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.240 Mbps +Download capacity: 207.854 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (832 RPM) +Fri May 6 14:03:53 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.824 Mbps +Download capacity: 185.081 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (348 RPM) +Fri May 6 14:04:23 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 102.466 Mbps +Download capacity: 243.883 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (748 RPM) +Fri May 6 14:04:55 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.198 Mbps +Download capacity: 221.094 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (790 RPM) +Fri May 6 14:05:23 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.801 Mbps +Download capacity: 220.624 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (717 RPM) +Fri May 6 14:05:54 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.747 Mbps +Download capacity: 217.499 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (620 RPM) +Fri May 6 14:06:24 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.044 Mbps +Download capacity: 220.420 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (745 RPM) +Fri May 6 14:06:50 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.811 Mbps +Download capacity: 225.198 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (746 RPM) +Fri May 6 14:07:17 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.745 Mbps +Download capacity: 244.119 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (684 RPM) +Fri May 6 14:23:12 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.643 Mbps +Download capacity: 212.189 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (743 RPM) +Fri May 6 14:23:36 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.960 Mbps +Download capacity: 208.540 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (784 RPM) +Fri May 6 14:24:08 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.011 Mbps +Download capacity: 230.454 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (726 RPM) +Fri May 6 14:24:38 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.849 Mbps +Download capacity: 206.637 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (644 RPM) +Fri May 6 14:25:08 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 110.984 Mbps +Download capacity: 219.081 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (759 RPM) +Fri May 6 14:25:38 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.365 Mbps +Download capacity: 220.186 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (925 RPM) +Fri May 6 14:26:12 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.404 Mbps +Download capacity: 212.779 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (764 RPM) +Fri May 6 14:26:42 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.366 Mbps +Download capacity: 242.648 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (745 RPM) +Fri May 6 14:27:09 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.287 Mbps +Download capacity: 237.468 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (814 RPM) +Fri May 6 14:27:41 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 111.862 Mbps +Download capacity: 219.342 Mbps +Upload flows: 20 +Download flows: 16 +Responsiveness: Medium (737 RPM) +Fri May 6 14:28:08 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.669 Mbps +Download capacity: 230.981 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (916 RPM) +Fri May 6 14:28:36 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 111.104 Mbps +Download capacity: 233.045 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (744 RPM) +Fri May 6 14:29:04 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.384 Mbps +Download capacity: 241.912 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (682 RPM) +Fri May 6 14:29:34 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.921 Mbps +Download capacity: 219.502 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (733 RPM) +Fri May 6 14:30:03 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 104.961 Mbps +Download capacity: 240.818 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (705 RPM) +Fri May 6 14:30:32 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 109.135 Mbps +Download capacity: 220.795 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (694 RPM) +Fri May 6 14:31:02 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.906 Mbps +Download capacity: 204.778 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (735 RPM) +Fri May 6 14:31:31 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.623 Mbps +Download capacity: 182.085 Mbps +Upload flows: 16 +Download flows: 12 +Responsiveness: Medium (787 RPM) +Fri May 6 14:31:57 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 103.090 Mbps +Download capacity: 238.842 Mbps +Upload flows: 12 +Download flows: 16 +Responsiveness: Medium (890 RPM) +Fri May 6 14:32:21 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.466 Mbps +Download capacity: 252.519 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (848 RPM) +Fri May 6 14:32:49 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.518 Mbps +Download capacity: 231.886 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (808 RPM) +Fri May 6 14:33:15 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.921 Mbps +Download capacity: 217.197 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (790 RPM) +Fri May 6 14:33:43 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 108.151 Mbps +Download capacity: 239.796 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (910 RPM) +Fri May 6 14:34:13 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.803 Mbps +Download capacity: 232.514 Mbps +Upload flows: 16 +Download flows: 20 +Responsiveness: Medium (833 RPM) +Fri May 6 14:34:44 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 105.526 Mbps +Download capacity: 213.560 Mbps +Upload flows: 20 +Download flows: 20 +Responsiveness: Medium (723 RPM) +Fri May 6 14:35:13 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.762 Mbps +Download capacity: 233.563 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (669 RPM) +Fri May 6 14:35:41 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 107.156 Mbps +Download capacity: 211.915 Mbps +Upload flows: 16 +Download flows: 16 +Responsiveness: Medium (762 RPM) +Fri May 6 14:36:06 EDT 2022 +
==== SUMMARY ==== +Upload capacity: 106.083 Mbps +Download capacity: 233.485 Mbps +Upload flows: 12 +Download flows: 20 +Responsiveness: Medium (745 RPM) diff --git a/extendedstats/other.go b/extendedstats/other.go new file mode 100644 index 0000000..c0f89ed --- /dev/null +++ b/extendedstats/other.go @@ -0,0 +1,22 @@ +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd + +package extendedstats + +import ( + "net" + + "golang.org/x/sys/unix" +) + +type ExtendedStats struct{} + +func (es *ExtendedStats) IncorporateConnectionStats(conn net.Conn) {} + +func (es *ExtendedStats) Repr() string { + return "" +} + +func ExtendedStatsAvailable() bool { + return false +} diff --git a/extendedstats/unix.go b/extendedstats/unix.go new file mode 100644 index 0000000..e50d719 --- /dev/null +++ b/extendedstats/unix.go @@ -0,0 +1,72 @@ +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd + +package extendedstats + +import ( + "crypto/tls" + "fmt" + "net" + + "github.com/network-quality/goresponsiveness/utilities" + "golang.org/x/sys/unix" +) + +type ExtendedStats struct { + MaxPathMtu uint64 + TotalRetransmissions uint64 + AverageRtt float64 + rtt_measurements uint64 + total_rtt float64 +} + +func ExtendedStatsAvailable() bool { + return true +} + +func (es *ExtendedStats) IncorporateConnectionStats(rawConn net.Conn) { + tlsConn, ok := rawConn.(*tls.Conn) + if !ok { + fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TLS connection)!\n") + } + tcpConn, ok := tlsConn.NetConn().(*net.TCPConn) + if !ok { + fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TCP connection)!\n") + } + if info, err := getTCPInfo(tcpConn); err != nil { + fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err) + } else { + es.MaxPathMtu = utilities.Max(es.MaxPathMtu, uint64(info.Pmtu)) + // https://lkml.iu.edu/hypermail/linux/kernel/1705.0/01790.html + es.TotalRetransmissions += uint64(info.Total_retrans) + es.total_rtt += float64(info.Rtt) + es.rtt_measurements += 1 + es.AverageRtt = es.total_rtt / float64(es.rtt_measurements) + + } +} + +func (es *ExtendedStats) Repr() string { + return fmt.Sprintf(`Extended Statistics: + Maximum Path MTU: %v + Total Retransmissions: %v + Average RTT: %v +`, es.MaxPathMtu, es.TotalRetransmissions, es.AverageRtt) +} + +func getTCPInfo(connection net.Conn) (*unix.TCPInfo, error) { + tcpConn, ok := connection.(*net.TCPConn) + if !ok { + return nil, fmt.Errorf("connection is not a net.TCPConn") + } + rawConn, err := tcpConn.SyscallConn() + if err != nil { + return nil, err + } + + var info *unix.TCPInfo = nil + rawConn.Control(func(fd uintptr) { + info, err = unix.GetsockoptTCPInfo(int(fd), unix.SOL_TCP, unix.TCP_INFO) + }) + return info, err +} @@ -4,4 +4,7 @@ go 1.18 require golang.org/x/net v0.0.0-20220225172249-27dd8689420f -require golang.org/x/text v0.3.7 // indirect +require ( + golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a // indirect + golang.org/x/text v0.3.7 // indirect +) @@ -1,4 +1,6 @@ golang.org/x/net v0.0.0-20220225172249-27dd8689420f h1:oA4XRj0qtSt8Yo1Zms0CUlsT3KG69V2UGQWPBxujDmc= golang.org/x/net v0.0.0-20220225172249-27dd8689420f/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a h1:dGzPydgVsqGcTRVwiLJ1jVbufYwmzD3LfVPLKsKg+0k= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= @@ -34,22 +34,28 @@ import ( type LoadGeneratingConnection interface { Start(context.Context, debug.DebugLevel) bool - Transferred() uint64 + TransferredInInterval() (uint64, time.Duration) Client() *http.Client IsValid() bool ClientId() uint64 + Stats() *stats.TraceStats } +// TODO: All 64-bit fields that are accessed atomically must +// appear at the top of this struct. type LoadGeneratingConnectionDownload struct { - Path string - downloaded uint64 - client *http.Client - debug debug.DebugLevel - valid bool - KeyLogger io.Writer - clientId uint64 - tracer *httptrace.ClientTrace - stats stats.TraceStats + downloaded uint64 + lastIntervalEnd int64 + Path string + downloadStartTime time.Time + lastDownloaded uint64 + client *http.Client + debug debug.DebugLevel + valid bool + KeyLogger io.Writer + clientId uint64 + tracer *httptrace.ClientTrace + stats stats.TraceStats } func (lgd *LoadGeneratingConnectionDownload) SetDnsStartTimeInfo( @@ -126,6 +132,10 @@ func (lgd *LoadGeneratingConnectionDownload) SetGotConnTimeInfo( now time.Time, gotConnInfo httptrace.GotConnInfo, ) { + if gotConnInfo.Reused { + fmt.Printf("Unexpectedly reusing a connection!\n") + panic(!gotConnInfo.Reused) + } lgd.stats.GetConnectionDoneTime = now lgd.stats.ConnInfo = gotConnInfo if debug.IsDebug(lgd.debug) { @@ -200,12 +210,15 @@ func (lgd *LoadGeneratingConnectionDownload) ClientId() uint64 { return lgd.clientId } -func (lgd *LoadGeneratingConnectionDownload) Transferred() uint64 { - transferred := atomic.LoadUint64(&lgd.downloaded) +func (lgd *LoadGeneratingConnectionDownload) TransferredInInterval() (uint64, time.Duration) { + transferred := atomic.SwapUint64(&lgd.downloaded, 0) + newIntervalEnd := (time.Now().Sub(lgd.downloadStartTime)).Nanoseconds() + previousIntervalEnd := atomic.SwapInt64(&lgd.lastIntervalEnd, newIntervalEnd) + intervalLength := time.Duration(newIntervalEnd - previousIntervalEnd) if debug.IsDebug(lgd.debug) { - fmt.Printf("download: Transferred: %v\n", transferred) + fmt.Printf("download: Transferred: %v bytes in %v.\n", transferred, intervalLength) } - return transferred + return transferred, intervalLength } func (lgd *LoadGeneratingConnectionDownload) Client() *http.Client { @@ -268,57 +281,72 @@ func (lgd *LoadGeneratingConnectionDownload) Start( go lgd.doDownload(ctx) return true } -func (lbd *LoadGeneratingConnectionDownload) IsValid() bool { - return lbd.valid +func (lgd *LoadGeneratingConnectionDownload) IsValid() bool { + return lgd.valid +} + +func (lgd *LoadGeneratingConnectionDownload) Stats() *stats.TraceStats { + return &lgd.stats } -func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { +func (lgd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { var request *http.Request = nil var get *http.Response = nil var err error = nil if request, err = http.NewRequestWithContext( - httptrace.WithClientTrace(ctx, lbd.tracer), + httptrace.WithClientTrace(ctx, lgd.tracer), "GET", - lbd.Path, + lgd.Path, nil, ); err != nil { - lbd.valid = false + lgd.valid = false return } - if get, err = lbd.client.Do(request); err != nil { - lbd.valid = false + lgd.downloadStartTime = time.Now() + lgd.lastIntervalEnd = 0 + + if get, err = lgd.client.Do(request); err != nil { + lgd.valid = false return } - cr := &countingReader{n: &lbd.downloaded, ctx: ctx, readable: get.Body} + cr := &countingReader{n: &lgd.downloaded, ctx: ctx, readable: get.Body} _, _ = io.Copy(ioutil.Discard, cr) get.Body.Close() - if debug.IsDebug(lbd.debug) { + if debug.IsDebug(lgd.debug) { fmt.Printf("Ending a load-generating download.\n") } } +// TODO: All 64-bit fields that are accessed atomically must +// appear at the top of this struct. type LoadGeneratingConnectionUpload struct { - Path string - uploaded uint64 - client *http.Client - debug debug.DebugLevel - valid bool - KeyLogger io.Writer - clientId uint64 + uploaded uint64 + lastIntervalEnd int64 + Path string + uploadStartTime time.Time + lastUploaded uint64 + client *http.Client + debug debug.DebugLevel + valid bool + KeyLogger io.Writer + clientId uint64 } func (lgu *LoadGeneratingConnectionUpload) ClientId() uint64 { return lgu.clientId } -func (lgu *LoadGeneratingConnectionUpload) Transferred() uint64 { - transferred := atomic.LoadUint64(&lgu.uploaded) - if debug.IsDebug(lgu.debug) { - fmt.Printf("upload: Transferred: %v\n", transferred) +func (lgd *LoadGeneratingConnectionUpload) TransferredInInterval() (uint64, time.Duration) { + transferred := atomic.SwapUint64(&lgd.uploaded, 0) + newIntervalEnd := (time.Now().Sub(lgd.uploadStartTime)).Nanoseconds() + previousIntervalEnd := atomic.SwapInt64(&lgd.lastIntervalEnd, newIntervalEnd) + intervalLength := time.Duration(newIntervalEnd - previousIntervalEnd) + if debug.IsDebug(lgd.debug) { + fmt.Printf("upload: Transferred: %v bytes in %v.\n", transferred, intervalLength) } - return transferred + return transferred, intervalLength } func (lgu *LoadGeneratingConnectionUpload) Client() *http.Client { @@ -351,6 +379,9 @@ func (lgu *LoadGeneratingConnectionUpload) doUpload(ctx context.Context) bool { var resp *http.Response = nil var err error + lgu.uploadStartTime = time.Now() + lgu.lastIntervalEnd = 0 + if resp, err = lgu.client.Post(lgu.Path, "application/octet-stream", s); err != nil { lgu.valid = false return false @@ -394,3 +425,8 @@ func (lgu *LoadGeneratingConnectionUpload) Start( go lgu.doUpload(ctx) return true } + +func (lgu *LoadGeneratingConnectionUpload) Stats() *stats.TraceStats { + // Get all your stats from the download side of the LGC. + return nil +} diff --git a/networkQuality.go b/networkQuality.go index 6b80a7e..217ee6a 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -17,25 +17,19 @@ package main import ( "context" "crypto/tls" - "encoding/json" "flag" "fmt" - _ "io" - "io/ioutil" - _ "log" - "math/rand" "net/http" - "net/url" "os" "runtime/pprof" - "strings" "time" "github.com/network-quality/goresponsiveness/ccw" + "github.com/network-quality/goresponsiveness/config" "github.com/network-quality/goresponsiveness/constants" "github.com/network-quality/goresponsiveness/debug" + "github.com/network-quality/goresponsiveness/extendedstats" "github.com/network-quality/goresponsiveness/lgc" - "github.com/network-quality/goresponsiveness/ma" "github.com/network-quality/goresponsiveness/rpm" "github.com/network-quality/goresponsiveness/timeoutat" "github.com/network-quality/goresponsiveness/utilities" @@ -64,6 +58,11 @@ var ( constants.DefaultDebug, "Enable debugging.", ) + strictFlag = flag.Bool( + "strict", + constants.DefaultStrict, + "Whether to run the test in strict mode (measure HTTP get time on load-generating connection)", + ) timeout = flag.Int( "timeout", constants.DefaultTestTime, @@ -79,344 +78,13 @@ var ( "", "Enable client runtime profiling and specify storage location. Disabled by default.", ) -) - -type ConfigUrls struct { - SmallUrl string `json:"small_https_download_url"` - LargeUrl string `json:"large_https_download_url"` - UploadUrl string `json:"https_upload_url"` -} - -type Config struct { - Version int - Urls ConfigUrls `json:"urls"` - Source string - Test_Endpoint string -} - -func (c *Config) Get(configHost string, configPath string) error { - configTransport := http2.Transport{} - configTransport.TLSClientConfig = &tls.Config{InsecureSkipVerify: true} - configClient := &http.Client{Transport: &configTransport} - // Extraneous /s in URLs is normally okay, but the Apple CDN does not - // like them. Make sure that we put exactly one (1) / between the host - // and the path. - if !strings.HasPrefix(configPath, "/") { - configPath = "/" + configPath - } - c.Source = fmt.Sprintf("https://%s%s", configHost, configPath) - resp, err := configClient.Get(c.Source) - if err != nil { - return fmt.Errorf( - "Error: Could not connect to configuration host %s: %v\n", - configHost, - err, - ) - } - - jsonConfig, err := ioutil.ReadAll(resp.Body) - if err != nil { - return fmt.Errorf( - "Error: Could not read configuration content downloaded from %s: %v\n", - c.Source, - err, - ) - } - err = json.Unmarshal(jsonConfig, c) - if err != nil { - return fmt.Errorf( - "Error: Could not parse configuration returned from %s: %v\n", - c.Source, - err, - ) - } - - //if len(c.Test_Endpoint) != 0 { - if false { - tempUrl, err := url.Parse(c.Urls.LargeUrl) - if err != nil { - return fmt.Errorf("Error parsing large_https_download_url: %v", err) - } - c.Urls.LargeUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path - tempUrl, err = url.Parse(c.Urls.SmallUrl) - if err != nil { - return fmt.Errorf("Error parsing small_https_download_url: %v", err) - } - c.Urls.SmallUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path - tempUrl, err = url.Parse(c.Urls.UploadUrl) - if err != nil { - return fmt.Errorf("Error parsing https_upload_url: %v", err) - } - c.Urls.UploadUrl = tempUrl.Scheme + "://" + c.Test_Endpoint + "/" + tempUrl.Path - } - return nil -} - -func (c *Config) String() string { - return fmt.Sprintf( - "Version: %d\nSmall URL: %s\nLarge URL: %s\nUpload URL: %s\nEndpoint: %s\n", - c.Version, - c.Urls.SmallUrl, - c.Urls.LargeUrl, - c.Urls.UploadUrl, - c.Test_Endpoint, + calculateExtendedStats = flag.Bool( + "extended-stats", + false, + "Enable the collection and display of extended statistics -- may not be available on certain platforms.", ) -} - -func (c *Config) IsValid() error { - if parsedUrl, err := url.ParseRequestURI(c.Urls.LargeUrl); err != nil || - parsedUrl.Scheme != "https" { - return fmt.Errorf( - "Configuration url large_https_download_url is invalid: %s", - utilities.Conditional( - len(c.Urls.LargeUrl) != 0, - c.Urls.LargeUrl, - "Missing", - ), - ) - } - if parsedUrl, err := url.ParseRequestURI(c.Urls.SmallUrl); err != nil || - parsedUrl.Scheme != "https" { - return fmt.Errorf( - "Configuration url small_https_download_url is invalid: %s", - utilities.Conditional( - len(c.Urls.SmallUrl) != 0, - c.Urls.SmallUrl, - "Missing", - ), - ) - } - if parsedUrl, err := url.ParseRequestURI(c.Urls.UploadUrl); err != nil || - parsedUrl.Scheme != "https" { - return fmt.Errorf( - "Configuration url https_upload_url is invalid: %s", - utilities.Conditional( - len(c.Urls.UploadUrl) != 0, - c.Urls.UploadUrl, - "Missing", - ), - ) - } - return nil -} - -func addFlows( - ctx context.Context, - toAdd uint64, - lgcs *[]lgc.LoadGeneratingConnection, - lgcsPreviousTransferred *[]uint64, - lgcGenerator func() lgc.LoadGeneratingConnection, - debug debug.DebugLevel, -) { - for i := uint64(0); i < toAdd; i++ { - *lgcs = append(*lgcs, lgcGenerator()) - *lgcsPreviousTransferred = append(*lgcsPreviousTransferred, 0) - if !(*lgcs)[len(*lgcs)-1].Start(ctx, debug) { - fmt.Printf( - "Error starting lgc with id %d!\n", - (*lgcs)[len(*lgcs)-1].ClientId(), - ) - return - } - } -} - -type SaturationResult struct { - RateBps float64 - lgcs []lgc.LoadGeneratingConnection -} - -func saturate( - saturationCtx context.Context, - operatingCtx context.Context, - lgcGenerator func() lgc.LoadGeneratingConnection, - debugging *debug.DebugWithPrefix, -) (saturated chan SaturationResult) { - saturated = make(chan SaturationResult) - go func() { - - lgcs := make([]lgc.LoadGeneratingConnection, 0) - lgcsPreviousTransferred := make([]uint64, 0) - - addFlows( - saturationCtx, - constants.StartingNumberOfLoadGeneratingConnections, - &lgcs, - &lgcsPreviousTransferred, - lgcGenerator, - debugging.Level, - ) - - previousFlowIncreaseIteration := uint64(0) - previousMovingAverage := float64(0) - movingAverage := ma.NewMovingAverage( - constants.MovingAverageIntervalCount, - ) - movingAverageAverage := ma.NewMovingAverage( - constants.MovingAverageIntervalCount, - ) - - nextSampleStartTime := time.Now().Add(time.Second) - - for currentIteration := uint64(0); true; currentIteration++ { - - // When the program stops operating, then stop. - if saturationCtx.Err() != nil { - return - } - - // We may be asked to stop trying to saturate the - // network and return our current status. - if saturationCtx.Err() != nil { - //break - } - - now := time.Now() - // At each 1-second interval - if nextSampleStartTime.Sub(now) > 0 { - if debug.IsDebug(debugging.Level) { - fmt.Printf( - "%v: Sleeping until %v\n", - debugging, - nextSampleStartTime, - ) - } - time.Sleep(nextSampleStartTime.Sub(now)) - } else { - fmt.Fprintf(os.Stderr, "Warning: Missed a one-second deadline.\n") - } - nextSampleStartTime = time.Now().Add(time.Second) - - // Compute "instantaneous aggregate" goodput which is the number of - // bytes transferred within the last second. - totalTransfer := uint64(0) - allInvalid := true - for i := range lgcs { - if !lgcs[i].IsValid() { - if debug.IsDebug(debugging.Level) { - fmt.Printf( - "%v: Load-generating connection with id %d is invalid ... skipping.\n", - debugging, - lgcs[i].ClientId(), - ) - } - continue - } - allInvalid = false - previousTransferred := lgcsPreviousTransferred[i] - currentTransferred := lgcs[i].Transferred() - totalTransfer += (currentTransferred - previousTransferred) - lgcsPreviousTransferred[i] = currentTransferred - } - - // For some reason, all the lgcs are invalid. This likely means that - // the network/server went away. - if allInvalid { - if debug.IsDebug(debugging.Level) { - fmt.Printf( - "%v: All lgcs were invalid. Assuming that network/server went away.\n", - debugging, - ) - } - break - } - - // Compute a moving average of the last - // constants.MovingAverageIntervalCount "instantaneous aggregate - // goodput" measurements - movingAverage.AddMeasurement(float64(totalTransfer)) - currentMovingAverage := movingAverage.CalculateAverage() - movingAverageAverage.AddMeasurement(currentMovingAverage) - movingAverageDelta := utilities.SignedPercentDifference( - currentMovingAverage, - previousMovingAverage, - ) - - if debug.IsDebug(debugging.Level) { - fmt.Printf( - "%v: Instantaneous goodput: %f MB.\n", - debugging, - utilities.ToMBps(float64(totalTransfer)), - ) - fmt.Printf( - "%v: Previous moving average: %f MB.\n", - debugging, - utilities.ToMBps(previousMovingAverage), - ) - fmt.Printf( - "%v: Current moving average: %f MB.\n", - debugging, - utilities.ToMBps(currentMovingAverage), - ) - fmt.Printf( - "%v: Moving average delta: %f.\n", - debugging, - movingAverageDelta, - ) - } - - previousMovingAverage = currentMovingAverage - - // Special case: We won't make any adjustments on the first - // iteration. - if currentIteration == 0 { - continue - } - - // If moving average > "previous" moving average + InstabilityDelta: - if movingAverageDelta > constants.InstabilityDelta { - // Network did not yet reach saturation. If no flows added - // within the last 4 seconds, add 4 more flows - if (currentIteration - previousFlowIncreaseIteration) > uint64( - constants.MovingAverageStabilitySpan, - ) { - if debug.IsDebug(debugging.Level) { - fmt.Printf( - "%v: Adding flows because we are unsaturated and waited a while.\n", - debugging, - ) - } - addFlows( - saturationCtx, - constants.AdditiveNumberOfLoadGeneratingConnections, - &lgcs, - &lgcsPreviousTransferred, - lgcGenerator, - debugging.Level, - ) - previousFlowIncreaseIteration = currentIteration - } else { - if debug.IsDebug(debugging.Level) { - fmt.Printf("%v: We are unsaturated, but it still too early to add anything.\n", debugging) - } - } - } else { // Else, network reached saturation for the current flow count. - if debug.IsDebug(debugging.Level) { - fmt.Printf("%v: Network reached saturation with current flow count.\n", debugging) - } - // If new flows added and for 4 seconds the moving average - // throughput did not change: network reached stable saturation - if (currentIteration-previousFlowIncreaseIteration) < uint64(constants.MovingAverageStabilitySpan) && movingAverageAverage.AllSequentialIncreasesLessThan(float64(5)) { - if debug.IsDebug(debugging.Level) { - fmt.Printf("%v: New flows added within the last four seconds and the moving-average average is consistent!\n", debugging) - } - break - } else { - // Else, add four more flows - if debug.IsDebug(debugging.Level) { - fmt.Printf("%v: New flows to add to try to increase our saturation!\n", debugging) - } - addFlows(saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, &lgcsPreviousTransferred, lgcGenerator, debugging.Level) - previousFlowIncreaseIteration = currentIteration - } - } - - } - saturated <- SaturationResult{RateBps: movingAverage.CalculateAverage(), lgcs: lgcs} - }() - return -} +) func main() { flag.Parse() @@ -428,13 +96,18 @@ func main() { saturationCtx, cancelSaturationCtx := context.WithCancel( context.Background(), ) - config := &Config{} + config := &config.Config{} var debugLevel debug.DebugLevel = debug.Error if *debugCliFlag { debugLevel = debug.Debug } + if *calculateExtendedStats && !extendedstats.ExtendedStatsAvailable() { + *calculateExtendedStats = false + fmt.Printf("Warning: Calculation of extended statics was requested but they are not supported on this platform.\n") + } + if err := config.Get(configHostPort, *configPath); err != nil { fmt.Fprintf(os.Stderr, "%s\n", err) return @@ -503,6 +176,10 @@ func main() { } } + /* + * Create (and then, ironically, name) two anonymous functions that, when invoked, + * will create load-generating connections for upload/download/ + */ generate_lbd := func() lgc.LoadGeneratingConnection { return &lgc.LoadGeneratingConnectionDownload{ Path: config.Urls.LargeUrl, @@ -519,13 +196,13 @@ func main() { var downloadDebugging *debug.DebugWithPrefix = debug.NewDebugWithPrefix(debugLevel, "download") var uploadDebugging *debug.DebugWithPrefix = debug.NewDebugWithPrefix(debugLevel, "upload") - downloadSaturationChannel := saturate( + downloadSaturationChannel := rpm.Saturate( saturationCtx, operatingCtx, generate_lbd, downloadDebugging, ) - uploadSaturationChannel := saturate( + uploadSaturationChannel := rpm.Saturate( saturationCtx, operatingCtx, generate_lbu, @@ -535,8 +212,8 @@ func main() { saturationTimeout := false uploadSaturated := false downloadSaturated := false - downloadSaturation := SaturationResult{} - uploadSaturation := SaturationResult{} + downloadSaturation := rpm.SaturationResult{} + uploadSaturation := rpm.SaturationResult{} for !(uploadSaturated && downloadSaturated) { select { @@ -552,7 +229,7 @@ func main() { "", ), utilities.ToMBps(downloadSaturation.RateBps), - len(downloadSaturation.lgcs), + len(downloadSaturation.LGCs), ) } } @@ -568,7 +245,7 @@ func main() { "", ), utilities.ToMBps(uploadSaturation.RateBps), - len(uploadSaturation.lgcs), + len(uploadSaturation.LGCs), ) } } @@ -580,7 +257,7 @@ func main() { // will exit! fmt.Fprint( os.Stderr, - "Error: Saturation could not be completed in time and no provisional rates could be accessed. Test failed.\n", + "Error: Saturation could not be completed in time and no provisional rates could be assessed. Test failed.\n", ) cancelOperatingCtx() if *debugCliFlag { @@ -624,25 +301,33 @@ func main() { ) } - totalRTsCount := uint64(0) - totalRTTimes := float64(0) - rttTimeout := false + totalMeasurements := uint64(0) + totalMeasurementTimes := float64(0) + measurementTimeout := false + extendedStats := extendedstats.ExtendedStats{} - for i := 0; i < constants.RPMProbeCount && !rttTimeout; i++ { - if len(downloadSaturation.lgcs) == 0 { + for i := 0; i < len(downloadSaturation.LGCs); 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. + if *calculateExtendedStats { + if !extendedstats.ExtendedStatsAvailable() { + panic("Extended stats are not available but the user requested their calculation.") + } + extendedStats.IncorporateConnectionStats(downloadSaturation.LGCs[i].Stats().ConnInfo.Conn) + } + } + + for i := 0; i < constants.MeasurementProbeCount && !measurementTimeout; i++ { + if len(downloadSaturation.LGCs) == 0 { continue } - randomlgcsIndex := rand.New(rand.NewSource(int64(time.Now().Nanosecond()))). - Int() % - len( - downloadSaturation.lgcs, - ) - if !downloadSaturation.lgcs[randomlgcsIndex].IsValid() { + randomLGCsIndex := utilities.RandBetween(len(downloadSaturation.LGCs)) + if !downloadSaturation.LGCs[randomLGCsIndex].IsValid() { if *debugCliFlag { fmt.Printf( - "%v: The randomly selected download lgc (with id %d) was invalid. Skipping.\n", + "%v: The randomly selected saturated connection (with id %d) was invalid. Skipping.\n", debugCliFlag, - downloadSaturation.lgcs[randomlgcsIndex].ClientId(), + downloadSaturation.LGCs[randomLGCsIndex].ClientId(), ) } @@ -652,7 +337,7 @@ func main() { if time.Since(timeoutAbsoluteTime) > 0 { if *debugCliFlag { fmt.Printf( - "Pathologically could not find valid lgcs to use for measurement.\n", + "Pathologically could not find valid saturated connections use for measurement.\n", ) } break @@ -660,46 +345,47 @@ func main() { continue } - newTransport := http2.Transport{} - newTransport.TLSClientConfig = &tls.Config{} + unsaturatedMeasurementTransport := http2.Transport{} + unsaturatedMeasurementTransport.TLSClientConfig = &tls.Config{} if sslKeyFileConcurrentWriter != nil { - newTransport.TLSClientConfig.KeyLogWriter = sslKeyFileConcurrentWriter + unsaturatedMeasurementTransport.TLSClientConfig.KeyLogWriter = sslKeyFileConcurrentWriter } - newTransport.TLSClientConfig.InsecureSkipVerify = true - newClient := http.Client{Transport: &newTransport} + unsaturatedMeasurementTransport.TLSClientConfig.InsecureSkipVerify = true + newClient := http.Client{Transport: &unsaturatedMeasurementTransport} - newRTTProbe := rpm.NewProbe(&newClient, debugLevel) + unsaturatedMeasurementProbe := rpm.NewProbe(&newClient, debugLevel) - saturatedRTTProbe := rpm.NewProbe( - downloadSaturation.lgcs[randomlgcsIndex].Client(), + saturatedMeasurementProbe := rpm.NewProbe( + downloadSaturation.LGCs[randomLGCsIndex].Client(), debugLevel, ) select { case <-timeoutChannel: { - rttTimeout = true + measurementTimeout = true } - case sequentialRTTimes := <-rpm.CalculateSequentialRTTsTime(operatingCtx, saturatedRTTProbe, newRTTProbe, config.Urls.SmallUrl, debugLevel): + case sequentialMeasurementTimes := <-rpm.CalculateProbeMeasurements(operatingCtx, *strictFlag, saturatedMeasurementProbe, unsaturatedMeasurementProbe, config.Urls.SmallUrl, debugLevel): { - if sequentialRTTimes.Err != nil { + if sequentialMeasurementTimes.Err != nil { fmt.Printf( - "Failed to calculate a time for sequential RTTs: %v\n", - sequentialRTTimes.Err, + "Failed to calculate a time for sequential measurements: %v\n", + sequentialMeasurementTimes.Err, ) continue } if debug.IsDebug(debugLevel) { - fmt.Printf("rttProbe: %v\n", newRTTProbe) + fmt.Printf("unsaturatedMeasurementProbe: %v\n", unsaturatedMeasurementProbe) } - // We know that we have a good Sequential RTT. - totalRTsCount += uint64(sequentialRTTimes.RoundTripCount) - totalRTTimes += sequentialRTTimes.Delay.Seconds() + // We know that we have a good Sequential measurement. + totalMeasurements += uint64(sequentialMeasurementTimes.MeasurementCount) + totalMeasurementTimes += sequentialMeasurementTimes.Delay.Seconds() if debug.IsDebug(debugLevel) { fmt.Printf( - "sequentialRTTsTime: %v\n", - sequentialRTTimes.Delay.Seconds(), + "most-recent sequential measurement time: %v; most-recent sequential measurement count: %v\n", + sequentialMeasurementTimes.Delay.Seconds(), + sequentialMeasurementTimes.MeasurementCount, ) } } @@ -710,36 +396,40 @@ func main() { "Download: %7.3f Mbps (%7.3f MBps), using %d parallel connections.\n", utilities.ToMbps(downloadSaturation.RateBps), utilities.ToMBps(downloadSaturation.RateBps), - len(downloadSaturation.lgcs), + len(downloadSaturation.LGCs), ) fmt.Printf( "Upload: %7.3f Mbps (%7.3f MBps), using %d parallel connections.\n", utilities.ToMbps(uploadSaturation.RateBps), utilities.ToMBps(uploadSaturation.RateBps), - len(uploadSaturation.lgcs), + len(uploadSaturation.LGCs), ) - if totalRTsCount != 0 { + if totalMeasurements != 0 { // "... it sums the five time values for each probe, and divides by the // total // number of probes to compute an average probe duration. The // reciprocal of this, normalized to 60 seconds, gives the Round-trips // Per Minute (RPM)." - // "average probe duration" = totalRTTimes / totalRTsCount. - // The reciprocol of this = 1 / (totalRTTimes / totalRTsCount) <- + // "average probe duration" = totalMeasurementTimes / totalMeasurements. + // The reciprocol of this = 1 / (totalMeasurementTimes / totalMeasurements) <- // semantically the probes-per-second. // Normalized to 60 seconds: 60 * (1 - // / (totalRTTimes / totalRTsCount))) <- semantically the number of + // / ((totalMeasurementTimes / totalMeasurements)))) <- semantically the number of // probes per minute. rpm := float64( time.Minute.Seconds(), - ) / (totalRTTimes / (float64(totalRTsCount))) - fmt.Printf("Total RTTs measured: %d\n", totalRTsCount) + ) / (totalMeasurementTimes / (float64(totalMeasurements))) + fmt.Printf("Total measurements: %d\n", totalMeasurements) fmt.Printf("RPM: %5.0f\n", rpm) } else { fmt.Printf("Error occurred calculating RPM -- no probe measurements received.\n") } + if *calculateExtendedStats { + fmt.Printf(extendedStats.Repr()) + } + cancelOperatingCtx() if *debugCliFlag { fmt.Printf("In debugging mode, we will cool down.\n") @@ -7,14 +7,238 @@ import ( "io" "net/http" "net/http/httptrace" + "os" "time" + "github.com/network-quality/goresponsiveness/constants" "github.com/network-quality/goresponsiveness/debug" + "github.com/network-quality/goresponsiveness/lgc" + "github.com/network-quality/goresponsiveness/ma" "github.com/network-quality/goresponsiveness/stats" "github.com/network-quality/goresponsiveness/traceable" "github.com/network-quality/goresponsiveness/utilities" ) +func addFlows( + ctx context.Context, + toAdd uint64, + lgcs *[]lgc.LoadGeneratingConnection, + lgcGenerator func() lgc.LoadGeneratingConnection, + debug debug.DebugLevel, +) { + for i := uint64(0); i < toAdd; i++ { + *lgcs = append(*lgcs, lgcGenerator()) + if !(*lgcs)[len(*lgcs)-1].Start(ctx, debug) { + fmt.Printf( + "Error starting lgc with id %d!\n", + (*lgcs)[len(*lgcs)-1].ClientId(), + ) + return + } + } +} + +type SaturationResult struct { + RateBps float64 + LGCs []lgc.LoadGeneratingConnection +} + +func Saturate( + saturationCtx context.Context, + operatingCtx context.Context, + lgcGenerator func() lgc.LoadGeneratingConnection, + debugging *debug.DebugWithPrefix, +) (saturated chan SaturationResult) { + saturated = make(chan SaturationResult) + go func() { + + lgcs := make([]lgc.LoadGeneratingConnection, 0) + + addFlows( + saturationCtx, + constants.StartingNumberOfLoadGeneratingConnections, + &lgcs, + lgcGenerator, + debugging.Level, + ) + + previousFlowIncreaseInterval := uint64(0) + previousMovingAverage := float64(0) + + // The moving average will contain the average for the last + // constants.MovingAverageIntervalCount throughputs. + // ie, ma[i] = (throughput[i-3] + throughput[i-2] + throughput[i-1] + throughput[i])/4 + movingAverage := ma.NewMovingAverage( + constants.MovingAverageIntervalCount, + ) + + // The moving average average will be the average of the last + // constants.MovingAverageIntervalCount moving averages. + // ie, maa[i] = (ma[i-3] + ma[i-2] + ma[i-1] + ma[i])/4 + movingAverageAverage := ma.NewMovingAverage( + constants.MovingAverageIntervalCount, + ) + + nextSampleStartTime := time.Now().Add(time.Second) + + for currentInterval := uint64(0); true; currentInterval++ { + + // When the program stops operating, then stop. + if saturationCtx.Err() != nil { + return + } + + // We may be asked to stop trying to saturate the + // network and return our current status. + if saturationCtx.Err() != nil { + //break + } + + now := time.Now() + // At each 1-second interval + if nextSampleStartTime.Sub(now) > 0 { + if debug.IsDebug(debugging.Level) { + fmt.Printf( + "%v: Sleeping until %v\n", + debugging, + nextSampleStartTime, + ) + } + time.Sleep(nextSampleStartTime.Sub(now)) + } else { + fmt.Fprintf(os.Stderr, "Warning: Missed a one-second deadline.\n") + } + nextSampleStartTime = time.Now().Add(time.Second) + + // Compute "instantaneous aggregate" goodput which is the number of + // bytes transferred within the last second. + var totalTransfer float64 = 0 + allInvalid := true + for i := range lgcs { + if !lgcs[i].IsValid() { + if debug.IsDebug(debugging.Level) { + fmt.Printf( + "%v: Load-generating connection with id %d is invalid ... skipping.\n", + debugging, + lgcs[i].ClientId(), + ) + } + continue + } + allInvalid = false + currentTransferred, currentInterval := lgcs[i].TransferredInInterval() + // normalize to a second-long interval! + instantaneousTransferred := float64(currentTransferred) / float64(currentInterval.Seconds()) + totalTransfer += instantaneousTransferred + } + + // For some reason, all the lgcs are invalid. This likely means that + // the network/server went away. + if allInvalid { + if debug.IsDebug(debugging.Level) { + fmt.Printf( + "%v: All lgcs were invalid. Assuming that network/server went away.\n", + debugging, + ) + } + break + } + + // Compute a moving average of the last + // constants.MovingAverageIntervalCount "instantaneous aggregate + // goodput" measurements + movingAverage.AddMeasurement(float64(totalTransfer)) + currentMovingAverage := movingAverage.CalculateAverage() + movingAverageAverage.AddMeasurement(currentMovingAverage) + movingAverageDelta := utilities.SignedPercentDifference( + currentMovingAverage, + previousMovingAverage, + ) + + if debug.IsDebug(debugging.Level) { + fmt.Printf( + "%v: Instantaneous goodput: %f MB.\n", + debugging, + utilities.ToMBps(float64(totalTransfer)), + ) + fmt.Printf( + "%v: Previous moving average: %f MB.\n", + debugging, + utilities.ToMBps(previousMovingAverage), + ) + fmt.Printf( + "%v: Current moving average: %f MB.\n", + debugging, + utilities.ToMBps(currentMovingAverage), + ) + fmt.Printf( + "%v: Moving average delta: %f.\n", + debugging, + movingAverageDelta, + ) + } + + previousMovingAverage = currentMovingAverage + + intervalsSinceLastFlowIncrease := currentInterval - previousFlowIncreaseInterval + + // Special case: We won't make any adjustments on the first + // iteration. + if currentInterval == 0 { + continue + } + + // If moving average > "previous" moving average + InstabilityDelta: + if movingAverageDelta > constants.InstabilityDelta { + // Network did not yet reach saturation. If no flows added + // within the last 4 seconds, add 4 more flows + if intervalsSinceLastFlowIncrease > constants.MovingAverageStabilitySpan { + if debug.IsDebug(debugging.Level) { + fmt.Printf( + "%v: Adding flows because we are unsaturated and waited a while.\n", + debugging, + ) + } + addFlows( + saturationCtx, + constants.AdditiveNumberOfLoadGeneratingConnections, + &lgcs, + lgcGenerator, + debugging.Level, + ) + previousFlowIncreaseInterval = currentInterval + } else { + if debug.IsDebug(debugging.Level) { + fmt.Printf("%v: We are unsaturated, but it still too early to add anything.\n", debugging) + } + } + } else { // Else, network reached saturation for the current flow count. + if debug.IsDebug(debugging.Level) { + fmt.Printf("%v: Network reached saturation with current flow count.\n", debugging) + } + // If new flows added and for 4 seconds the moving average + // throughput did not change: network reached stable saturation + if intervalsSinceLastFlowIncrease < constants.MovingAverageStabilitySpan && movingAverageAverage.AllSequentialIncreasesLessThan(constants.InstabilityDelta) { + if debug.IsDebug(debugging.Level) { + fmt.Printf("%v: New flows added within the last four seconds and the moving-average average is consistent!\n", debugging) + } + break + } else { + // Else, add four more flows + if debug.IsDebug(debugging.Level) { + fmt.Printf("%v: New flows to add to try to increase our saturation!\n", debugging) + } + addFlows(saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, lgcGenerator, debugging.Level) + previousFlowIncreaseInterval = currentInterval + } + } + + } + saturated <- SaturationResult{RateBps: movingAverage.CalculateAverage(), LGCs: lgcs} + }() + return +} + type Probe struct { client *http.Client stats *stats.TraceStats @@ -36,6 +260,9 @@ func (p *Probe) GetTrace() *httptrace.ClientTrace { } func (p *Probe) GetDnsDelta() time.Duration { + if p.stats.ConnectionReused { + return time.Duration(0) + } delta := p.stats.DnsDoneTime.Sub(p.stats.DnsStartTime) if debug.IsDebug(p.debug) { fmt.Printf("(Probe %v): DNS Time: %v\n", p.probeid, delta) @@ -44,6 +271,9 @@ func (p *Probe) GetDnsDelta() time.Duration { } func (p *Probe) GetTCPDelta() time.Duration { + if p.stats.ConnectionReused { + return time.Duration(0) + } delta := p.stats.ConnectDoneTime.Sub(p.stats.ConnectStartTime) if debug.IsDebug(p.debug) { fmt.Printf("(Probe %v): TCP Connection Time: %v\n", p.probeid, delta) @@ -70,7 +300,14 @@ func (p *Probe) GetTLSAndHttpHeaderDelta() time.Duration { // *and* the TLS handshake RTT, whether we can specifically measure the latter // or not. Eventually when TLS handshake tracing is fixed, we can break these // into separate buckets, but for now this workaround is reasonable. - delta := p.stats.HttpResponseReadyTime.Sub(p.stats.ConnectDoneTime) + before := p.stats.ConnectDoneTime + if p.stats.ConnectionReused { + // When we reuse a connection there will be no time logged for when the + // TCP connection was established (obviously). So, fall back to the time + // when we were notified about reusing a connection (as a close approximation!). + before = p.stats.GetConnectionDoneTime + } + delta := p.stats.HttpResponseReadyTime.Sub(before) if debug.IsDebug(p.debug) { fmt.Printf("(Probe %v): Http TLS and Header Time: %v\n", p.probeid, delta) } @@ -184,9 +421,15 @@ func (probe *Probe) SetGotConnTimeInfo( ) { probe.stats.GetConnectionDoneTime = now probe.stats.ConnInfo = gotConnInfo + probe.stats.ConnectionReused = gotConnInfo.Reused if debug.IsDebug(probe.debug) { + reusedString := "(new)" + if probe.stats.ConnectionReused { + reusedString = "(reused)" + } fmt.Printf( - "(Probe) Got connection for %v at %v with info %v\n", + "(Probe) Got %v connection for %v at %v with info %v\n", + reusedString, probe.ProbeId(), probe.stats.GetConnectionDoneTime, probe.stats.ConnInfo, @@ -252,91 +495,110 @@ func (probe *Probe) SetHttpResponseReadyTime( } } -func CalculateSequentialRTTsTime( +func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug.DebugLevel) utilities.MeasurementResult { + time_before_probe := time.Now() + probe_req, err := http.NewRequestWithContext( + httptrace.WithClientTrace(ctx, probe.GetTrace()), + "GET", + url, + nil, + ) + if err != nil { + return utilities.MeasurementResult{Delay: 0, MeasurementCount: 0, Err: err} + } + + probe_resp, err := probe.client.Do(probe_req) + if err != nil { + return utilities.MeasurementResult{Delay: 0, MeasurementCount: 0, Err: err} + } + + // TODO: Make this interruptable somehow by using _ctx_. + _, err = io.ReadAll(probe_resp.Body) + if err != nil { + return utilities.MeasurementResult{Delay: 0, Err: err} + } + time_after_probe := time.Now() + + // Depending on whether we think that Close() requires another RTT (via TCP), we + // may need to move this before/after capturing the after time. + probe_resp.Body.Close() + + sanity := time_after_probe.Sub(time_before_probe) + + tlsAndHttpHeaderDelta := probe.GetTLSAndHttpHeaderDelta() + httpDownloadDelta := probe.GetHttpDownloadDelta(time_after_probe) // Combined with above, constitutes 2 time measurements, per the Spec. + tcpDelta := probe.GetTCPDelta() // Constitutes 1 time measurement, per the Spec. + totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + tcpDelta + + // By default, assume that there was a reused connection which + // means that we only made 1 time measurement. + var measurementCount uint16 = 1 + if !probe.stats.ConnectionReused { + // If we did not reuse the connection, then we made three additional time measurements. + // See above for details on that calculation. + measurementCount = 3 + } + + if debug.IsDebug(debugLevel) { + fmt.Printf( + "(Probe %v) sanity vs total: %v vs %v\n", + probe.ProbeId(), + sanity, + totalDelay, + ) + } + return utilities.MeasurementResult{Delay: totalDelay, MeasurementCount: measurementCount, Err: nil} +} + +func CalculateProbeMeasurements( ctx context.Context, - saturated_rtt_probe *Probe, - new_rtt_probe *Probe, + strict bool, + saturated_measurement_probe *Probe, + unsaturated_measurement_probe *Probe, url string, debugLevel debug.DebugLevel, -) chan utilities.GetLatency { - responseChannel := make(chan utilities.GetLatency) +) chan utilities.MeasurementResult { + responseChannel := make(chan utilities.MeasurementResult) go func() { - before := time.Now() - roundTripCount := uint16(0) /* - TODO: We are not going to measure round-trip times on the load-generating connection - right now because we are dealing with a massive amount of buffer bloat on the - Apple CDN. + * Depending on whether the user wants their measurements to be strict, we will + * measure on the LGC. + */ + var saturated_probe_latency utilities.MeasurementResult + if strict { - TODO: When this functionality is enabled, we may need to change the assertion in - the GotConn callback in the Traceable interface in traceable.go because a connection - will be reused in that case. If such a situation does come to pass, we will want to - move that assertion in to the various Traceable interface implementations that continue - to rely on this assertion. + if debug.IsDebug(debugLevel) { + fmt.Printf("Beginning saturated measurement probe.\n") + } + saturated_latency := getLatency(ctx, saturated_measurement_probe, url, debugLevel) - c_a, err := saturated_client.Get(url) - if err != nil { - responseChannel <- GetLatency{Delay: 0, RTTs: 0, Err: err} - return - } - // TODO: Make this interruptable somehow - // by using _ctx_. - _, err = io.ReadAll(c_a.Body) - if err != nil { - responseChannel <- GetLatency{Delay: 0, RTTs: 0, Err: err} - return - } - roundTripCount += 5 - c_a.Body.Close() - */ - c_b_req, err := http.NewRequestWithContext( - httptrace.WithClientTrace(ctx, new_rtt_probe.GetTrace()), - "GET", - url, - nil, - ) - if err != nil { - responseChannel <- utilities.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} - return + if saturated_latency.Err != nil { + fmt.Printf("Error occurred getting the saturated measurement.\n") + responseChannel <- saturated_latency + return + } } - c_b, err := new_rtt_probe.client.Do(c_b_req) - if err != nil { - responseChannel <- utilities.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} - return + if debug.IsDebug(debugLevel) { + fmt.Printf("Beginning unsaturated measurement probe.\n") } + unsaturated_probe_latency := getLatency(ctx, unsaturated_measurement_probe, url, debugLevel) - // TODO: Make this interruptable somehow by using _ctx_. - _, err = io.ReadAll(c_b.Body) - if err != nil { - responseChannel <- utilities.GetLatency{Delay: 0, Err: err} + if unsaturated_probe_latency.Err != nil { + fmt.Printf("Error occurred getting the unsaturated measurement.\n") + responseChannel <- unsaturated_probe_latency return } - after := time.Now() - - // Depending on whether we think that Close() requires another RTT (via TCP), we - // may need to move this before/after capturing the after time. - c_b.Body.Close() - - sanity := after.Sub(before) - tlsAndHttpHeaderDelta := new_rtt_probe.GetTLSAndHttpHeaderDelta() // Constitutes 2 RTT, per the Spec. - httpDownloadDelta := new_rtt_probe.GetHttpDownloadDelta(after) // Constitutes 1 RTT, per the Spec. - dnsDelta := new_rtt_probe.GetDnsDelta() // Constitutes 1 RTT, per the Spec. - tcpDelta := new_rtt_probe.GetTCPDelta() // Constitutes 1 RTT, per the Spec. - totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + dnsDelta + tcpDelta + total_latency := unsaturated_probe_latency.Delay + total_measurement_count := unsaturated_probe_latency.MeasurementCount - if debug.IsDebug(debugLevel) { - fmt.Printf( - "(Probe %v) sanity vs total: %v vs %v\n", - new_rtt_probe.ProbeId(), - sanity, - totalDelay, - ) + if strict { + total_latency += saturated_probe_latency.Delay + total_measurement_count += saturated_probe_latency.MeasurementCount } - - roundTripCount += 5 // According to addition, there are 5 RTTs that we measured. - responseChannel <- utilities.GetLatency{Delay: totalDelay, RoundTripCount: roundTripCount, Err: nil} + responseChannel <- utilities.MeasurementResult{Delay: total_latency, MeasurementCount: total_measurement_count, Err: nil} + return }() return responseChannel } diff --git a/stats/stats.go b/stats/stats.go index a636326..f5ae4cb 100644 --- a/stats/stats.go +++ b/stats/stats.go @@ -22,6 +22,7 @@ type TraceStats struct { TLSDoneTime utilities.Optional[time.Time] ConnectStartTime time.Time ConnectDoneTime time.Time + ConnectionReused bool GetConnectionStartTime time.Time GetConnectionDoneTime time.Time HttpWroteRequestTime time.Time @@ -44,6 +45,7 @@ func (s *TraceStats) String() string { fmt.Sprintf("TLSDoneTime: %v\n", s.TLSDoneTime) + fmt.Sprintf("ConnectStartTime: %v\n", s.ConnectStartTime) + fmt.Sprintf("ConnectDoneTime: %v\n", s.ConnectDoneTime) + + fmt.Sprintf("ConnectionReused: %v\n", s.ConnectionReused) + fmt.Sprintf("GetConnectionStartTime: %v\n", s.GetConnectionStartTime) + fmt.Sprintf("GetConnectionDoneTime: %v\n", s.GetConnectionDoneTime) + fmt.Sprintf("HttpResponseReadyTime: %v\n", s.HttpResponseReadyTime) diff --git a/traceable/traceable.go b/traceable/traceable.go index 6efc7f7..0d9da21 100644 --- a/traceable/traceable.go +++ b/traceable/traceable.go @@ -42,9 +42,6 @@ func GenerateHttpTimingTracer( traceable.SetGetConnTime(time.Now()) }, GotConn: func(connInfo httptrace.GotConnInfo) { - if connInfo.Reused { - panic(!connInfo.Reused) - } traceable.SetGotConnTimeInfo(time.Now(), connInfo) }, TLSHandshakeStart: func() { diff --git a/utilities/utilities.go b/utilities/utilities.go index 160368b..76acbd2 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -17,6 +17,7 @@ package utilities import ( "fmt" "math" + "math/rand" "os" "reflect" "sync/atomic" @@ -32,7 +33,10 @@ func SignedPercentDifference( current float64, previous float64, ) (difference float64) { - return ((current - previous) / (float64(current+previous) / 2.0)) * float64( + //return ((current - previous) / (float64(current+previous) / 2.0)) * float64( + //100, + // ) + return ((current - previous) / previous) * float64( 100, ) } @@ -61,10 +65,10 @@ func ToMBps(bytes float64) float64 { return float64(bytes) / float64(1024*1024) } -type GetLatency struct { - Delay time.Duration - RoundTripCount uint16 - Err error +type MeasurementResult struct { + Delay time.Duration + MeasurementCount uint16 + Err error } func SeekForAppend(file *os.File) (err error) { @@ -114,3 +118,14 @@ func (optional Optional[S]) String() string { return "None" } } + +func RandBetween(max int) int { + return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max +} + +func Max(x, y uint64) uint64 { + if x > y { + return x + } + return y +} |
