grep: replace the internal queue with a ring buffer
We know up front how many items we can have in the queue (-B/Bflag), so pay the cost of those particular allocations early on. The reduced queue maintenance overhead seemed to yield about an ~8% improvement for my earlier `grep -C8 -r closefrom .` test. MFC after: 2 weeks
This commit is contained in:
parent
281412ce7b
commit
df546c3b73
@ -707,6 +707,8 @@ main(int argc, char *argv[])
|
|||||||
if ((aargc == 0 || aargc == 1) && !Hflag)
|
if ((aargc == 0 || aargc == 1) && !Hflag)
|
||||||
hflag = true;
|
hflag = true;
|
||||||
|
|
||||||
|
initqueue();
|
||||||
|
|
||||||
if (aargc == 0 && dirbehave != DIR_RECURSE)
|
if (aargc == 0 && dirbehave != DIR_RECURSE)
|
||||||
exit(!procfile("-"));
|
exit(!procfile("-"));
|
||||||
|
|
||||||
|
@ -149,6 +149,7 @@ char *grep_strdup(const char *str);
|
|||||||
void grep_printline(struct str *line, int sep);
|
void grep_printline(struct str *line, int sep);
|
||||||
|
|
||||||
/* queue.c */
|
/* queue.c */
|
||||||
|
void initqueue(void);
|
||||||
bool enqueue(struct str *x);
|
bool enqueue(struct str *x);
|
||||||
void printqueue(void);
|
void printqueue(void);
|
||||||
void clearqueue(void);
|
void clearqueue(void);
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
*
|
*
|
||||||
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
|
* Copyright (c) 1999 James Howard and Dag-Erling Coïdan Smørgrav
|
||||||
* All rights reserved.
|
* All rights reserved.
|
||||||
|
* Copyright (c) 2020 Kyle Evans <kevans@FreeBSD.org>
|
||||||
*
|
*
|
||||||
* Redistribution and use in source and binary forms, with or without
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -45,15 +46,33 @@ __FBSDID("$FreeBSD$");
|
|||||||
|
|
||||||
#include "grep.h"
|
#include "grep.h"
|
||||||
|
|
||||||
struct qentry {
|
typedef struct str qentry_t;
|
||||||
STAILQ_ENTRY(qentry) list;
|
|
||||||
struct str data;
|
|
||||||
};
|
|
||||||
|
|
||||||
static STAILQ_HEAD(, qentry) queue = STAILQ_HEAD_INITIALIZER(queue);
|
static long long filled;
|
||||||
static long long count;
|
static qentry_t *qend, *qpool;
|
||||||
|
|
||||||
static struct qentry *dequeue(void);
|
/*
|
||||||
|
* qnext is the next entry to populate. qlist is where the list actually
|
||||||
|
* starts, for the purposes of printing.
|
||||||
|
*/
|
||||||
|
static qentry_t *qlist, *qnext;
|
||||||
|
|
||||||
|
void
|
||||||
|
initqueue(void)
|
||||||
|
{
|
||||||
|
|
||||||
|
qlist = qnext = qpool = grep_calloc(Bflag, sizeof(*qpool));
|
||||||
|
qend = qpool + (Bflag - 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static qentry_t *
|
||||||
|
advqueue(qentry_t *itemp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if (itemp == qend)
|
||||||
|
return (qpool);
|
||||||
|
return (itemp + 1);
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Enqueue another line; return true if we've dequeued a line as a result
|
* Enqueue another line; return true if we've dequeued a line as a result
|
||||||
@ -61,61 +80,65 @@ static struct qentry *dequeue(void);
|
|||||||
bool
|
bool
|
||||||
enqueue(struct str *x)
|
enqueue(struct str *x)
|
||||||
{
|
{
|
||||||
struct qentry *item;
|
qentry_t *item;
|
||||||
|
bool rotated;
|
||||||
|
|
||||||
item = grep_malloc(sizeof(struct qentry));
|
item = qnext;
|
||||||
item->data.dat = grep_malloc(sizeof(char) * x->len);
|
qnext = advqueue(qnext);
|
||||||
item->data.len = x->len;
|
rotated = false;
|
||||||
item->data.line_no = x->line_no;
|
|
||||||
item->data.boff = x->boff;
|
|
||||||
item->data.off = x->off;
|
|
||||||
memcpy(item->data.dat, x->dat, x->len);
|
|
||||||
item->data.file = x->file;
|
|
||||||
|
|
||||||
STAILQ_INSERT_TAIL(&queue, item, list);
|
if (filled < Bflag) {
|
||||||
|
filled++;
|
||||||
if (++count > Bflag) {
|
} else if (filled == Bflag) {
|
||||||
item = dequeue();
|
/* We had already filled up coming in; just rotate. */
|
||||||
free(item->data.dat);
|
qlist = advqueue(qlist);
|
||||||
free(item);
|
rotated = true;
|
||||||
return (true);
|
free(item->dat);
|
||||||
}
|
}
|
||||||
return (false);
|
item->dat = grep_malloc(sizeof(char) * x->len);
|
||||||
}
|
item->len = x->len;
|
||||||
|
item->line_no = x->line_no;
|
||||||
|
item->boff = x->boff;
|
||||||
|
item->off = x->off;
|
||||||
|
memcpy(item->dat, x->dat, x->len);
|
||||||
|
item->file = x->file;
|
||||||
|
|
||||||
static struct qentry *
|
return (rotated);
|
||||||
dequeue(void)
|
|
||||||
{
|
|
||||||
struct qentry *item;
|
|
||||||
|
|
||||||
item = STAILQ_FIRST(&queue);
|
|
||||||
if (item == NULL)
|
|
||||||
return (NULL);
|
|
||||||
|
|
||||||
STAILQ_REMOVE_HEAD(&queue, list);
|
|
||||||
--count;
|
|
||||||
return (item);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
printqueue(void)
|
printqueue(void)
|
||||||
{
|
{
|
||||||
struct qentry *item;
|
qentry_t *item;
|
||||||
|
|
||||||
while ((item = dequeue()) != NULL) {
|
item = qlist;
|
||||||
grep_printline(&item->data, '-');
|
do {
|
||||||
free(item->data.dat);
|
/* Buffer must have ended early. */
|
||||||
free(item);
|
if (item->dat == NULL)
|
||||||
}
|
break;
|
||||||
|
|
||||||
|
grep_printline(item, '-');
|
||||||
|
free(item->dat);
|
||||||
|
item->dat = NULL;
|
||||||
|
item = advqueue(item);
|
||||||
|
} while (item != qlist);
|
||||||
|
|
||||||
|
qlist = qnext = qpool;
|
||||||
|
filled = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
clearqueue(void)
|
clearqueue(void)
|
||||||
{
|
{
|
||||||
struct qentry *item;
|
qentry_t *item;
|
||||||
|
|
||||||
while ((item = dequeue()) != NULL) {
|
item = qlist;
|
||||||
free(item->data.dat);
|
do {
|
||||||
free(item);
|
free(item->dat);
|
||||||
}
|
item->dat = NULL;
|
||||||
|
item = advqueue(item);
|
||||||
|
} while (item != qlist);
|
||||||
|
|
||||||
|
qlist = qnext = qpool;
|
||||||
|
filled = 0;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user