LINUX.ORG.RU

История изменений

Исправление 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;
}