mirror of
git://git.gnupg.org/gnupg.git
synced 2025-01-08 12:44:23 +01:00
iobuf: add zerocopy optimization for iobuf_write
* common/iobuf.c (filter_flush): Use 'iobuf->e_d' if configured. (iobuf_write): Configure 'iobuf->e_d' for 'filter_flush' if 'iobuf->d.buf' is empty and external buffer is larger than threshold. -- Zero-copy operation in iobuf_write() and filter_flush() allow bypassing 'iobuf->d.buf' for greater performance. This mainly helps OCB performance where additional memory copies through iobuf stack can take significant portion of program time. GnuPG-bug-id: T5828 Signed-off-by: Jussi Kivilinna <jussi.kivilinna@iki.fi>
This commit is contained in:
parent
15df88d135
commit
b96eb6f08d
@ -2052,9 +2052,14 @@ underflow_target (iobuf_t a, int clear_pending_eof, size_t target)
|
|||||||
static int
|
static int
|
||||||
filter_flush (iobuf_t a)
|
filter_flush (iobuf_t a)
|
||||||
{
|
{
|
||||||
|
int external_used = 0;
|
||||||
|
byte *src_buf;
|
||||||
|
size_t src_len;
|
||||||
size_t len;
|
size_t len;
|
||||||
int rc;
|
int rc;
|
||||||
|
|
||||||
|
a->e_d.used = 0;
|
||||||
|
|
||||||
if (a->use == IOBUF_OUTPUT_TEMP)
|
if (a->use == IOBUF_OUTPUT_TEMP)
|
||||||
{ /* increase the temp buffer */
|
{ /* increase the temp buffer */
|
||||||
size_t newsize = a->d.size + iobuf_buffer_size;
|
size_t newsize = a->d.size + iobuf_buffer_size;
|
||||||
@ -2071,9 +2076,31 @@ filter_flush (iobuf_t a)
|
|||||||
log_bug ("flush on non-output iobuf\n");
|
log_bug ("flush on non-output iobuf\n");
|
||||||
else if (!a->filter)
|
else if (!a->filter)
|
||||||
log_bug ("filter_flush: no filter\n");
|
log_bug ("filter_flush: no filter\n");
|
||||||
len = a->d.len;
|
|
||||||
rc = a->filter (a->filter_ov, IOBUFCTRL_FLUSH, a->chain, a->d.buf, &len);
|
if (a->d.len == 0 && a->e_d.buf && a->e_d.len > 0)
|
||||||
if (!rc && len != a->d.len)
|
{
|
||||||
|
src_buf = a->e_d.buf;
|
||||||
|
src_len = a->e_d.len;
|
||||||
|
external_used = 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
src_buf = a->d.buf;
|
||||||
|
src_len = a->d.len;
|
||||||
|
external_used = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_len == 0)
|
||||||
|
{
|
||||||
|
if (DBG_IOBUF)
|
||||||
|
log_debug ("filter_flush, nothing to flush%s\n",
|
||||||
|
external_used ? " (external buffer)" : "");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
len = src_len;
|
||||||
|
rc = a->filter (a->filter_ov, IOBUFCTRL_FLUSH, a->chain, src_buf, &len);
|
||||||
|
if (!rc && len != src_len)
|
||||||
{
|
{
|
||||||
log_info ("filter_flush did not write all!\n");
|
log_info ("filter_flush did not write all!\n");
|
||||||
rc = GPG_ERR_INTERNAL;
|
rc = GPG_ERR_INTERNAL;
|
||||||
@ -2081,6 +2108,8 @@ filter_flush (iobuf_t a)
|
|||||||
else if (rc)
|
else if (rc)
|
||||||
a->error = rc;
|
a->error = rc;
|
||||||
a->d.len = 0;
|
a->d.len = 0;
|
||||||
|
if (external_used)
|
||||||
|
a->e_d.used = len;
|
||||||
|
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
@ -2303,11 +2332,37 @@ iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
a->e_d.buf = NULL;
|
||||||
|
a->e_d.len = 0;
|
||||||
|
|
||||||
|
/* Hint for how full to fill iobuf internal drain buffer. */
|
||||||
|
a->e_d.preferred = (buflen >= IOBUF_ZEROCOPY_THRESHOLD_SIZE);
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
if (buflen && a->d.len < a->d.size)
|
if (a->d.len == 0 && buflen >= IOBUF_ZEROCOPY_THRESHOLD_SIZE)
|
||||||
{
|
{
|
||||||
unsigned size = a->d.size - a->d.len;
|
/* Setup external drain buffer for faster moving of data
|
||||||
|
* (avoid memcpy). */
|
||||||
|
a->e_d.buf = (byte *)buf;
|
||||||
|
a->e_d.len = buflen / IOBUF_ZEROCOPY_THRESHOLD_SIZE
|
||||||
|
* IOBUF_ZEROCOPY_THRESHOLD_SIZE;
|
||||||
|
if (a->e_d.len == 0)
|
||||||
|
a->e_d.buf = NULL;
|
||||||
|
if (a->e_d.buf && DBG_IOBUF)
|
||||||
|
log_debug ("iobuf-%d.%d: writing from external buffer, %lu bytes\n",
|
||||||
|
a->no, a->subno, (ulong)a->e_d.len);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (a->e_d.buf == NULL && buflen && a->d.len < a->d.size)
|
||||||
|
{
|
||||||
|
unsigned size;
|
||||||
|
|
||||||
|
if (a->e_d.preferred && a->d.len < IOBUF_ZEROCOPY_THRESHOLD_SIZE)
|
||||||
|
size = IOBUF_ZEROCOPY_THRESHOLD_SIZE - a->d.len;
|
||||||
|
else
|
||||||
|
size = a->d.size - a->d.len;
|
||||||
|
|
||||||
if (size > buflen)
|
if (size > buflen)
|
||||||
size = buflen;
|
size = buflen;
|
||||||
memcpy (a->d.buf + a->d.len, buf, size);
|
memcpy (a->d.buf + a->d.len, buf, size);
|
||||||
@ -2315,13 +2370,27 @@ iobuf_write (iobuf_t a, const void *buffer, unsigned int buflen)
|
|||||||
buf += size;
|
buf += size;
|
||||||
a->d.len += size;
|
a->d.len += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (buflen)
|
if (buflen)
|
||||||
{
|
{
|
||||||
rc = filter_flush (a);
|
rc = filter_flush (a);
|
||||||
if (rc)
|
if (rc)
|
||||||
|
{
|
||||||
|
a->e_d.buf = NULL;
|
||||||
|
a->e_d.len = 0;
|
||||||
return rc;
|
return rc;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (a->e_d.buf && a->e_d.used > 0)
|
||||||
|
{
|
||||||
|
buf += a->e_d.used;
|
||||||
|
buflen -= a->e_d.used;
|
||||||
|
}
|
||||||
|
|
||||||
|
a->e_d.buf = NULL;
|
||||||
|
a->e_d.len = 0;
|
||||||
|
}
|
||||||
while (buflen);
|
while (buflen);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user