From 143599bb8e6817b9dbdfe308a5078c4973700379 Mon Sep 17 00:00:00 2001 From: Al Morton Date: Wed, 13 Apr 2022 10:55:23 -0500 Subject: [PATCH 1/3] On branch acm-algo-c Changes to be committed: modified: CHANGELOG.MD modified: README.md modified: udpst.c modified: udpst.h modified: udpst_data.c modified: udpst_protocol.h JIRA OBUDPST-40 New Type (C) Load Adjustment Alg (Multiplicative) --- CHANGELOG.MD | 10 ++++++++ README.md | 13 +++++++++++ udpst.c | 2 +- udpst.h | 11 +++++++++ udpst_data.c | 59 ++++++++++++++++++++++++++++++++++++++++++++++++ udpst_protocol.h | 3 ++- 6 files changed, 96 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.MD b/CHANGELOG.MD index a5d5080..1dba8d8 100644 --- a/CHANGELOG.MD +++ b/CHANGELOG.MD @@ -3,6 +3,16 @@ *The udpst utility conforms to TR-471 and TR-471 Issue 2. The latest TR-471 specification can be found at https://www.broadband-forum.org/technical/download/TR-471.pdf * +# 2022-05-05: [UDPST 7.5.0] (https://github.com/BroadbandForum/OB-UDPST/releases/tag/v7.5.0) + +This release has one major new feature, which was anticipated by the version 9 protocol: + +* Optional Load Adjustment (Search) Algorithm, Type C, briefly described as "Multiply and Retry" +* The "fast" ramp-up is now a multiplicative rate increase to congestion, reaching 1Gbps in ~1 second +* The "fast" ramp-up can be re-tried when conditions warrent, to ensure that the Max IP-Layer Capacity is reached +* This algorithm supports a search over the full range of rates, even if the subscribed rate is >1Gbps +* The Type B algorithm remains the default, for testing that does not benefit from "Multiply and Retry" aspects + # 2022-02-24: [UDPST 7.4.0] (https://github.com/BroadbandForum/OB-UDPST/releases/tag/v7.4.0) This release has many new features, supported by the version 9 protocol: diff --git a/README.md b/README.md index 01f1abc..e38194e 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,19 @@ $ udpst -? (c) -h delta High-speed (row adjustment) delta [Default 10] (c) -q seqerr Sequence error threshold [Default 10] ``` +An option in Release 7.5.0 allows the client to request the algorithm used for +load adjustment when conducting a search for the Maximum IP-Layer Capacity. +The Type C algorithm (a.k.a. Multiply and Retry) will provide a fast +rate increase to congestion, reaching 1Gbps in ~1 second. The "fast" ramp-up +will be re-tried when conditions warrent, to ensure that the Max IP-Layer +Capacity has been reached. This option is activated using -A algo: +``` +$ udpst -d -A c + Do downstream test from server (as hostname or IP address) to client + using the Type C algorithm +``` +The Type B algorithm remains the default. + See the following publication (which is updated frequently) for more details on testing in the circumstances described above: diff --git a/udpst.c b/udpst.c index d60ade0..72a3caf 100644 --- a/udpst.c +++ b/udpst.c @@ -120,7 +120,7 @@ struct connection *conn; // Connection table (array) static volatile sig_atomic_t sig_alrm = 0; // Interrupt indicator static volatile sig_atomic_t sig_exit = 0; // Interrupt indicator char *boolText[] = {"Disabled", "Enabled"}; -char *rateAdjAlgo[] = {"B"}; // Aligned to CHTA_RA_ALGO_x +char *rateAdjAlgo[] = {"B", "C"}; // Aligned to CHTA_RA_ALGO_x // cJSON *json_top = NULL, *json_output = NULL; char json_errbuf[STRING_SIZE]; diff --git a/udpst.h b/udpst.h index e697fec..33b3ff0 100644 --- a/udpst.h +++ b/udpst.h @@ -173,6 +173,12 @@ #define SMA_BIND 1 #define SMA_UPDATE 2 +//---------------------------------------------------------------------------- +// +// Rate Adjustment Algorithms +// +#define RETRY_THRESH_ALGOC 5 // AlgoC: Initial retry threshold + //---------------------------------------------------------------------------- // Data structures //---------------------------------------------------------------------------- @@ -324,6 +330,11 @@ struct connection { BOOL randPayload; // Payload randomization int rateAdjAlgo; // Rate adjustment algorithm // + int algoCRateWImpair; // AlgoC: Previous max send rate during multiplicative ramp-up + int algoCRetryCount; // AlgoC: Waiting timer till next multiplicative retry + int algoCRetryThresh; // AlgoC: Threshold for multiplicative retry + BOOL algoCUpdate; // AlgoC: Indicates when max send rate was updated + // struct timespec endTime; // Connection end time int (*priAction)(int); // Primary action upon IO int (*secAction)(int); // Secondary action upon IO diff --git a/udpst_data.c b/udpst_data.c index 9d6f5f3..64d2934 100644 --- a/udpst_data.c +++ b/udpst_data.c @@ -62,6 +62,7 @@ * Len Ciavattone 12/24/2021 Handle interface byte counter wrap * Len Ciavattone 01/08/2022 Check burstsize >1 if forcing to 1 * Len Ciavattone 02/02/2022 Add rate adj. algo. selection + * Al Morton 04/12/2022 Type C algoithm, Multiply and Retry * */ @@ -1151,8 +1152,66 @@ int adjust_sending_rate(int connindex) { c->srIndex--; } } + }else if (c->rateAdjAlgo == CHTA_RA_ALGO_C) { + if (c->algoCRetryThresh == 0) + c->algoCRetryThresh = RETRY_THRESH_ALGOC; // Keep non-zero initialization local to algorithm + // + // Multiplicative adjust sending rate : 2x previous rate : with retry after waiting (if new max rate achieved) + // This section of code would be an optional algorithm, with the properties of + // faster search to the max region, also shorter time when errors might end the fast search + // + if (seqerr <= c->seqErrThresh && delay < c->lowThresh) { + if (c->srIndex < repo.hSpeedThresh && c->slowAdjCount < c->slowAdjThresh) { // Congestion not detected + if (c->srIndex * 2 > repo.hSpeedThresh) { // If no room to jump within high-speed threshold + c->srIndex = repo.hSpeedThresh; // Truncate jump at high-speed threshold + } else { + if (c->srIndex == 0) + c->srIndex++; // Pre-increment to deal with zero index + // Halve the Multiplicative Rate, using algoCUpdate + if(c->algoCUpdate == TRUE) { + c->srIndex *= 2; // Jump forward (while staying below high-speed threshold) + c->algoCUpdate = FALSE; + } else { + c->algoCUpdate = TRUE; + } + } + c->slowAdjCount = 0; // Reset congestion detection counter + } else { + if (c->srIndex < repo.maxSendingRates - 1) { + c->srIndex++; // Increment index (slow path) + c->algoCRetryCount++; // Increment waiting count until retry + } + if (c->algoCRetryCount >= c->algoCRetryThresh) { + c->slowAdjCount = 0; // Retry fast ramp-up again + c->algoCRetryCount = 0; // Use the same thresholds in the next 2x ramp-up + c->algoCRetryThresh += RETRY_THRESH_ALGOC; // Bump thresh out + } + } + } else if (seqerr > c->seqErrThresh || delay > c->upperThresh) { + c->slowAdjCount++; + if (c->srIndex < repo.hSpeedThresh && c->slowAdjCount == c->slowAdjThresh) { // Congestion detected + if (c->srIndex > c->highSpeedDelta * HS_DELTA_BACKUP) { // If room to jump backward + c->srIndex -= c->highSpeedDelta * HS_DELTA_BACKUP; // Jump backward (staying above start) + } else { + c->srIndex = 0; // Jump backward to start + } + } else { + if (c->srIndex > 0) { + c->srIndex--; // Decrement index (slow path) + c->algoCRetryCount++; // Increment waiting count until retry + + if (c->algoCRetryCount >= c->algoCRetryThresh) { + c->slowAdjCount = 0; // Retry fast ramp-up again + c->algoCRetryCount = 0; // Use the same thresholds in the next mult. ramp-up + + } + + } + } + } } + // // Display debug info if needed // diff --git a/udpst_protocol.h b/udpst_protocol.h index 199e672..a48a7ca 100644 --- a/udpst_protocol.h +++ b/udpst_protocol.h @@ -158,8 +158,9 @@ struct controlHdrTA { #define CHTA_RAND_PAYLOAD 0x02 uint8_t modifierBitmap; // Modifier bitmap (replaced reserved1 in v9) #define CHTA_RA_ALGO_B 0 +#define CHTA_RA_ALGO_C 1 #define CHTA_RA_ALGO_MIN CHTA_RA_ALGO_B -#define CHTA_RA_ALGO_MAX CHTA_RA_ALGO_B +#define CHTA_RA_ALGO_MAX CHTA_RA_ALGO_C uint8_t rateAdjAlgo; // Rate adjust. algo. (replaced reserved2 in v9) uint8_t reserved1; // (Alignment) (replaced reserved2 in v9) struct sendingRate srStruct; // Sending rate structure From 54fddcd63d55b297056a84c4a2761ad198589a1e Mon Sep 17 00:00:00 2001 From: Len Ciavattone Date: Fri, 22 Apr 2022 16:03:14 -0400 Subject: [PATCH 2/3] OBUDPST-43: Extend sending rate table This change extends the sending rate table to 40 Gbps (with jumbo datagram sizes enabled). This new maximum is expected to allow the software to run to its absolute limit when adequate processor and network resources are available. --- udpst.h | 9 ++--- udpst_data.c | 43 +++++++++++----------- udpst_srates.c | 96 ++++++++++++++++++-------------------------------- 3 files changed, 59 insertions(+), 89 deletions(-) diff --git a/udpst.h b/udpst.h index 33b3ff0..b6e0248 100644 --- a/udpst.h +++ b/udpst.h @@ -135,7 +135,7 @@ // // Sending rate payload, protocol, and buffer sizes // -#define MAX_SENDING_RATES 1091 // Max rows in sending rate table +#define MAX_SENDING_RATES 1109 // Max rows in sending rate table #define BASE_SEND_TIMER1 MIN_INTERVAL_USEC // Base send timer, transmitter 1 (us) #define BASE_SEND_TIMER2 1000 // Base send timer, transmitter 2 (us) #define MAX_L3_PACKET 1250 // Max desired L3 packet size @@ -151,11 +151,9 @@ #define MAX_JPAYLOAD_SIZE (MAX_JL3_PACKET - L3DG_OVERHEAD) #define MAX_TPAYLOAD_SIZE (MAX_TL3_PACKET - L3DG_OVERHEAD) // -// The send buffer needs to contain all the datagram payloads for a burst. The maximum -// burst size that is used with non-jumbo payloads is actually much larger than the maximum -// burst size used with jumbo payloads. +// The send buffer needs to contain all the datagram payloads for a burst. // -#define SND_BUFFER_SIZE (MAX_BURST_SIZE * MAX_TPAYLOAD_SIZE) +#define SND_BUFFER_SIZE (MAX_BURST_SIZE * MAX_JPAYLOAD_SIZE) #define DEF_BUFFER_SIZE 65536 //---------------------------------------------------------------------------- @@ -330,7 +328,6 @@ struct connection { BOOL randPayload; // Payload randomization int rateAdjAlgo; // Rate adjustment algorithm // - int algoCRateWImpair; // AlgoC: Previous max send rate during multiplicative ramp-up int algoCRetryCount; // AlgoC: Waiting timer till next multiplicative retry int algoCRetryThresh; // AlgoC: Threshold for multiplicative retry BOOL algoCUpdate; // AlgoC: Indicates when max send rate was updated diff --git a/udpst_data.c b/udpst_data.c index 64d2934..e13ff52 100644 --- a/udpst_data.c +++ b/udpst_data.c @@ -1152,13 +1152,13 @@ int adjust_sending_rate(int connindex) { c->srIndex--; } } - }else if (c->rateAdjAlgo == CHTA_RA_ALGO_C) { + } else if (c->rateAdjAlgo == CHTA_RA_ALGO_C) { if (c->algoCRetryThresh == 0) c->algoCRetryThresh = RETRY_THRESH_ALGOC; // Keep non-zero initialization local to algorithm // - // Multiplicative adjust sending rate : 2x previous rate : with retry after waiting (if new max rate achieved) - // This section of code would be an optional algorithm, with the properties of - // faster search to the max region, also shorter time when errors might end the fast search + // Multiplicative adjust sending rate : 1.5x previous rate : with retry after waiting + // This section of code provides an optional algorithm, with the properties of faster search to the + // max region, meaning less time when errors might end a fast search, and retry fast if that happens. // if (seqerr <= c->seqErrThresh && delay < c->lowThresh) { if (c->srIndex < repo.hSpeedThresh && c->slowAdjCount < c->slowAdjThresh) { // Congestion not detected @@ -1167,51 +1167,50 @@ int adjust_sending_rate(int connindex) { } else { if (c->srIndex == 0) c->srIndex++; // Pre-increment to deal with zero index - // Halve the Multiplicative Rate, using algoCUpdate - if(c->algoCUpdate == TRUE) { - c->srIndex *= 2; // Jump forward (while staying below high-speed threshold) - c->algoCUpdate = FALSE; - } else { - c->algoCUpdate = TRUE; - } + + if (c->algoCUpdate == TRUE) { // Halve the multiplicative rate, using algoCUpdate + c->srIndex *= 2; // Jump forward (while staying below high-speed threshold) + c->algoCUpdate = FALSE; + } else { + c->algoCUpdate = TRUE; + } } c->slowAdjCount = 0; // Reset congestion detection counter } else { if (c->srIndex < repo.maxSendingRates - 1) { c->srIndex++; // Increment index (slow path) - c->algoCRetryCount++; // Increment waiting count until retry + c->algoCRetryCount++; // Increment waiting count until retry fast ramp-up } if (c->algoCRetryCount >= c->algoCRetryThresh) { - c->slowAdjCount = 0; // Retry fast ramp-up again - c->algoCRetryCount = 0; // Use the same thresholds in the next 2x ramp-up - c->algoCRetryThresh += RETRY_THRESH_ALGOC; // Bump thresh out + c->slowAdjCount = 0; // Retry fast ramp-up again + c->algoCRetryCount = 0; // Clear variables to enable fast ramp-up + c->algoCRetryThresh += + RETRY_THRESH_ALGOC; // Use higher wait threshold for the next fast ramp-up } } } else if (seqerr > c->seqErrThresh || delay > c->upperThresh) { c->slowAdjCount++; if (c->srIndex < repo.hSpeedThresh && c->slowAdjCount == c->slowAdjThresh) { // Congestion detected if (c->srIndex > c->highSpeedDelta * HS_DELTA_BACKUP) { // If room to jump backward - c->srIndex -= c->highSpeedDelta * HS_DELTA_BACKUP; // Jump backward (staying above start) + c->srIndex -= + c->highSpeedDelta * HS_DELTA_BACKUP; // Large jump backward (staying above start) } else { c->srIndex = 0; // Jump backward to start } } else { if (c->srIndex > 0) { c->srIndex--; // Decrement index (slow path) - c->algoCRetryCount++; // Increment waiting count until retry + c->algoCRetryCount++; // Increment waiting count until fast ramp-up retry - if (c->algoCRetryCount >= c->algoCRetryThresh) { + if (c->algoCRetryCount >= c->algoCRetryThresh) { c->slowAdjCount = 0; // Retry fast ramp-up again - c->algoCRetryCount = 0; // Use the same thresholds in the next mult. ramp-up - + c->algoCRetryCount = 0; // Use the same thresholds in the next fast ramp-up } - } } } } - // // Display debug info if needed // diff --git a/udpst_srates.c b/udpst_srates.c index 43eccd5..1151edb 100644 --- a/udpst_srates.c +++ b/udpst_srates.c @@ -43,6 +43,7 @@ * with IPv6. No longer mixing jumbo * sizes with non-jumbo sizes. * Len Ciavattone 12/21/2021 Add traditional (1500 byte) MTU + * Len Ciavattone 04/21/2022 Increase sending rates to 40 Gbps * */ @@ -167,66 +168,39 @@ int def_sending_rates(void) { // // Increase payload sizes until jumbo limit // - for (i = MAX_L3_PACKET + 125; i <= MAX_JL3_PACKET; i += 125) { - sr = &repo.sendingRates[repo.maxSendingRates++]; - sr->txInterval1 = BASE_SEND_TIMER1; - sr->udpPayload1 = i - L3DG_OVERHEAD; - sr->burstSize1 = 10; - } - // - // With jumbo payload size for transmitter 1, add additional payload required for 2 - // // To better support the use of jumbo sizes with a non-jumbo MTU, do not use any payload sizes // that would mix datagrams requiring fragmentation with datagrams not requiring fragmentation. // Because this has been shown to produce reordering, all payload sizes will be greater than // what can be accommodated in IPv6 with a 1500 byte MTU. // - for (i = 0; i < 4; i++) { - var = MAX_L3_PACKET - (i * 125 * 2); - for (j = 0; j < 7; j++) { - sr = &repo.sendingRates[repo.maxSendingRates++]; - sr->txInterval1 = BASE_SEND_TIMER1; - sr->udpPayload1 = MAX_JPAYLOAD_SIZE; - sr->burstSize1 = 10 + i; - sr->txInterval2 = BASE_SEND_TIMER1; - sr->udpPayload2 = (var + (j * MAX_L3_PACKET)) - L3DG_OVERHEAD; - // Avoid non-jumbo sizes with less frequent larger payloads - if (j == 0) { - sr->txInterval2 *= 4; - sr->udpPayload2 *= 4; - } else if (j == 1) { - sr->txInterval2 *= 2; - sr->udpPayload2 *= 2; - } - sr->burstSize2 = 1; - sr->udpAddon2 = 0; - } - } - } else { - if (conf.traditionalMTU) { - jmax = 9; - payload = MAX_TPAYLOAD_SIZE; - } else { - jmax = 11; - payload = MAX_PAYLOAD_SIZE; - } - for (j = jmax; j <= MAX_BURST_SIZE; j++) { + for (i = MAX_L3_PACKET + 125; i <= MAX_JL3_PACKET; i += 125) { sr = &repo.sendingRates[repo.maxSendingRates++]; sr->txInterval1 = BASE_SEND_TIMER1; - sr->udpPayload1 = payload; - sr->burstSize1 = j; - if (conf.traditionalMTU && j < 23) { - sr = &repo.sendingRates[repo.maxSendingRates++]; - sr->txInterval1 = BASE_SEND_TIMER1; - sr->udpPayload1 = payload; - sr->burstSize1 = j; - sr->txInterval2 = BASE_SEND_TIMER2; - sr->udpPayload2 = payload; - sr->burstSize2 = 5; - } - if (repo.maxSendingRates == MAX_SENDING_RATES) - break; + sr->udpPayload1 = i - L3DG_OVERHEAD; + sr->burstSize1 = 10; } + jmax = 11; + payload = MAX_JPAYLOAD_SIZE; + + } else if (conf.traditionalMTU) { + jmax = 9; + payload = MAX_TPAYLOAD_SIZE; + } else { + jmax = 11; + payload = MAX_PAYLOAD_SIZE; + } + for (j = jmax; repo.maxSendingRates < MAX_SENDING_RATES; j++) { + sr = &repo.sendingRates[repo.maxSendingRates++]; + sr->txInterval1 = BASE_SEND_TIMER1; + sr->udpPayload1 = payload; + if (j < MAX_BURST_SIZE) + sr->burstSize1 = j; + else + sr->burstSize1 = MAX_BURST_SIZE; + sr->txInterval2 = 0; + sr->udpPayload2 = 0; + sr->burstSize2 = 0; + sr->udpAddon2 = 0; } // @@ -243,9 +217,9 @@ int def_sending_rates(void) { // Display sending rate table parameters for each index // void show_sending_rates(int fd) { - int i, var, var2, payload1, payload2, addon, ipv6add; + int i, var, payload1, payload2, addon, ipv6add; char ipver[8]; - double dvar; + double dvar, dvar2; struct sendingRate *sr; // @@ -268,23 +242,23 @@ void show_sending_rates(int fd) { // Output each row // for (i = 0, sr = repo.sendingRates; i < repo.maxSendingRates; i++, sr++) { - var = var2 = 0; + dvar = dvar2 = 0; payload1 = payload2 = addon = 0; if (sr->burstSize1 > 0) { - var = (USECINSEC / sr->txInterval1) * sr->burstSize1; + dvar = (double) ((USECINSEC / sr->txInterval1) * sr->burstSize1); payload1 = (int) sr->udpPayload1 - ipv6add; - var *= payload1 + L3DG_OVERHEAD + ipv6add; + dvar *= (double) (payload1 + L3DG_OVERHEAD + ipv6add); } if (sr->burstSize2 > 0) { - var2 = (USECINSEC / sr->txInterval2) * sr->burstSize2; + dvar2 = (double) ((USECINSEC / sr->txInterval2) * sr->burstSize2); payload2 = (int) sr->udpPayload2 - ipv6add; - var2 *= payload2 + L3DG_OVERHEAD + ipv6add; + dvar2 *= (double) (payload2 + L3DG_OVERHEAD + ipv6add); } if (sr->udpAddon2 > 0) { addon = (int) sr->udpAddon2 - ipv6add; - var2 += (USECINSEC / sr->txInterval2) * (addon + L3DG_OVERHEAD + ipv6add); + dvar2 += (double) ((USECINSEC / sr->txInterval2) * (addon + L3DG_OVERHEAD + ipv6add)); } - dvar = (double) (var + var2); + dvar += dvar2; dvar *= 8; // Convert to bits/sec dvar /= 1000000; // Convert to Mbps var = sprintf(scratch, "%5d) %8u %7d %5u + %8u %7d %5u %5d = %10.2f\n", i, sr->txInterval1, payload1, From 92222be75aecafc36ef74a548630a01e076af0a5 Mon Sep 17 00:00:00 2001 From: Al Morton Date: Fri, 6 May 2022 11:14:27 -0500 Subject: [PATCH 3/3] OBUDPST-40, obudpst-43, OBUDPST-44 Release 7.5.0 final commit Branch acm-algo-c --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index f0564e2..59bd15b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -33,7 +33,7 @@ if(${CMAKE_VERSION} VERSION_GREATER "3.3.0") endif() set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -set(SOFTWARE_VER "7.4.0") +set(SOFTWARE_VER "7.5.0") INCLUDE (CheckIncludeFiles) INCLUDE (CheckFunctionExists)