[OPTIM] halog: make fgets parse more bytes by blocks

By adding a "landing area" at the end of the buffer, it becomes safe to
parse more bytes at once. On 32-bit this makes fgets run about 4% faster
but it does not save anything on 64-bit.
This commit is contained in:
Willy Tarreau 2011-09-10 10:25:05 +02:00
parent e8c7ecc2dd
commit 31a02e9c5b
2 changed files with 17 additions and 11 deletions

View File

@ -58,7 +58,7 @@ static inline unsigned long long has_zero64(unsigned long long x)
#define FGETS2_BUFSIZE (256*1024) #define FGETS2_BUFSIZE (256*1024)
const char *fgets2(FILE *stream) const char *fgets2(FILE *stream)
{ {
static char buffer[FGETS2_BUFSIZE + 9]; // +9 to have zeroes past the end static char buffer[FGETS2_BUFSIZE + 68];
static char *end = buffer; static char *end = buffer;
static char *line = buffer; static char *line = buffer;
@ -73,7 +73,7 @@ const char *fgets2(FILE *stream)
* time. * time.
*/ */
if (next <= (end-12)) { if (next <= end) {
/* max 3 bytes tested here */ /* max 3 bytes tested here */
while ((((unsigned long)next) & 3) && *next != '\n') while ((((unsigned long)next) & 3) && *next != '\n')
next++; next++;
@ -115,8 +115,8 @@ const char *fgets2(FILE *stream)
if (!has_zero(*(unsigned int *)next ^ 0x0A0A0A0AU)) if (!has_zero(*(unsigned int *)next ^ 0x0A0A0A0AU))
next += 4; next += 4;
/* we finish if needed. Note that next might be slightly higher /* We finish if needed : if <next> is below <end>, it means we
* than end here because we might have gone past it above. * found an LF in one of the 4 following bytes.
*/ */
while (next < end) { while (next < end) {
if (*next == '\n') { if (*next == '\n') {
@ -131,7 +131,8 @@ const char *fgets2(FILE *stream)
/* we found an incomplete line. First, let's move the /* we found an incomplete line. First, let's move the
* remaining part of the buffer to the beginning, then * remaining part of the buffer to the beginning, then
* try to complete the buffer with a new read. * try to complete the buffer with a new read. We can't
* rely on <next> anymore because it went past <end>.
*/ */
if (line > buffer) { if (line > buffer) {
if (end != line) if (end != line)
@ -156,6 +157,7 @@ const char *fgets2(FILE *stream)
} }
end += ret; end += ret;
*end = '\n'; /* make parser stop ASAP */
/* search for '\n' again */ /* search for '\n' again */
} }
} }

View File

@ -47,7 +47,7 @@ static inline unsigned int has_zero(unsigned int x)
#define FGETS2_BUFSIZE (256*1024) #define FGETS2_BUFSIZE (256*1024)
const char *fgets2(FILE *stream) const char *fgets2(FILE *stream)
{ {
static char buffer[FGETS2_BUFSIZE + 5]; static char buffer[FGETS2_BUFSIZE + 32];
static char *end = buffer; static char *end = buffer;
static char *line = buffer; static char *line = buffer;
@ -64,8 +64,10 @@ const char *fgets2(FILE *stream)
while (next < end && (((unsigned long)next) & 3) && *next != '\n') while (next < end && (((unsigned long)next) & 3) && *next != '\n')
next++; next++;
/* now next is multiple of 4 or equal to end */ /* Now next is multiple of 4 or equal to end. We know we can safely
while (next <= (end-32)) { * read up to 32 bytes past end if needed because they're allocated.
*/
while (next < end) {
if (has_zero(*(unsigned int *)next ^ 0x0A0A0A0A)) if (has_zero(*(unsigned int *)next ^ 0x0A0A0A0A))
break; break;
next += 4; next += 4;
@ -92,8 +94,8 @@ const char *fgets2(FILE *stream)
next += 4; next += 4;
} }
/* we finish if needed. Note that next might be slightly higher /* We finish if needed : if <next> is below <end>, it means we
* than end here because we might have gone past it above. * found an LF in one of the 4 following bytes.
*/ */
while (next < end) { while (next < end) {
if (*next == '\n') { if (*next == '\n') {
@ -108,7 +110,8 @@ const char *fgets2(FILE *stream)
/* we found an incomplete line. First, let's move the /* we found an incomplete line. First, let's move the
* remaining part of the buffer to the beginning, then * remaining part of the buffer to the beginning, then
* try to complete the buffer with a new read. * try to complete the buffer with a new read. We can't
* rely on <next> anymore because it went past <end>.
*/ */
if (line > buffer) { if (line > buffer) {
if (end != line) if (end != line)
@ -133,6 +136,7 @@ const char *fgets2(FILE *stream)
} }
end += ret; end += ret;
*end = '\n'; /* make parser stop ASAP */
/* search for '\n' again */ /* search for '\n' again */
} }
} }