From 15f995e8860846588f585a8f062cea2cf57712d4 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Mon, 9 May 2022 09:52:38 -0400 Subject: [Data Analysis] First data analysis results The first set of raw data and a tool for munging it into csv files. The data look promising but there are a few things that we need to address. --- data-analysis1/data.sh | 60 +++ data-analysis1/go.log.FriMay6121542EDT2022 | 603 ++++++++++++++++++++++++ data-analysis1/nq.log.FriMay6121542EDT2022 | 706 +++++++++++++++++++++++++++++ 3 files changed, 1369 insertions(+) create mode 100755 data-analysis1/data.sh create mode 100644 data-analysis1/go.log.FriMay6121542EDT2022 create mode 100644 data-analysis1/nq.log.FriMay6121542EDT2022 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/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 .<1>, _NSURLErrorRelatedURLSessionTaskErrorKey=( + "LocalUploadTask .<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) -- cgit v1.2.3 From a754f1a93b45da3b2f51594ba1c2fc1b2eac0734 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Mon, 9 May 2022 09:56:21 -0400 Subject: [Data analysis] Script that generated those data --- data-analysis1/gather.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100755 data-analysis1/gather.sh 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 -- cgit v1.2.3 From e184c0808b980e81ee87791264a7fa030f52e962 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Wed, 11 May 2022 10:25:25 -0400 Subject: Refactor RPM calculations Refactor RPM calculations to make them more reusble. Enable (perhaps temporarily) probe calculations on the saturated connections. This change is to check whether this makes our RPM calculations match the ones generated by Apple's native client. --- lgc/lgc.go | 4 ++ rpm/rpm.go | 113 +++++++++++++++++++++++++++++-------------------- traceable/traceable.go | 3 -- 3 files changed, 72 insertions(+), 48 deletions(-) diff --git a/lgc/lgc.go b/lgc/lgc.go index a32bb36..1f6332d 100644 --- a/lgc/lgc.go +++ b/lgc/lgc.go @@ -126,6 +126,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) { diff --git a/rpm/rpm.go b/rpm/rpm.go index e01e2e8..40a7729 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -252,6 +252,55 @@ func (probe *Probe) SetHttpResponseReadyTime( } } +func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug.DebugLevel) utilities.GetLatency { + before := time.Now() + c_b_req, err := http.NewRequestWithContext( + httptrace.WithClientTrace(ctx, probe.GetTrace()), + "GET", + url, + nil, + ) + if err != nil { + return utilities.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} + } + + c_b, err := probe.client.Do(c_b_req) + if err != nil { + return utilities.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} + } + + // TODO: Make this interruptable somehow by using _ctx_. + _, err = io.ReadAll(c_b.Body) + if err != nil { + return utilities.GetLatency{Delay: 0, Err: err} + } + 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 := probe.GetTLSAndHttpHeaderDelta() // Constitutes 2 RTT, per the Spec. + httpDownloadDelta := probe.GetHttpDownloadDelta(after) // Constitutes 1 RTT, per the Spec. + dnsDelta := probe.GetDnsDelta() // Constitutes 1 RTT, per the Spec. + tcpDelta := probe.GetTCPDelta() // Constitutes 1 RTT, per the Spec. + totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + dnsDelta + tcpDelta + + if debug.IsDebug(debugLevel) { + fmt.Printf( + "(Probe %v) sanity vs total: %v vs %v\n", + probe.ProbeId(), + sanity, + totalDelay, + ) + } + + roundTripCount := uint16(5) // According to addition, there are 5 RTTs that we measured. + return utilities.GetLatency{Delay: totalDelay, RoundTripCount: roundTripCount, Err: nil} +} + func CalculateSequentialRTTsTime( ctx context.Context, saturated_rtt_probe *Probe, @@ -261,8 +310,17 @@ func CalculateSequentialRTTsTime( ) chan utilities.GetLatency { responseChannel := make(chan utilities.GetLatency) go func() { - before := time.Now() - roundTripCount := uint16(0) + + if debug.IsDebug(debugLevel) { + fmt.Printf("Beginning saturated RTT probe.\n") + } + saturated_latency := getLatency(ctx, saturated_rtt_probe, url, debugLevel) + + if saturated_latency.Err != nil { + fmt.Printf("Error occurred getting the saturated RTT.\n") + responseChannel <- saturated_latency + return + } /* 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 @@ -289,54 +347,19 @@ func CalculateSequentialRTTsTime( 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 - } - - 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 RTT probe.\n") } + new_rtt_latency := getLatency(ctx, new_rtt_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 new_rtt_latency.Err != nil { + fmt.Printf("Error occurred getting the unsaturated RTT.\n") + responseChannel <- new_rtt_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 - - if debug.IsDebug(debugLevel) { - fmt.Printf( - "(Probe %v) sanity vs total: %v vs %v\n", - new_rtt_probe.ProbeId(), - sanity, - totalDelay, - ) - } - roundTripCount += 5 // According to addition, there are 5 RTTs that we measured. - responseChannel <- utilities.GetLatency{Delay: totalDelay, RoundTripCount: roundTripCount, Err: nil} + responseChannel <- utilities.GetLatency{Delay: saturated_latency.Delay + new_rtt_latency.Delay, RoundTripCount: uint16(10), Err: nil} + return }() return responseChannel } 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() { -- cgit v1.2.3 From 49301ae7f6ef1c479fe3b23cba29d74a815d15ee Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Wed, 11 May 2022 14:35:26 -0400 Subject: [Bugfix] Support reused connections in calculating RPM There was an error in prior versions when calculating the RPM in the presence of reused connections because invalid time values were being compared. This patch fixes that error. --- rpm/rpm.go | 69 ++++++++++++++++++++++++++++++---------------------------- stats/stats.go | 2 ++ 2 files changed, 38 insertions(+), 33 deletions(-) diff --git a/rpm/rpm.go b/rpm/rpm.go index 40a7729..34501c8 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -36,6 +36,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 +47,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 +76,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 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 +197,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, @@ -288,6 +307,15 @@ func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug. tcpDelta := probe.GetTCPDelta() // Constitutes 1 RTT, per the Spec. totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + dnsDelta + tcpDelta + // By default, assume that there was a reused connection which + // means that we only made 2 round trips. + roundTripCount := uint16(2) + if !probe.stats.ConnectionReused { + // If we did not reuse the connection, then we made three additional RTTs -- one for the DNS, + // one for the TCP, one for the TLS. + roundTripCount = 5 + } + if debug.IsDebug(debugLevel) { fmt.Printf( "(Probe %v) sanity vs total: %v vs %v\n", @@ -296,8 +324,6 @@ func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug. totalDelay, ) } - - roundTripCount := uint16(5) // According to addition, there are 5 RTTs that we measured. return utilities.GetLatency{Delay: totalDelay, RoundTripCount: roundTripCount, Err: nil} } @@ -310,7 +336,11 @@ func CalculateSequentialRTTsTime( ) chan utilities.GetLatency { responseChannel := make(chan utilities.GetLatency) go func() { - + /* + TODO: We *are* measuring round-trip times on the load-generating connection + right now. However, it is not clear if Apple is doing the same in their native + client. We will have to adjust based on that. + */ if debug.IsDebug(debugLevel) { fmt.Printf("Beginning saturated RTT probe.\n") } @@ -321,32 +351,6 @@ func CalculateSequentialRTTsTime( responseChannel <- saturated_latency return } - /* - 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. - - 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. - - 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() - */ if debug.IsDebug(debugLevel) { fmt.Printf("Beginning unsaturated RTT probe.\n") } @@ -357,8 +361,7 @@ func CalculateSequentialRTTsTime( responseChannel <- new_rtt_latency return } - - responseChannel <- utilities.GetLatency{Delay: saturated_latency.Delay + new_rtt_latency.Delay, RoundTripCount: uint16(10), Err: nil} + responseChannel <- utilities.GetLatency{Delay: saturated_latency.Delay + new_rtt_latency.Delay, RoundTripCount: saturated_latency.RoundTripCount + new_rtt_latency.RoundTripCount, 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) -- cgit v1.2.3 From fdfe96b53ef8f4532e5b6f65f86ba39fe242cc5b Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Wed, 11 May 2022 16:49:09 -0400 Subject: [Refactor/Bugfix] Refactor RPM calculation and fix calculation algorithm As it turns out, I was misreading the algorithm for calculating the RPM based upon the measurements taken during execution. This patch fixes that mistake and also (starts) renames "RTT" as "measurement" (those are technically a better nomenclature according to the spec.) --- constants/constants.go | 3 ++ networkQuality.go | 9 ++++-- rpm/rpm.go | 86 +++++++++++++++++++++++++++++--------------------- utilities/utilities.go | 8 ++--- 4 files changed, 64 insertions(+), 42 deletions(-) diff --git a/constants/constants.go b/constants/constants.go index 1a060dd..2f906b6 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -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/networkQuality.go b/networkQuality.go index 6b80a7e..2aba054 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -64,6 +64,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, @@ -680,7 +685,7 @@ func main() { { rttTimeout = true } - case sequentialRTTimes := <-rpm.CalculateSequentialRTTsTime(operatingCtx, saturatedRTTProbe, newRTTProbe, config.Urls.SmallUrl, debugLevel): + case sequentialRTTimes := <-rpm.CalculateProbeMeasurements(operatingCtx, *strictFlag, saturatedRTTProbe, newRTTProbe, config.Urls.SmallUrl, debugLevel): { if sequentialRTTimes.Err != nil { fmt.Printf( @@ -694,7 +699,7 @@ func main() { fmt.Printf("rttProbe: %v\n", newRTTProbe) } // We know that we have a good Sequential RTT. - totalRTsCount += uint64(sequentialRTTimes.RoundTripCount) + totalRTsCount += uint64(sequentialRTTimes.MeasurementCount) totalRTTimes += sequentialRTTimes.Delay.Seconds() if debug.IsDebug(debugLevel) { fmt.Printf( diff --git a/rpm/rpm.go b/rpm/rpm.go index 34501c8..f41ad92 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -271,49 +271,49 @@ func (probe *Probe) SetHttpResponseReadyTime( } } -func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug.DebugLevel) utilities.GetLatency { - before := time.Now() - c_b_req, err := http.NewRequestWithContext( +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.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} + return utilities.MeasurementResult{Delay: 0, MeasurementCount: 0, Err: err} } - c_b, err := probe.client.Do(c_b_req) + probe_resp, err := probe.client.Do(probe_req) if err != nil { - return utilities.GetLatency{Delay: 0, RoundTripCount: 0, Err: err} + return utilities.MeasurementResult{Delay: 0, MeasurementCount: 0, Err: err} } // TODO: Make this interruptable somehow by using _ctx_. - _, err = io.ReadAll(c_b.Body) + _, err = io.ReadAll(probe_resp.Body) if err != nil { - return utilities.GetLatency{Delay: 0, Err: err} + return utilities.MeasurementResult{Delay: 0, Err: err} } - after := time.Now() + 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. - c_b.Body.Close() + probe_resp.Body.Close() - sanity := after.Sub(before) + sanity := time_after_probe.Sub(time_before_probe) - tlsAndHttpHeaderDelta := probe.GetTLSAndHttpHeaderDelta() // Constitutes 2 RTT, per the Spec. - httpDownloadDelta := probe.GetHttpDownloadDelta(after) // Constitutes 1 RTT, per the Spec. - dnsDelta := probe.GetDnsDelta() // Constitutes 1 RTT, per the Spec. - tcpDelta := probe.GetTCPDelta() // Constitutes 1 RTT, per the Spec. + tlsAndHttpHeaderDelta := probe.GetTLSAndHttpHeaderDelta() + httpDownloadDelta := probe.GetHttpDownloadDelta(time_after_probe) // Combined with above, constitutes 2 time measurements, per the Spec. + dnsDelta := probe.GetDnsDelta() // Constitutes 1 time measurement, per the Spec. + tcpDelta := probe.GetTCPDelta() // Constitutes 1 time measurement, per the Spec. totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + dnsDelta + tcpDelta // By default, assume that there was a reused connection which - // means that we only made 2 round trips. - roundTripCount := uint16(2) + // 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 RTTs -- one for the DNS, - // one for the TCP, one for the TLS. - roundTripCount = 5 + // If we did not reuse the connection, then we made three additional time measurements. + // See above for details on that calculation. + measurementCount = 4 } if debug.IsDebug(debugLevel) { @@ -324,44 +324,58 @@ func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug. totalDelay, ) } - return utilities.GetLatency{Delay: totalDelay, RoundTripCount: roundTripCount, Err: nil} + return utilities.MeasurementResult{Delay: totalDelay, MeasurementCount: measurementCount, Err: nil} } -func CalculateSequentialRTTsTime( +func CalculateProbeMeasurements( ctx context.Context, - saturated_rtt_probe *Probe, - new_rtt_probe *Probe, + strict bool, + saturated_measurement_probe *Probe, + new_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() { /* TODO: We *are* measuring round-trip times on the load-generating connection right now. However, it is not clear if Apple is doing the same in their native client. We will have to adjust based on that. */ - if debug.IsDebug(debugLevel) { - fmt.Printf("Beginning saturated RTT probe.\n") + var saturated_latency utilities.MeasurementResult + if strict { + + if debug.IsDebug(debugLevel) { + fmt.Printf("Beginning saturated RTT probe.\n") + } + saturated_latency := getLatency(ctx, saturated_measurement_probe, url, debugLevel) + + if saturated_latency.Err != nil { + fmt.Printf("Error occurred getting the saturated RTT.\n") + responseChannel <- saturated_latency + return + } } - saturated_latency := getLatency(ctx, saturated_rtt_probe, url, debugLevel) - if saturated_latency.Err != nil { - fmt.Printf("Error occurred getting the saturated RTT.\n") - responseChannel <- saturated_latency - return - } if debug.IsDebug(debugLevel) { fmt.Printf("Beginning unsaturated RTT probe.\n") } - new_rtt_latency := getLatency(ctx, new_rtt_probe, url, debugLevel) + new_rtt_latency := getLatency(ctx, new_measurement_probe, url, debugLevel) if new_rtt_latency.Err != nil { fmt.Printf("Error occurred getting the unsaturated RTT.\n") responseChannel <- new_rtt_latency return } - responseChannel <- utilities.GetLatency{Delay: saturated_latency.Delay + new_rtt_latency.Delay, RoundTripCount: saturated_latency.RoundTripCount + new_rtt_latency.RoundTripCount, Err: nil} + + total_delay := new_rtt_latency.Delay + total_measurement_count := new_rtt_latency.MeasurementCount + + if strict { + total_delay += saturated_latency.Delay + total_measurement_count += saturated_latency.MeasurementCount + } + responseChannel <- utilities.MeasurementResult{Delay: total_delay, MeasurementCount: total_measurement_count, Err: nil} return }() return responseChannel diff --git a/utilities/utilities.go b/utilities/utilities.go index 160368b..b1b180f 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -61,10 +61,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) { -- cgit v1.2.3 From e6cd1fedf2522e58a38a51eaa676f59094da8249 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Thu, 12 May 2022 15:43:41 -0400 Subject: [Functionality] Change definition of percent change Switch from calculating "difference" as percent difference to calculating the difference as percent change. --- utilities/utilities.go | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/utilities/utilities.go b/utilities/utilities.go index b1b180f..4b114ba 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -32,7 +32,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, ) } -- cgit v1.2.3 From f0dcb55643612ab05137314b46ee66ccf9308a53 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Thu, 12 May 2022 15:45:40 -0400 Subject: [Functionality] Match Apple's Client RPM Calcuation -- Remove DNS Per a (to-be-released) update from the spec, the time for a DNS lookup is no longer considered to make up a portion of the RPM. --- rpm/rpm.go | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/rpm/rpm.go b/rpm/rpm.go index f41ad92..a349cee 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -303,9 +303,8 @@ func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug. tlsAndHttpHeaderDelta := probe.GetTLSAndHttpHeaderDelta() httpDownloadDelta := probe.GetHttpDownloadDelta(time_after_probe) // Combined with above, constitutes 2 time measurements, per the Spec. - dnsDelta := probe.GetDnsDelta() // Constitutes 1 time measurement, per the Spec. tcpDelta := probe.GetTCPDelta() // Constitutes 1 time measurement, per the Spec. - totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + dnsDelta + tcpDelta + totalDelay := tlsAndHttpHeaderDelta + httpDownloadDelta + tcpDelta // By default, assume that there was a reused connection which // means that we only made 1 time measurement. @@ -313,7 +312,7 @@ func getLatency(ctx context.Context, probe *Probe, url string, debugLevel debug. 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 = 4 + measurementCount = 3 } if debug.IsDebug(debugLevel) { -- cgit v1.2.3 From 89f26501e59095e1e6ac59cf158f6305e4e93389 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Fri, 13 May 2022 11:02:09 -0400 Subject: [Refactor] Create config package and package-ify saturate() 1. Create a separate package to handle the config information. 2. Move the saturate functionality into the rpm package. 3. Do general renaming/refactoring so that we are consistently saying measurement and not RTT (this nomenclature is more consistent with the standard). --- config/config.go | 134 +++++++++++++++ constants/constants.go | 2 +- networkQuality.go | 443 ++++++------------------------------------------- rpm/rpm.go | 221 ++++++++++++++++++++++++ utilities/utilities.go | 5 + 5 files changed, 412 insertions(+), 393 deletions(-) create mode 100644 config/config.go 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 2f906b6..147b643 100644 --- a/constants/constants.go +++ b/constants/constants.go @@ -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 diff --git a/networkQuality.go b/networkQuality.go index 2aba054..ab9517e 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -17,25 +17,20 @@ 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/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" @@ -86,343 +81,6 @@ var ( ) ) -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 -} - -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() @@ -433,7 +91,7 @@ func main() { saturationCtx, cancelSaturationCtx := context.WithCancel( context.Background(), ) - config := &Config{} + config := &config.Config{} var debugLevel debug.DebugLevel = debug.Error if *debugCliFlag { @@ -508,6 +166,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, @@ -524,13 +186,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, @@ -540,8 +202,8 @@ func main() { saturationTimeout := false uploadSaturated := false downloadSaturated := false - downloadSaturation := SaturationResult{} - uploadSaturation := SaturationResult{} + downloadSaturation := rpm.SaturationResult{} + uploadSaturation := rpm.SaturationResult{} for !(uploadSaturated && downloadSaturated) { select { @@ -557,7 +219,7 @@ func main() { "", ), utilities.ToMBps(downloadSaturation.RateBps), - len(downloadSaturation.lgcs), + len(downloadSaturation.LGCs), ) } } @@ -573,7 +235,7 @@ func main() { "", ), utilities.ToMBps(uploadSaturation.RateBps), - len(uploadSaturation.lgcs), + len(uploadSaturation.LGCs), ) } } @@ -585,7 +247,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 { @@ -629,25 +291,21 @@ func main() { ) } - totalRTsCount := uint64(0) - totalRTTimes := float64(0) - rttTimeout := false + totalMeasurements := uint64(0) + totalMeasurementTimes := float64(0) + measurementTimeout := false - for i := 0; i < constants.RPMProbeCount && !rttTimeout; i++ { - if len(downloadSaturation.lgcs) == 0 { + 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(), ) } @@ -657,7 +315,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 @@ -665,46 +323,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.CalculateProbeMeasurements(operatingCtx, *strictFlag, 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.MeasurementCount) - 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, ) } } @@ -715,31 +374,31 @@ 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") diff --git a/rpm/rpm.go b/rpm/rpm.go index a349cee..8f431b6 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -7,14 +7,235 @@ 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, + 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 +} + type Probe struct { client *http.Client stats *stats.TraceStats diff --git a/utilities/utilities.go b/utilities/utilities.go index 4b114ba..a143d31 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -17,6 +17,7 @@ package utilities import ( "fmt" "math" + "math/rand" "os" "reflect" "sync/atomic" @@ -117,3 +118,7 @@ func (optional Optional[S]) String() string { return "None" } } + +func RandBetween(max int) int { + return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max +} -- cgit v1.2.3 From 39e17236e4f759fdfa26660c9476528c82556faa Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Fri, 13 May 2022 19:50:05 -0400 Subject: [Refactor] Additional (general) refactoring. --- constants/constants.go | 2 +- rpm/rpm.go | 57 +++++++++++++++++++++++++++++--------------------- 2 files changed, 34 insertions(+), 25 deletions(-) diff --git a/constants/constants.go b/constants/constants.go index 147b643..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. diff --git a/rpm/rpm.go b/rpm/rpm.go index 8f431b6..8956509 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -66,18 +66,26 @@ func Saturate( debugging.Level, ) - previousFlowIncreaseIteration := uint64(0) + 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 currentIteration := uint64(0); true; currentIteration++ { + for currentInterval := uint64(0); true; currentInterval++ { // When the program stops operating, then stop. if saturationCtx.Err() != nil { @@ -124,7 +132,8 @@ func Saturate( allInvalid = false previousTransferred := lgcsPreviousTransferred[i] currentTransferred := lgcs[i].Transferred() - totalTransfer += (currentTransferred - previousTransferred) + instantaneousTransferred := currentTransferred - previousTransferred + totalTransfer += instantaneousTransferred lgcsPreviousTransferred[i] = currentTransferred } @@ -176,9 +185,11 @@ func Saturate( previousMovingAverage = currentMovingAverage + intervalsSinceLastFlowIncrease := currentInterval - previousFlowIncreaseInterval + // Special case: We won't make any adjustments on the first // iteration. - if currentIteration == 0 { + if currentInterval == 0 { continue } @@ -186,9 +197,7 @@ func Saturate( 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 intervalsSinceLastFlowIncrease > constants.MovingAverageStabilitySpan { if debug.IsDebug(debugging.Level) { fmt.Printf( "%v: Adding flows because we are unsaturated and waited a while.\n", @@ -203,7 +212,7 @@ func Saturate( lgcGenerator, debugging.Level, ) - previousFlowIncreaseIteration = currentIteration + previousFlowIncreaseInterval = currentInterval } else { if debug.IsDebug(debugging.Level) { fmt.Printf("%v: We are unsaturated, but it still too early to add anything.\n", debugging) @@ -215,7 +224,7 @@ func Saturate( } // 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 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) } @@ -226,7 +235,7 @@ func Saturate( 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 + previousFlowIncreaseInterval = currentInterval } } @@ -551,7 +560,7 @@ func CalculateProbeMeasurements( ctx context.Context, strict bool, saturated_measurement_probe *Probe, - new_measurement_probe *Probe, + unsaturated_measurement_probe *Probe, url string, debugLevel debug.DebugLevel, ) chan utilities.MeasurementResult { @@ -562,40 +571,40 @@ func CalculateProbeMeasurements( right now. However, it is not clear if Apple is doing the same in their native client. We will have to adjust based on that. */ - var saturated_latency utilities.MeasurementResult + var saturated_probe_latency utilities.MeasurementResult if strict { if debug.IsDebug(debugLevel) { - fmt.Printf("Beginning saturated RTT probe.\n") + fmt.Printf("Beginning saturated measurement probe.\n") } saturated_latency := getLatency(ctx, saturated_measurement_probe, url, debugLevel) if saturated_latency.Err != nil { - fmt.Printf("Error occurred getting the saturated RTT.\n") + fmt.Printf("Error occurred getting the saturated measurement.\n") responseChannel <- saturated_latency return } } if debug.IsDebug(debugLevel) { - fmt.Printf("Beginning unsaturated RTT probe.\n") + fmt.Printf("Beginning unsaturated measurement probe.\n") } - new_rtt_latency := getLatency(ctx, new_measurement_probe, url, debugLevel) + unsaturated_probe_latency := getLatency(ctx, unsaturated_measurement_probe, url, debugLevel) - if new_rtt_latency.Err != nil { - fmt.Printf("Error occurred getting the unsaturated RTT.\n") - responseChannel <- new_rtt_latency + if unsaturated_probe_latency.Err != nil { + fmt.Printf("Error occurred getting the unsaturated measurement.\n") + responseChannel <- unsaturated_probe_latency return } - total_delay := new_rtt_latency.Delay - total_measurement_count := new_rtt_latency.MeasurementCount + total_latency := unsaturated_probe_latency.Delay + total_measurement_count := unsaturated_probe_latency.MeasurementCount if strict { - total_delay += saturated_latency.Delay - total_measurement_count += saturated_latency.MeasurementCount + total_latency += saturated_probe_latency.Delay + total_measurement_count += saturated_probe_latency.MeasurementCount } - responseChannel <- utilities.MeasurementResult{Delay: total_delay, MeasurementCount: total_measurement_count, Err: nil} + responseChannel <- utilities.MeasurementResult{Delay: total_latency, MeasurementCount: total_measurement_count, Err: nil} return }() return responseChannel -- cgit v1.2.3 From 140c64907408d1cf998f1616d6aec4bc2904ce95 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Fri, 13 May 2022 23:49:56 -0400 Subject: [Improvement] Increase granularity of transfer rate calculation Previously the code relied on the fact that the go runtime would wake up the saturation go function at exactly 1 second intervals, as we asked. With this change, the code takes into account any minor fluctuations in that time when calculating the throughput in an interval. I hope that this change is an improvement. --- lgc/lgc.go | 70 +++++++++++++++++++++++++++++++++++++++----------------------- rpm/rpm.go | 16 +++++--------- 2 files changed, 49 insertions(+), 37 deletions(-) diff --git a/lgc/lgc.go b/lgc/lgc.go index 1f6332d..59b623d 100644 --- a/lgc/lgc.go +++ b/lgc/lgc.go @@ -34,22 +34,25 @@ import ( type LoadGeneratingConnection interface { Start(context.Context, debug.DebugLevel) bool - Transferred() uint64 + TransferredInInterval() (uint64, time.Duration) Client() *http.Client IsValid() bool ClientId() uint64 } 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 + Path string + downloaded uint64 + downloadStartTime time.Time + lastDownloaded uint64 + lastIntervalEnd int64 + client *http.Client + debug debug.DebugLevel + valid bool + KeyLogger io.Writer + clientId uint64 + tracer *httptrace.ClientTrace + stats stats.TraceStats } func (lgd *LoadGeneratingConnectionDownload) SetDnsStartTimeInfo( @@ -204,12 +207,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 { @@ -291,6 +297,9 @@ func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { return } + lbd.downloadStartTime = time.Now() + lbd.lastIntervalEnd = 0 + if get, err = lbd.client.Do(request); err != nil { lbd.valid = false return @@ -304,25 +313,31 @@ func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { } type LoadGeneratingConnectionUpload struct { - Path string - uploaded uint64 - client *http.Client - debug debug.DebugLevel - valid bool - KeyLogger io.Writer - clientId uint64 + Path string + uploaded uint64 + uploadStartTime time.Time + lastUploaded uint64 + lastIntervalEnd int64 + 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 { @@ -355,6 +370,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 diff --git a/rpm/rpm.go b/rpm/rpm.go index 8956509..3425566 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -23,13 +23,11 @@ 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", @@ -55,13 +53,11 @@ func Saturate( go func() { lgcs := make([]lgc.LoadGeneratingConnection, 0) - lgcsPreviousTransferred := make([]uint64, 0) addFlows( saturationCtx, constants.StartingNumberOfLoadGeneratingConnections, &lgcs, - &lgcsPreviousTransferred, lgcGenerator, debugging.Level, ) @@ -116,7 +112,7 @@ func Saturate( // Compute "instantaneous aggregate" goodput which is the number of // bytes transferred within the last second. - totalTransfer := uint64(0) + var totalTransfer float64 = 0 allInvalid := true for i := range lgcs { if !lgcs[i].IsValid() { @@ -130,11 +126,10 @@ func Saturate( continue } allInvalid = false - previousTransferred := lgcsPreviousTransferred[i] - currentTransferred := lgcs[i].Transferred() - instantaneousTransferred := currentTransferred - previousTransferred + currentTransferred, currentInterval := lgcs[i].TransferredInInterval() + // normalize to a second-long interval! + instantaneousTransferred := float64(currentTransferred) / float64(currentInterval.Seconds()) totalTransfer += instantaneousTransferred - lgcsPreviousTransferred[i] = currentTransferred } // For some reason, all the lgcs are invalid. This likely means that @@ -208,7 +203,6 @@ func Saturate( saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, - &lgcsPreviousTransferred, lgcGenerator, debugging.Level, ) @@ -234,7 +228,7 @@ func Saturate( 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) + addFlows(saturationCtx, constants.AdditiveNumberOfLoadGeneratingConnections, &lgcs, lgcGenerator, debugging.Level) previousFlowIncreaseInterval = currentInterval } } -- cgit v1.2.3 From eb8f1e7826c375b1ad8ea16e842451677d74df11 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Tue, 17 May 2022 16:53:27 -0400 Subject: [Comments] Fix a few comments 1. A misleading comment was corrected. 2. A typo was fixed. --- rpm/rpm.go | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/rpm/rpm.go b/rpm/rpm.go index 3425566..28496cd 100644 --- a/rpm/rpm.go +++ b/rpm/rpm.go @@ -304,7 +304,7 @@ func (p *Probe) GetTLSAndHttpHeaderDelta() time.Duration { 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 were notified about reusing a connection (as a close approximation!). + // when we were notified about reusing a connection (as a close approximation!). before = p.stats.GetConnectionDoneTime } delta := p.stats.HttpResponseReadyTime.Sub(before) @@ -561,10 +561,9 @@ func CalculateProbeMeasurements( responseChannel := make(chan utilities.MeasurementResult) go func() { /* - TODO: We *are* measuring round-trip times on the load-generating connection - right now. However, it is not clear if Apple is doing the same in their native - client. We will have to adjust based on that. - */ + * 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 { -- cgit v1.2.3 From d38bea818a90a0ca2bfc17e96c00b9896e2c61ca Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Sat, 4 Jun 2022 04:02:07 -0400 Subject: [Bugfix #21] Bad alignment of elements in structs accessed atomically Fixes #21 --- lgc/lgc.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/lgc/lgc.go b/lgc/lgc.go index 59b623d..13f2c06 100644 --- a/lgc/lgc.go +++ b/lgc/lgc.go @@ -40,12 +40,14 @@ type LoadGeneratingConnection interface { ClientId() uint64 } +// TODO: All 64-bit fields that are accessed atomically must +// appear at the top of this struct. type LoadGeneratingConnectionDownload struct { - Path string downloaded uint64 + lastIntervalEnd int64 + Path string downloadStartTime time.Time lastDownloaded uint64 - lastIntervalEnd int64 client *http.Client debug debug.DebugLevel valid bool @@ -312,12 +314,14 @@ func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { } } +// TODO: All 64-bit fields that are accessed atomically must +// appear at the top of this struct. type LoadGeneratingConnectionUpload struct { - Path string uploaded uint64 + lastIntervalEnd int64 + Path string uploadStartTime time.Time lastUploaded uint64 - lastIntervalEnd int64 client *http.Client debug debug.DebugLevel valid bool -- cgit v1.2.3 From de7a7bf994a020049eca89098aab9d13ff81f361 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Sat, 4 Jun 2022 05:49:07 -0400 Subject: [Feature] Access TCP_INFO about underlying TCP connections This will only work on *nix systems. Code that displays information in this PR is only exemplary -- I am sure that there are better places in the code to display it! --- go.mod | 5 ++++- go.sum | 2 ++ lgc/lgc.go | 9 +++++++++ networkQuality.go | 19 ++++++++++++++++++ utilities/utilities.go | 54 ++++++++++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 88 insertions(+), 1 deletion(-) 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 13f2c06..5b35fd1 100644 --- a/lgc/lgc.go +++ b/lgc/lgc.go @@ -38,6 +38,7 @@ type LoadGeneratingConnection interface { Client() *http.Client IsValid() bool ClientId() uint64 + Stats() *stats.TraceStats } // TODO: All 64-bit fields that are accessed atomically must @@ -284,6 +285,10 @@ func (lbd *LoadGeneratingConnectionDownload) IsValid() bool { return lbd.valid } +func (lbd *LoadGeneratingConnectionDownload) Stats() *stats.TraceStats { + return &lbd.stats +} + func (lbd *LoadGeneratingConnectionDownload) doDownload(ctx context.Context) { var request *http.Request = nil var get *http.Response = nil @@ -420,3 +425,7 @@ func (lgu *LoadGeneratingConnectionUpload) Start( go lgu.doUpload(ctx) return true } + +func (lbd *LoadGeneratingConnectionUpload) Stats() *stats.TraceStats { + return nil +} diff --git a/networkQuality.go b/networkQuality.go index ab9517e..7593714 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -21,6 +21,7 @@ import ( "fmt" _ "io" _ "log" + "net" "net/http" "os" "runtime/pprof" @@ -323,6 +324,24 @@ func main() { continue } + if *debugCliFlag { + // Note: This code is just an example of how to use utilities.GetTCPInfo. + rawConn := downloadSaturation.LGCs[randomLGCsIndex].Stats().ConnInfo.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 := utilities.GetTCPInfo(tcpConn); err != nil { + fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err) + } else { + utilities.PrintTCPInfo(info) + } + } + unsaturatedMeasurementTransport := http2.Transport{} unsaturatedMeasurementTransport.TLSClientConfig = &tls.Config{} if sslKeyFileConcurrentWriter != nil { diff --git a/utilities/utilities.go b/utilities/utilities.go index a143d31..e4c8a0d 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -18,10 +18,13 @@ import ( "fmt" "math" "math/rand" + "net" "os" "reflect" "sync/atomic" "time" + + "golang.org/x/sys/unix" ) func IsInterfaceNil(ifc interface{}) bool { @@ -122,3 +125,54 @@ func (optional Optional[S]) String() string { func RandBetween(max int) int { return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max } + +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 +} + +func PrintTCPInfo(info *unix.TCPInfo) { + fmt.Printf("TCPInfo: \n") + fmt.Printf(" State: %v\n", info.State) + fmt.Printf(" Ca_state: %v\n", info.Ca_state) + fmt.Printf(" Retransmits: %v\n", info.Retransmits) + fmt.Printf(" Probes: %v\n", info.Probes) + fmt.Printf(" Backoff: %v\n", info.Backoff) + fmt.Printf(" Options: %v\n", info.Options) + fmt.Printf(" Rto: %v\n", info.Rto) + fmt.Printf(" Ato: %v\n", info.Ato) + fmt.Printf(" Snd_mss: %v\n", info.Snd_mss) + fmt.Printf(" Rcv_mss: %v\n", info.Rcv_mss) + fmt.Printf(" Unacked: %v\n", info.Unacked) + fmt.Printf(" Sacked: %v\n", info.Sacked) + fmt.Printf(" Lost: %v\n", info.Lost) + fmt.Printf(" Retrans: %v\n", info.Retrans) + fmt.Printf(" Fackets: %v\n", info.Fackets) + fmt.Printf(" Last_data_sent: %v\n", info.Last_data_sent) + fmt.Printf(" Last_ack_sent: %v\n", info.Last_ack_sent) + fmt.Printf(" Last_data_recv: %v\n", info.Last_data_recv) + fmt.Printf(" Last_ack_recv: %v\n", info.Last_ack_recv) + fmt.Printf(" Pmtu: %v\n", info.Pmtu) + fmt.Printf(" Rcv_ssthresh: %v\n", info.Rcv_ssthresh) + fmt.Printf(" Rtt: %v\n", info.Rtt) + fmt.Printf(" Rttvar: %v\n", info.Rttvar) + fmt.Printf(" Snd_ssthresh: %v\n", info.Snd_ssthresh) + fmt.Printf(" Snd_cwnd: %v\n", info.Snd_cwnd) + fmt.Printf(" Advmss: %v\n", info.Advmss) + fmt.Printf(" Reordering: %v\n", info.Reordering) + fmt.Printf(" Rcv_rtt: %v\n", info.Rcv_rtt) + fmt.Printf(" Rcv_space: %v\n", info.Rcv_space) + fmt.Printf(" Total_retrans: %v\n", info.Total_retrans) +} -- cgit v1.2.3 From 9be87fa5ec89c9e393c9c93b3cb36668c71593d6 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Sat, 4 Jun 2022 21:24:19 -0400 Subject: [Feature] Add conditional compilation support for GetTCPInfo Now there is functionality for conditionally supporting GetTCPInfo depending on the platform. If the platform supports it, then the client can call utilities.GetTCPInfo. In the case that the platform does not support the GetTCPInfo function call, the result is an error of the type `NotImplemented`. --- lgc/lgc.go | 31 ++++++++++++----------- networkQuality.go | 7 +++++- utilities/tcpinfo_other.go | 18 ++++++++++++++ utilities/tcpinfo_unix.go | 62 ++++++++++++++++++++++++++++++++++++++++++++++ utilities/utilities.go | 56 ++++------------------------------------- 5 files changed, 107 insertions(+), 67 deletions(-) create mode 100644 utilities/tcpinfo_other.go create mode 100644 utilities/tcpinfo_unix.go diff --git a/lgc/lgc.go b/lgc/lgc.go index 5b35fd1..fb51ec1 100644 --- a/lgc/lgc.go +++ b/lgc/lgc.go @@ -281,40 +281,40 @@ 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 (lbd *LoadGeneratingConnectionDownload) Stats() *stats.TraceStats { - return &lbd.stats +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 } - lbd.downloadStartTime = time.Now() - lbd.lastIntervalEnd = 0 + lgd.downloadStartTime = time.Now() + lgd.lastIntervalEnd = 0 - if get, err = lbd.client.Do(request); err != nil { - lbd.valid = false + 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") } } @@ -426,6 +426,7 @@ func (lgu *LoadGeneratingConnectionUpload) Start( return true } -func (lbd *LoadGeneratingConnectionUpload) Stats() *stats.TraceStats { +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 7593714..d9bdc94 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -336,7 +336,12 @@ func main() { fmt.Printf("OOPS: Could not get the TCP info for the connection (not a TCP connection)!\n") } if info, err := utilities.GetTCPInfo(tcpConn); err != nil { - fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err) + switch err.(type) { + case *utilities.NotImplemented: + fmt.Printf("GetTCPInfo not implemented on this platform.\n") + default: + fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err) + } } else { utilities.PrintTCPInfo(info) } diff --git a/utilities/tcpinfo_other.go b/utilities/tcpinfo_other.go new file mode 100644 index 0000000..8dd070b --- /dev/null +++ b/utilities/tcpinfo_other.go @@ -0,0 +1,18 @@ +//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd +// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd + +package utilities + +import ( + "net" + + "golang.org/x/sys/unix" +) + +func GetTCPInfo(connection net.Conn) (*unix.TCPInfo, error) { + return nil, NotImplemented{Functionality: "GetTCPInfo"} +} + +func PrintTCPInfo(info *unix.TCPInfo) { + return +} diff --git a/utilities/tcpinfo_unix.go b/utilities/tcpinfo_unix.go new file mode 100644 index 0000000..b0b5252 --- /dev/null +++ b/utilities/tcpinfo_unix.go @@ -0,0 +1,62 @@ +//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd +// +build darwin dragonfly freebsd linux netbsd openbsd + +package utilities + +import ( + "fmt" + "net" + + "golang.org/x/sys/unix" +) + +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 +} + +func PrintTCPInfo(info *unix.TCPInfo) { + fmt.Printf("TCPInfo: \n") + fmt.Printf(" State: %v\n", info.State) + fmt.Printf(" Ca_state: %v\n", info.Ca_state) + fmt.Printf(" Retransmits: %v\n", info.Retransmits) + fmt.Printf(" Probes: %v\n", info.Probes) + fmt.Printf(" Backoff: %v\n", info.Backoff) + fmt.Printf(" Options: %v\n", info.Options) + fmt.Printf(" Rto: %v\n", info.Rto) + fmt.Printf(" Ato: %v\n", info.Ato) + fmt.Printf(" Snd_mss: %v\n", info.Snd_mss) + fmt.Printf(" Rcv_mss: %v\n", info.Rcv_mss) + fmt.Printf(" Unacked: %v\n", info.Unacked) + fmt.Printf(" Sacked: %v\n", info.Sacked) + fmt.Printf(" Lost: %v\n", info.Lost) + fmt.Printf(" Retrans: %v\n", info.Retrans) + fmt.Printf(" Fackets: %v\n", info.Fackets) + fmt.Printf(" Last_data_sent: %v\n", info.Last_data_sent) + fmt.Printf(" Last_ack_sent: %v\n", info.Last_ack_sent) + fmt.Printf(" Last_data_recv: %v\n", info.Last_data_recv) + fmt.Printf(" Last_ack_recv: %v\n", info.Last_ack_recv) + fmt.Printf(" Pmtu: %v\n", info.Pmtu) + fmt.Printf(" Rcv_ssthresh: %v\n", info.Rcv_ssthresh) + fmt.Printf(" Rtt: %v\n", info.Rtt) + fmt.Printf(" Rttvar: %v\n", info.Rttvar) + fmt.Printf(" Snd_ssthresh: %v\n", info.Snd_ssthresh) + fmt.Printf(" Snd_cwnd: %v\n", info.Snd_cwnd) + fmt.Printf(" Advmss: %v\n", info.Advmss) + fmt.Printf(" Reordering: %v\n", info.Reordering) + fmt.Printf(" Rcv_rtt: %v\n", info.Rcv_rtt) + fmt.Printf(" Rcv_space: %v\n", info.Rcv_space) + fmt.Printf(" Total_retrans: %v\n", info.Total_retrans) +} diff --git a/utilities/utilities.go b/utilities/utilities.go index e4c8a0d..7e26ab9 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -18,13 +18,10 @@ import ( "fmt" "math" "math/rand" - "net" "os" "reflect" "sync/atomic" "time" - - "golang.org/x/sys/unix" ) func IsInterfaceNil(ifc interface{}) bool { @@ -126,53 +123,10 @@ func RandBetween(max int) int { return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max } -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 - } +type NotImplemented struct { + Functionality string +} - 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 -} - -func PrintTCPInfo(info *unix.TCPInfo) { - fmt.Printf("TCPInfo: \n") - fmt.Printf(" State: %v\n", info.State) - fmt.Printf(" Ca_state: %v\n", info.Ca_state) - fmt.Printf(" Retransmits: %v\n", info.Retransmits) - fmt.Printf(" Probes: %v\n", info.Probes) - fmt.Printf(" Backoff: %v\n", info.Backoff) - fmt.Printf(" Options: %v\n", info.Options) - fmt.Printf(" Rto: %v\n", info.Rto) - fmt.Printf(" Ato: %v\n", info.Ato) - fmt.Printf(" Snd_mss: %v\n", info.Snd_mss) - fmt.Printf(" Rcv_mss: %v\n", info.Rcv_mss) - fmt.Printf(" Unacked: %v\n", info.Unacked) - fmt.Printf(" Sacked: %v\n", info.Sacked) - fmt.Printf(" Lost: %v\n", info.Lost) - fmt.Printf(" Retrans: %v\n", info.Retrans) - fmt.Printf(" Fackets: %v\n", info.Fackets) - fmt.Printf(" Last_data_sent: %v\n", info.Last_data_sent) - fmt.Printf(" Last_ack_sent: %v\n", info.Last_ack_sent) - fmt.Printf(" Last_data_recv: %v\n", info.Last_data_recv) - fmt.Printf(" Last_ack_recv: %v\n", info.Last_ack_recv) - fmt.Printf(" Pmtu: %v\n", info.Pmtu) - fmt.Printf(" Rcv_ssthresh: %v\n", info.Rcv_ssthresh) - fmt.Printf(" Rtt: %v\n", info.Rtt) - fmt.Printf(" Rttvar: %v\n", info.Rttvar) - fmt.Printf(" Snd_ssthresh: %v\n", info.Snd_ssthresh) - fmt.Printf(" Snd_cwnd: %v\n", info.Snd_cwnd) - fmt.Printf(" Advmss: %v\n", info.Advmss) - fmt.Printf(" Reordering: %v\n", info.Reordering) - fmt.Printf(" Rcv_rtt: %v\n", info.Rcv_rtt) - fmt.Printf(" Rcv_space: %v\n", info.Rcv_space) - fmt.Printf(" Total_retrans: %v\n", info.Total_retrans) +func (ni *NotImplemented) Error() string { + return fmt.Sprintf("%v not implemented.\n", ni.Functionality) } -- cgit v1.2.3 From d06438ff7414abfcc5a2a1bd13a935ee594f0842 Mon Sep 17 00:00:00 2001 From: Will Hawkins Date: Sun, 5 Jun 2022 03:32:17 -0400 Subject: [Feature] Add -extended-stats for *nix platforms On *nix platforms, there is now a `-extended-stats` option that will print out some extended statistics for the test. The statistics are based on information gleaned from the `TCP_INFO` of the underlying TCP connections. What is implemented so far is just a proof of concept of the extended stats that could be calculated. Depending on what users want, we can add additional extended statistics. --- extendedstats/other.go | 22 ++++++++++++++ extendedstats/unix.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++ networkQuality.go | 54 +++++++++++++++++----------------- utilities/tcpinfo_other.go | 18 ------------ utilities/tcpinfo_unix.go | 62 --------------------------------------- utilities/utilities.go | 11 ++++--- 6 files changed, 127 insertions(+), 112 deletions(-) create mode 100644 extendedstats/other.go create mode 100644 extendedstats/unix.go delete mode 100644 utilities/tcpinfo_other.go delete mode 100644 utilities/tcpinfo_unix.go 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/networkQuality.go b/networkQuality.go index d9bdc94..217ee6a 100644 --- a/networkQuality.go +++ b/networkQuality.go @@ -19,9 +19,6 @@ import ( "crypto/tls" "flag" "fmt" - _ "io" - _ "log" - "net" "net/http" "os" "runtime/pprof" @@ -31,6 +28,7 @@ import ( "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/rpm" "github.com/network-quality/goresponsiveness/timeoutat" @@ -80,6 +78,12 @@ var ( "", "Enable client runtime profiling and specify storage location. Disabled by default.", ) + + calculateExtendedStats = flag.Bool( + "extended-stats", + false, + "Enable the collection and display of extended statistics -- may not be available on certain platforms.", + ) ) func main() { @@ -99,6 +103,11 @@ func main() { 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 @@ -295,6 +304,18 @@ func main() { totalMeasurements := uint64(0) totalMeasurementTimes := float64(0) measurementTimeout := false + extendedStats := extendedstats.ExtendedStats{} + + 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 { @@ -324,29 +345,6 @@ func main() { continue } - if *debugCliFlag { - // Note: This code is just an example of how to use utilities.GetTCPInfo. - rawConn := downloadSaturation.LGCs[randomLGCsIndex].Stats().ConnInfo.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 := utilities.GetTCPInfo(tcpConn); err != nil { - switch err.(type) { - case *utilities.NotImplemented: - fmt.Printf("GetTCPInfo not implemented on this platform.\n") - default: - fmt.Printf("OOPS: Could not get the TCP info for the connection: %v!\n", err) - } - } else { - utilities.PrintTCPInfo(info) - } - } - unsaturatedMeasurementTransport := http2.Transport{} unsaturatedMeasurementTransport.TLSClientConfig = &tls.Config{} if sslKeyFileConcurrentWriter != nil { @@ -428,6 +426,10 @@ func main() { 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/utilities/tcpinfo_other.go b/utilities/tcpinfo_other.go deleted file mode 100644 index 8dd070b..0000000 --- a/utilities/tcpinfo_other.go +++ /dev/null @@ -1,18 +0,0 @@ -//go:build !darwin && !dragonfly && !freebsd && !linux && !netbsd && !openbsd -// +build !darwin,!dragonfly,!freebsd,!linux,!netbsd,!openbsd - -package utilities - -import ( - "net" - - "golang.org/x/sys/unix" -) - -func GetTCPInfo(connection net.Conn) (*unix.TCPInfo, error) { - return nil, NotImplemented{Functionality: "GetTCPInfo"} -} - -func PrintTCPInfo(info *unix.TCPInfo) { - return -} diff --git a/utilities/tcpinfo_unix.go b/utilities/tcpinfo_unix.go deleted file mode 100644 index b0b5252..0000000 --- a/utilities/tcpinfo_unix.go +++ /dev/null @@ -1,62 +0,0 @@ -//go:build darwin || dragonfly || freebsd || linux || netbsd || openbsd -// +build darwin dragonfly freebsd linux netbsd openbsd - -package utilities - -import ( - "fmt" - "net" - - "golang.org/x/sys/unix" -) - -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 -} - -func PrintTCPInfo(info *unix.TCPInfo) { - fmt.Printf("TCPInfo: \n") - fmt.Printf(" State: %v\n", info.State) - fmt.Printf(" Ca_state: %v\n", info.Ca_state) - fmt.Printf(" Retransmits: %v\n", info.Retransmits) - fmt.Printf(" Probes: %v\n", info.Probes) - fmt.Printf(" Backoff: %v\n", info.Backoff) - fmt.Printf(" Options: %v\n", info.Options) - fmt.Printf(" Rto: %v\n", info.Rto) - fmt.Printf(" Ato: %v\n", info.Ato) - fmt.Printf(" Snd_mss: %v\n", info.Snd_mss) - fmt.Printf(" Rcv_mss: %v\n", info.Rcv_mss) - fmt.Printf(" Unacked: %v\n", info.Unacked) - fmt.Printf(" Sacked: %v\n", info.Sacked) - fmt.Printf(" Lost: %v\n", info.Lost) - fmt.Printf(" Retrans: %v\n", info.Retrans) - fmt.Printf(" Fackets: %v\n", info.Fackets) - fmt.Printf(" Last_data_sent: %v\n", info.Last_data_sent) - fmt.Printf(" Last_ack_sent: %v\n", info.Last_ack_sent) - fmt.Printf(" Last_data_recv: %v\n", info.Last_data_recv) - fmt.Printf(" Last_ack_recv: %v\n", info.Last_ack_recv) - fmt.Printf(" Pmtu: %v\n", info.Pmtu) - fmt.Printf(" Rcv_ssthresh: %v\n", info.Rcv_ssthresh) - fmt.Printf(" Rtt: %v\n", info.Rtt) - fmt.Printf(" Rttvar: %v\n", info.Rttvar) - fmt.Printf(" Snd_ssthresh: %v\n", info.Snd_ssthresh) - fmt.Printf(" Snd_cwnd: %v\n", info.Snd_cwnd) - fmt.Printf(" Advmss: %v\n", info.Advmss) - fmt.Printf(" Reordering: %v\n", info.Reordering) - fmt.Printf(" Rcv_rtt: %v\n", info.Rcv_rtt) - fmt.Printf(" Rcv_space: %v\n", info.Rcv_space) - fmt.Printf(" Total_retrans: %v\n", info.Total_retrans) -} diff --git a/utilities/utilities.go b/utilities/utilities.go index 7e26ab9..76acbd2 100644 --- a/utilities/utilities.go +++ b/utilities/utilities.go @@ -123,10 +123,9 @@ func RandBetween(max int) int { return rand.New(rand.NewSource(int64(time.Now().Nanosecond()))).Int() % max } -type NotImplemented struct { - Functionality string -} - -func (ni *NotImplemented) Error() string { - return fmt.Sprintf("%v not implemented.\n", ni.Functionality) +func Max(x, y uint64) uint64 { + if x > y { + return x + } + return y } -- cgit v1.2.3