OPTIM: channel: speed up co_getline()'s search of the end of line

Previously, co_getline() was essentially used for occasional parsing
in peers's banner or Lua, so it could afford to read one character at
a time. However now it's also used on the TCP log path, where it can
consume up to 40% CPU as mentioned in GH issue #2731. Let's speed it
up by using memchr() to look for the LF, and copying the data at once
using memcpy().

Previously it would take 2.44s to consume 1 GB of log on a single
thread of a Core i7-8650U, now it takes 1.56s (-36%).
This commit is contained in:
Willy Tarreau 2024-09-30 11:19:20 +02:00
parent 7caf073faa
commit 11051ed9c7

View File

@ -324,7 +324,7 @@ int co_getword(const struct channel *chn, char *str, int len, char sep)
int co_getline(const struct channel *chn, char *str, int len)
{
int ret, max;
char *p;
size_t ofs;
ret = 0;
max = len;
@ -336,20 +336,30 @@ int co_getline(const struct channel *chn, char *str, int len)
goto out;
}
p = co_head(chn);
if (max > co_data(chn)) {
max = co_data(chn);
str[max-1] = 0;
}
while (max) {
*str++ = *p;
ret++;
max--;
if (*p == '\n')
ofs = 0;
while (max) {
size_t contig = b_contig_data(&chn->buf, ofs);
size_t len = MIN(max, contig);
const char *beg = b_peek(&chn->buf, ofs);
const char *lf = memchr(beg, '\n', len);
if (lf) /* take the LF with it before stopping */
len = lf + 1 - beg;
memcpy(str, beg, len);
ret += len;
str += len;
ofs += len;
max -= len;
if (lf)
break;
p = b_next(&chn->buf, p);
}
if (ret > 0 && ret < len &&
(ret < co_data(chn) || channel_may_recv(chn)) &&