summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--config/config.go134
-rw-r--r--constants/constants.go7
-rwxr-xr-xdata-analysis1/data.sh60
-rwxr-xr-xdata-analysis1/gather.sh14
-rw-r--r--data-analysis1/go.log.FriMay6121542EDT2022603
-rw-r--r--data-analysis1/nq.log.FriMay6121542EDT2022706
-rw-r--r--extendedstats/other.go22
-rw-r--r--extendedstats/unix.go72
-rw-r--r--go.mod5
-rw-r--r--go.sum2
-rw-r--r--lgc/lgc.go108
-rw-r--r--networkQuality.go476
-rw-r--r--rpm/rpm.go404
-rw-r--r--stats/stats.go2
-rw-r--r--traceable/traceable.go3
-rw-r--r--utilities/utilities.go25
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
+}
diff --git a/go.mod b/go.mod
index d60ef0a..39b9252 100644
--- a/go.mod
+++ b/go.mod
@@ -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
+)
diff --git a/go.sum b/go.sum
index 4832ce9..ce291cf 100644
--- a/go.sum
+++ b/go.sum
@@ -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=
diff --git a/lgc/lgc.go b/lgc/lgc.go
index a32bb36..fb51ec1 100644
--- a/lgc/lgc.go
+++ b/lgc/lgc.go
@@ -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")
diff --git a/rpm/rpm.go b/rpm/rpm.go
index e01e2e8..28496cd 100644
--- a/rpm/rpm.go
+++ b/rpm/rpm.go
@@ -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
+}