История изменений
Исправление firkax, (текущая версия) :
Когда приведете сравнение хотя бы на двух, трех синтетических тестах, тогда и заходите.
Два теста мне лень делать, сделал один, самый тривиальный.
Взял много логов из десктопного /var/log (cat | gunzip архивные), повторил, вышел входной файл на 800мбайт. Положил его в tmpfs (иначе жёсткий диск портит чистоту теста), запустил такие команды (см.ниже).
Разница в скорости (user time) - в 6 раз (grep 1.48 сек, нормальный сканер 0.24 сек). Если даже добавить system time которое там было одинаковое в полсекунды - получается разница в скорости в 3 раза (0.7 против 2.0). Если добавить побольше парсерной логики - разница, очевидно, станет ещё больше, на особо сложных случаях может и в 100 раз. А если ещё вызовы всяких date и прочей чуши в баш-подпроцессах заменить на тупо выполняющиеся мгновенно функции, например для конвертации плохого формата даты в хороший - то даже не знаю.
gcc -O2 slow_grep_example.c
time grep "^Jun" < log0 > log1g
time ./a.out < log0 > log1m
diff log1g log1m
slow_grep_example.c:
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define READ_BUF_SIZE 131072
/*#define USE_FWRITE_BUF_SIZE 4096*/
/*#define MAX_READ 98304*/
static char buf[READ_BUF_SIZE];
static size_t bsz, pos;
static int state;
static int write_all(char const *b, size_t n) {
size_t c;
ssize_t r;
while(c=n) {
/* if(c>8192) c = 8192;*/
while(((ssize_t)c)<=0) c/=2;
while((r = write(1, b, c))<0) if(errno!=EINTR) return -1;
/* assert(r>0 && c>=(size_t)r); */
b += r; n -= r;
}
return 0;
}
#ifdef USE_FWRITE_BUF_SIZE
#define write_all(b,n) fwrite(b,1,n,stdout)
#endif
int main(void) {
ssize_t rsz;
size_t n;
char *b;
int nextstate;
#ifdef USE_FWRITE_BUF_SIZE
static char ob[USE_FWRITE_BUF_SIZE];
setbuffer(stdout,ob,sizeof(ob));
#endif
while(1) {
if(pos && bsz-pos<100) {
if(bsz -= pos) bcopy(buf+pos, buf, bsz);
pos = 0;
}
n = sizeof(buf)-bsz;
#ifdef MAX_READ
if(n>MAX_READ) n = MAX_READ;
#endif
while((rsz=read(0, buf+bsz, n))<0) if(errno!=EINTR) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); break; }
if(rsz<=0) break;
bsz += rsz;
if(!state) {
if(bsz-pos<3) continue;
if(buf[pos]=='J' && buf[pos+1]=='u' && buf[pos+2]=='n') state = 1;
else state = 2;
}
loop:
b = memchr(buf+pos, '\n', bsz-pos);
again:
if(!b) {
if(state==1 && write_all(buf+pos, bsz-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
bsz = pos = 0; continue;
}
n = b+1-buf;
if(bsz-n<3) nextstate = 0;
else if(buf[n]=='J' && buf[n+1]=='u' && buf[n+2]=='n') nextstate = 1;
else nextstate = 2;
#ifndef USE_FWRITE_BUF_SIZE
if(nextstate==state) { b = memchr(buf+n, '\n', bsz-n); goto again; }
#endif
if(state==1 && write_all(buf+pos, n-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
pos = n; state = nextstate;
if(state) goto loop;
}
return rsz?-1:0;
}
Исправление firkax, :
Когда приведете сравнение хотя бы на двух, трех синтетических тестах, тогда и заходите.
Два теста мне лень делать, сделал один, самый тривиальный.
Взял много логов из десктопного /var/log (cat | gunzip архивные), повторил, вышел входной файл на 800мбайт. Положил его в tmpfs (иначе жёсткий диск портит чистоту теста), запустил такие команды (см.ниже).
Разница в скорости (user time) - в 6 раз (grep 1.48 сек, нормальный сканер 0.24 сек). Если даже добавить system time которое там было одинаковое в полсекунды - получается разница в скорости в 3 раза (0.7 против 2.0). Если добавить побольше парсерной логики - разница, очевидно, станет ещё больше, на особо сложных случаях может и в 100 раз. А если ещё вызовы всяких date и прочей чуши в баш-подпроцессах заменить на тупо выполняющиеся мгновенно функции, например для конвертации плохого формата даты в хороший - то даже не знаю.
gcc -O2 slow_grep_example.c
time grep "^Jun" < log0 > log1g
time ./a.out < log0 > log1m
diff log1g log1m
slow_grep_example.c:
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define READ_BUF_SIZE 131072
/*#define USE_FWRITE_BUF_SIZE 4096*/
/*#define MAX_READ 98304*/
static char buf[READ_BUF_SIZE];
static size_t bsz, pos;
static int state;
static int write_all(char const *b, size_t n) {
size_t c;
ssize_t r;
while(c=n) {
if(c>8192) c = 8192;
while(((ssize_t)c)<=0) c/=2;
while((r = write(1, b, c))<0) if(errno!=EINTR) return -1;
/* assert(r>0 && c>=(size_t)r); */
b += r; n -= r;
}
return 0;
}
#ifdef USE_FWRITE_BUF_SIZE
#define write_all(b,n) fwrite(b,1,n,stdout)
#endif
int main(void) {
ssize_t rsz;
size_t n;
char *b;
int nextstate;
#ifdef USE_FWRITE_BUF_SIZE
static char ob[USE_FWRITE_BUF_SIZE];
setbuffer(stdout,ob,sizeof(ob));
#endif
while(1) {
if(pos && bsz-pos<100) {
if(bsz -= pos) bcopy(buf+pos, buf, bsz);
pos = 0;
}
n = sizeof(buf)-bsz;
#ifdef MAX_READ
if(n>MAX_READ) n = MAX_READ;
#endif
while((rsz=read(0, buf+bsz, n))<0) if(errno!=EINTR) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); break; }
if(rsz<=0) break;
bsz += rsz;
if(!state) {
if(bsz-pos<3) continue;
if(buf[pos]=='J' && buf[pos+1]=='u' && buf[pos+2]=='n') state = 1;
else state = 2;
}
loop:
b = memchr(buf+pos, '\n', bsz-pos);
again:
if(!b) {
if(state==1 && write_all(buf+pos, bsz-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
bsz = pos = 0; continue;
}
n = b+1-buf;
if(bsz-n<3) nextstate = 0;
else if(buf[n]=='J' && buf[n+1]=='u' && buf[n+2]=='n') nextstate = 1;
else nextstate = 2;
#ifndef USE_FWRITE_BUF_SIZE
if(nextstate==state) { b = memchr(buf+n, '\n', bsz-n); goto again; }
#endif
if(state==1 && write_all(buf+pos, n-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
pos = n; state = nextstate;
if(state) goto loop;
}
return rsz?-1:0;
}
Исходная версия firkax, :
Когда приведете сравнение хотя бы на двух, трех синтетических тестах, тогда и заходите.
Два теста мне лень делать, сделал один, самый тривиальный.
Взял много логов из десктопного /var/log (cat | gunzip архивные), повторил, вышел входной файл на 800мбайт. Положил его в tmpfs (иначе жёсткий диск портит чистоту теста), запустил такие команды (см.ниже).
Разница в скорости (user time) - в 6 раз (grep 1.48 сек, нормальный сканер 0.24 сек). Если даже добавить system time которое там было одинаковое в полсекунды - получается разница в скорости в 3 раза (0.7 против 2.0). Если добавить побольше парсерной логики - разница, очевидно, станет ещё больше, на особо сложных случаях может и в 100 раз.
gcc -O2 slow_grep_example.c
time grep "^Jun" < log0 > log1g
time ./a.out < log0 > log1m
diff log1g log1m
slow_grep_example.c:
#include <stdio.h>
#include <string.h>
#include <strings.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
#define READ_BUF_SIZE 131072
/*#define USE_FWRITE_BUF_SIZE 4096*/
/*#define MAX_READ 98304*/
static char buf[READ_BUF_SIZE];
static size_t bsz, pos;
static int state;
static int write_all(char const *b, size_t n) {
size_t c;
ssize_t r;
while(c=n) {
if(c>8192) c = 8192;
while(((ssize_t)c)<=0) c/=2;
while((r = write(1, b, c))<0) if(errno!=EINTR) return -1;
/* assert(r>0 && c>=(size_t)r); */
b += r; n -= r;
}
return 0;
}
#ifdef USE_FWRITE_BUF_SIZE
#define write_all(b,n) fwrite(b,1,n,stdout)
#endif
int main(void) {
ssize_t rsz;
size_t n;
char *b;
int nextstate;
#ifdef USE_FWRITE_BUF_SIZE
static char ob[USE_FWRITE_BUF_SIZE];
setbuffer(stdout,ob,sizeof(ob));
#endif
while(1) {
if(pos && bsz-pos<100) {
if(bsz -= pos) bcopy(buf+pos, buf, bsz);
pos = 0;
}
n = sizeof(buf)-bsz;
#ifdef MAX_READ
if(n>MAX_READ) n = MAX_READ;
#endif
while((rsz=read(0, buf+bsz, n))<0) if(errno!=EINTR) { fprintf(stderr, "read error %d (%s)\n", errno, strerror(errno)); break; }
if(rsz<=0) break;
bsz += rsz;
if(!state) {
if(bsz-pos<3) continue;
if(buf[pos]=='J' && buf[pos+1]=='u' && buf[pos+2]=='n') state = 1;
else state = 2;
}
loop:
b = memchr(buf+pos, '\n', bsz-pos);
again:
if(!b) {
if(state==1 && write_all(buf+pos, bsz-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
bsz = pos = 0; continue;
}
n = b+1-buf;
if(bsz-n<3) nextstate = 0;
else if(buf[n]=='J' && buf[n+1]=='u' && buf[n+2]=='n') nextstate = 1;
else nextstate = 2;
#ifndef USE_FWRITE_BUF_SIZE
if(nextstate==state) { b = memchr(buf+n, '\n', bsz-n); goto again; }
#endif
if(state==1 && write_all(buf+pos, n-pos)<0) { fprintf(stderr, "write error %d (%s)\n", errno, strerror(errno)); break; }
pos = n; state = nextstate;
if(state) goto loop;
}
return rsz?-1:0;
}