@matheusbsbs / matheus-bagliano / commits / 49de321698
Fork 0

grep: handle pre context lines on demand

Factor out pre context line handling into the new function show_pre_context() and change the algorithm to rewind by looking for newline characters and roll forward again, instead of maintaining an array of line beginnings and ends. This is slower for hits, but the cost for non-matching lines becomes zero. Normally, there are far more non-matching lines, so the time spent in total decreases. Before this patch (current Linux kernel repo, best of five runs): $ time git grep --no-ext-grep -B1 memset >/dev/null real 0m2.134s user 0m1.932s sys 0m0.196s $ time git grep --no-ext-grep -B1000 memset >/dev/null real 0m12.059s user 0m11.837s sys 0m0.224s The same with this patch: $ time git grep --no-ext-grep -B1 memset >/dev/null real 0m2.117s user 0m1.892s sys 0m0.228s $ time git grep --no-ext-grep -B1000 memset >/dev/null real 0m2.986s user 0m2.696s sys 0m0.288s Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx> Signed-off-by: Junio C Hamano <gitster@pobox.com>

René Scharfe committed Jul 2, 2009 at 00:05 UTC 49de3216983cc921ea66ade18a8521d4d74bbf3f
1 file changed +32 -29
grep.c
+32 -29
@@ -531,16 +531,42 @@ static void show_line(struct grep_opt *opt, char *bol, char *eol,
531 printf("%.*s\n", rest, bol);
532 }
533
534 +static void show_pre_context(struct grep_opt *opt, const char *name, char *buf,
535 + char *bol, unsigned lno)
536 +{
537 + unsigned cur = lno, from = 1;
538 +
539 + if (opt->pre_context < lno)
540 + from = lno - opt->pre_context;
541 + if (from <= opt->last_shown)
542 + from = opt->last_shown + 1;
543 +
544 + /* Rewind. */
545 + while (bol > buf && cur > from) {
546 + bol--;
547 + while (bol > buf && bol[-1] != '\n')
548 + bol--;
549 + cur--;
550 + }
551 +
552 + /* Back forward. */
553 + while (cur < lno) {
554 + char *eol = bol;
555 +
556 + while (*eol != '\n')
557 + eol++;
558 + show_line(opt, bol, eol, name, cur, '-');
559 + bol = eol + 1;
560 + cur++;
561 + }
562 +}
563 +
564 static int grep_buffer_1(struct grep_opt *opt, const char *name,
565 char *buf, unsigned long size, int collect_hits)
566 {
567 char *bol = buf;
568 unsigned long left = size;
569 unsigned lno = 1;
540 - struct pre_context_line {
541 - char *bol;
542 - char *eol;
543 - } *prev = NULL, *pcl;
570 unsigned last_hit = 0;
571 int binary_match_only = 0;
572 unsigned count = 0;
@@ -561,9 +587,6 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
587 }
588 }
589
564 - if (opt->pre_context)
565 - prev = xcalloc(opt->pre_context, sizeof(*prev));
566 -
590 while (left) {
591 char *eol, ch;
592 int hit;
@@ -610,21 +633,8 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
633 * the context which is nonsense, but the user
634 * deserves to get that ;-).
635 */
613 - if (opt->pre_context) {
614 - unsigned from;
615 - if (opt->pre_context < lno)
616 - from = lno - opt->pre_context;
617 - else
618 - from = 1;
619 - if (from <= opt->last_shown)
620 - from = opt->last_shown + 1;
621 - while (from < lno) {
622 - pcl = &prev[lno-from-1];
623 - show_line(opt, pcl->bol, pcl->eol,
624 - name, from, '-');
625 - from++;
626 - }
627 - }
636 + if (opt->pre_context)
637 + show_pre_context(opt, name, buf, bol, lno);
638 if (!opt->count)
639 show_line(opt, bol, eol, name, lno, ':');
640 last_hit = lno;
@@ -636,12 +646,6 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
646 */
647 show_line(opt, bol, eol, name, lno, '-');
648 }
639 - if (opt->pre_context) {
640 - memmove(prev+1, prev,
641 - (opt->pre_context-1) * sizeof(*prev));
642 - prev->bol = bol;
643 - prev->eol = eol;
644 - }
649
650 next_line:
651 bol = eol + 1;
@@ -651,7 +655,6 @@ static int grep_buffer_1(struct grep_opt *opt, const char *name,
655 lno++;
656 }
657
654 - free(prev);
658 if (collect_hits)
659 return 0;
660