Skip to content

Commit 595c377

Browse files
committed
erts: Shrink the adaptive esock rcvbuf via an EWMA
The consecutive-reads counter made shrinking statistically unreachable on mixed traffic: a single read over a quarter of the buffer reset it, so a buffer at the cap could stay there through tens of thousands of smaller reads. Track an EWMA of the read sizes instead (alpha 1/8, shift arithmetic) and halve the buffer whenever the average falls below a quarter of it. Bulk bursts still ramp up unchanged since every filled read doubles the buffer, and once traffic turns small the average converges within a couple dozen reads and the buffer halves per read back to the configured size. An isolated filled read among small ones now also shrinks back instead of ratcheting.
1 parent cfa4e6c commit 595c377

3 files changed

Lines changed: 16 additions & 20 deletions

File tree

erts/emulator/nifs/common/prim_socket_int.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -522,7 +522,7 @@ typedef struct {
522522
* the size, since it bounds the chunks such a recv may return.
523523
*/
524524
size_t rBufSzAdapt; // Current adaptive read buffer size
525-
unsigned int rBufShrinkCnt;
525+
size_t rBufSzAvg; // EWMA of the read sizes
526526
BOOLEAN_T rBufAdapt;
527527
#endif
528528
size_t rCtrlSz; // Read control buffer size

erts/emulator/nifs/common/prim_socket_nif.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8225,9 +8225,9 @@ ERL_NIF_TERM esock_setopt_otp_rcvbuf(ErlNifEnv* env,
82258225
else
82268226
descP->rBufSz = bufSz;
82278227
#ifndef __WIN32__
8228-
descP->rBufAdapt = FALSE;
8229-
descP->rBufSzAdapt = descP->rBufSz;
8230-
descP->rBufShrinkCnt = 0;
8228+
descP->rBufAdapt = FALSE;
8229+
descP->rBufSzAdapt = descP->rBufSz;
8230+
descP->rBufSzAvg = descP->rBufSz;
82318231
#endif
82328232

82338233
SSDBG( descP,
@@ -17069,7 +17069,7 @@ ESockDescriptor* esock_alloc_descriptor(SOCKET sock)
1706917069
descP->rNumCnt = 0;
1707017070
descP->rBufAdapt = TRUE;
1707117071
descP->rBufSzAdapt = ESOCK_RECV_BUFFER_SIZE_DEFAULT;
17072-
descP->rBufShrinkCnt = 0;
17072+
descP->rBufSzAvg = ESOCK_RECV_BUFFER_SIZE_DEFAULT;
1707317073
#endif
1707417074
descP->rCtrlSz = ESOCK_RECV_CTRL_BUFFER_SIZE_DEFAULT;
1707517075
descP->wCtrlSz = ESOCK_SEND_CTRL_BUFFER_SIZE_DEFAULT;

erts/emulator/nifs/unix/unix_socket_syncio.c

Lines changed: 11 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,11 @@
211211
#define sock_close(s) close((s))
212212

213213
/* Adaptive read buffer: double on a filled buffer, halve back towards
214-
* the configured size after this many consecutive reads that used
215-
* less than a quarter of it.
214+
* the configured size once an EWMA of the read sizes falls below a
215+
* quarter of it.
216216
*/
217217
#define ESSIO_RECV_ADAPT_BUFFER_MAX (1 << 20)
218-
#define ESSIO_RECV_ADAPT_SHRINK_COUNT 32
218+
#define ESSIO_RECV_ADAPT_EWMA_SHIFT 3
219219
// #define sock_close_event(e) /* do nothing */
220220
#define sock_connect(s, addr, len) connect((s), (addr), (len))
221221
#define sock_connectx(s, addrs, acnt, aidp) \
@@ -2850,7 +2850,7 @@ BOOLEAN_T essio_accept_accepted(ErlNifEnv* env,
28502850
accDescP->rBufSz = descP->rBufSz; // Inherit buffer size
28512851
accDescP->rBufAdapt = descP->rBufAdapt;
28522852
accDescP->rBufSzAdapt = descP->rBufSz;
2853-
accDescP->rBufShrinkCnt = 0;
2853+
accDescP->rBufSzAvg = descP->rBufSz;
28542854
accDescP->rNum = descP->rNum; // Inherit buffer uses
28552855
accDescP->rNumCnt = 0;
28562856
accDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size
@@ -2956,7 +2956,7 @@ ERL_NIF_TERM essio_peeloff(ErlNifEnv* env,
29562956
poDescP->rBufSz = descP->rBufSz; // Inherit buffer size
29572957
poDescP->rBufAdapt = descP->rBufAdapt;
29582958
poDescP->rBufSzAdapt = descP->rBufSz;
2959-
poDescP->rBufShrinkCnt = 0;
2959+
poDescP->rBufSzAvg = descP->rBufSz;
29602960
poDescP->rNum = descP->rNum; // Inherit buffer uses
29612961
poDescP->rNumCnt = 0;
29622962
poDescP->rCtrlSz = descP->rCtrlSz; // Inherit buffer size
@@ -3863,20 +3863,16 @@ ERL_NIF_TERM essio_recv(ErlNifEnv* env,
38633863
/* readResult >= 0 */
38643864

38653865
if ((len == 0) && descP->rBufAdapt && (descP->type == SOCK_STREAM)) {
3866+
descP->rBufSzAvg -= descP->rBufSzAvg >> ESSIO_RECV_ADAPT_EWMA_SHIFT;
3867+
descP->rBufSzAvg += ((size_t) readResult) >> ESSIO_RECV_ADAPT_EWMA_SHIFT;
38663868
if ((size_t) readResult == bufP->size) {
38673869
if (descP->rBufSzAdapt < ESSIO_RECV_ADAPT_BUFFER_MAX)
38683870
descP->rBufSzAdapt <<= 1;
3869-
descP->rBufShrinkCnt = 0;
38703871
} else if ((descP->rBufSzAdapt > descP->rBufSz) &&
3871-
((size_t) readResult < (descP->rBufSzAdapt >> 2))) {
3872-
if (++descP->rBufShrinkCnt >= ESSIO_RECV_ADAPT_SHRINK_COUNT) {
3873-
descP->rBufSzAdapt >>= 1;
3874-
if (descP->rBufSzAdapt < descP->rBufSz)
3875-
descP->rBufSzAdapt = descP->rBufSz;
3876-
descP->rBufShrinkCnt = 0;
3877-
}
3878-
} else {
3879-
descP->rBufShrinkCnt = 0;
3872+
(descP->rBufSzAvg < (descP->rBufSzAdapt >> 2))) {
3873+
descP->rBufSzAdapt >>= 1;
3874+
if (descP->rBufSzAdapt < descP->rBufSz)
3875+
descP->rBufSzAdapt = descP->rBufSz;
38803876
}
38813877
}
38823878

0 commit comments

Comments
 (0)