Skip to content

Commit

Permalink
Pull request #32: Acm algo c
Browse files Browse the repository at this point in the history
Merge in OBUDPST/udpst from acm-algo-c to develop

* commit '92222be75aecafc36ef74a548630a01e076af0a5':
  OBUDPST-40, obudpst-43, OBUDPST-44 Release 7.5.0 final commit Branch acm-algo-c
  OBUDPST-43: Extend sending rate table
  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)
  • Loading branch information
acmacm committed May 6, 2022
2 parents 200ecf3 + 92222be commit 8cc26ba
Show file tree
Hide file tree
Showing 8 changed files with 133 additions and 69 deletions.
10 changes: 10 additions & 0 deletions CHANGELOG.MD
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
13 changes: 13 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 <server> -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:

Expand Down
2 changes: 1 addition & 1 deletion udpst.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];
Expand Down
18 changes: 13 additions & 5 deletions udpst.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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

//----------------------------------------------------------------------------
Expand All @@ -173,6 +171,12 @@
#define SMA_BIND 1
#define SMA_UPDATE 2

//----------------------------------------------------------------------------
//
// Rate Adjustment Algorithms
//
#define RETRY_THRESH_ALGOC 5 // AlgoC: Initial retry threshold

//----------------------------------------------------------------------------
// Data structures
//----------------------------------------------------------------------------
Expand Down Expand Up @@ -324,6 +328,10 @@ struct connection {
BOOL randPayload; // Payload randomization
int rateAdjAlgo; // Rate adjustment algorithm
//
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
Expand Down
58 changes: 58 additions & 0 deletions udpst_data.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
*/

Expand Down Expand Up @@ -1151,6 +1152,63 @@ 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 : 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
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

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 fast ramp-up
}
if (c->algoCRetryCount >= c->algoCRetryThresh) {
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; // 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 fast ramp-up retry

if (c->algoCRetryCount >= c->algoCRetryThresh) {
c->slowAdjCount = 0; // Retry fast ramp-up again
c->algoCRetryCount = 0; // Use the same thresholds in the next fast ramp-up
}
}
}
}
}

//
Expand Down
3 changes: 2 additions & 1 deletion udpst_protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
96 changes: 35 additions & 61 deletions udpst_srates.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
*
*/

Expand Down Expand Up @@ -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;
}

//
Expand All @@ -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;

//
Expand All @@ -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,
Expand Down

0 comments on commit 8cc26ba

Please sign in to comment.