try to avoid extra syscalls when reading sockets

so far we shifted down the buffered data only when we ran out of space.
however, that may cause chopping up the actual socket read, which is a
bad trade-off with avoiding a moderate-sized memmove. so try to keep
enough space for the anticipated read size.

note that this ignores the zlib path, as that always does full-size
socket reads into z_buf, and saving inflate() calls seems pointless.
This commit is contained in:
Oswald Buddenhagen 2022-06-09 13:32:16 +02:00
parent ac3b5186b0
commit 859b7dd7f2
2 changed files with 17 additions and 4 deletions

View File

@ -407,6 +407,7 @@ socket_start_deflate( conn_t *conn )
} }
init_wakeup( &conn->z_fake, z_fake_cb, conn ); init_wakeup( &conn->z_fake, z_fake_cb, conn );
conn->readsz = 0; // This optimization makes no sense past this point
} }
#endif /* HAVE_LIBZ */ #endif /* HAVE_LIBZ */
@ -726,8 +727,9 @@ socket_filled( conn_t *conn, uint len )
uint cnt = conn->bytes + len; uint cnt = conn->bytes + len;
conn->bytes = cnt; conn->bytes = cnt;
if (conn->wanted) { if (conn->wanted) {
// Fulfill as much of the request as still fits into the buffer // Fulfill as much of the request as still fits into the buffer,
if (cnt < conn->wanted && off + cnt < sizeof(conn->buf)) // but avoid chopping up the actual socket reads
if (cnt < conn->wanted && off + cnt < sizeof(conn->buf) - conn->readsz)
return; return;
} else { } else {
// Need a full line // Need a full line
@ -735,7 +737,7 @@ socket_filled( conn_t *conn, uint len )
char *p = memchr( s + conn->scanoff, '\n', cnt - conn->scanoff ); char *p = memchr( s + conn->scanoff, '\n', cnt - conn->scanoff );
if (!p) { if (!p) {
conn->scanoff = cnt; conn->scanoff = cnt;
if (off + cnt == sizeof(conn->buf)) { if (off && off + cnt >= sizeof(conn->buf) - conn->readsz) {
memmove( conn->buf, conn->buf + off, cnt ); memmove( conn->buf, conn->buf + off, cnt );
conn->offset = 0; conn->offset = 0;
} }
@ -803,6 +805,12 @@ socket_fill( conn_t *sock )
if ((n = do_read( sock, buf, len )) <= 0) if ((n = do_read( sock, buf, len )) <= 0)
return; return;
// IIR filter for tracking average size of bulk reads.
// We use this to optimize the free space at the end of the
// buffer, hence the factor of 1.5.
if (n >= MIN_BULK_READ)
sock->readsz = (sock->readsz * 3 + n * 3 / 2) / 4;
socket_filled( sock, (uint)n ); socket_filled( sock, (uint)n );
} }
} }
@ -831,7 +839,7 @@ socket_expect_bytes( conn_t *conn, uint len )
if (off) { if (off) {
uint cnt = conn->bytes; uint cnt = conn->bytes;
if (off + len > sizeof(conn->buf) || if (off + len > sizeof(conn->buf) ||
off + cnt == sizeof(conn->buf)) { off + cnt >= sizeof(conn->buf) - conn->readsz) {
memmove( conn->buf, conn->buf + off, cnt ); memmove( conn->buf, conn->buf + off, cnt );
conn->offset = 0; conn->offset = 0;
} }

View File

@ -100,12 +100,16 @@ typedef struct {
uint bytes; /* number of filled bytes in buffer */ uint bytes; /* number of filled bytes in buffer */
uint scanoff; /* offset to continue scanning for newline at, relative to 'offset' */ uint scanoff; /* offset to continue scanning for newline at, relative to 'offset' */
uint wanted; // try to accumulate that many bytes before calling back; 0 => full line uint wanted; // try to accumulate that many bytes before calling back; 0 => full line
uint readsz; // average size of bulk reads from the underlying socket, times 1.5
char buf[100000]; char buf[100000];
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
char z_buf[100000]; char z_buf[100000];
#endif #endif
} conn_t; } conn_t;
// Shorter reads are assumed to be limited by round-trips.
#define MIN_BULK_READ 1000
/* call this before doing anything with the socket */ /* call this before doing anything with the socket */
static INLINE void socket_init( conn_t *conn, static INLINE void socket_init( conn_t *conn,
const server_conf_t *conf, const server_conf_t *conf,
@ -123,6 +127,7 @@ static INLINE void socket_init( conn_t *conn,
conn->name = NULL; conn->name = NULL;
conn->write_buf_append = &conn->write_buf; conn->write_buf_append = &conn->write_buf;
conn->wanted = 1; conn->wanted = 1;
conn->readsz = MIN_BULK_READ * 3 / 2;
} }
void socket_connect( conn_t *conn, void (*cb)( int ok, void *aux ) ); void socket_connect( conn_t *conn, void (*cb)( int ok, void *aux ) );
void socket_start_tls(conn_t *conn, void (*cb)( int ok, void *aux ) ); void socket_start_tls(conn_t *conn, void (*cb)( int ok, void *aux ) );