Mit Axel und Frank kam ich
auf Gits eigenes grep
zu sprechen. Warum wird die Funktionalität da
gedoppelt und neu programmiert?
Ein Auszug meiner Antwortmail an die beiden, für das Blog mit Links angereichert:
Im wesentlichen leistet git-grep das gleiche wie grep auf allen verwalteten Dateien. ABER es ist, und das war m.E. die Hauptmotivation dahinter, es überhaupt zu schreiben, viel schneller als reguläres grep. (Und reguläres grep zu schlagen ist ja bekanntermaßen schon schwer.)
Zum Beispiel, wenn man im Kernel-Tree greppt. (Alle Kommandos mehrfach ausgeführt, so dass der Cache voll ist.)
$ time grep foo -- **/*.c NO grep foo -- **/*.c &>| /dev/null 17.67s user 0.22s system 99% cpu 17.928 total $ time git grep foo -- **/*.c NO git grep foo -- **/*.c &>| /dev/null 6.17s user 0.31s system 109% cpu 5.888 total
Viel beeindruckender wird es noch, wenn man für git-grep das Globbing-Muster erst gar nicht angibt.
$ time git grep foo NO git grep foo &>| /dev/null 0.66s user 0.30s system 342% cpu 0.281 total
Oder alternativ ein Globbing-Muster angibt, das aber nicht erst von der Shell expandieren lässt:
$ time git grep foo -- '*.c' NO git grep foo -- '*.c' &>| /dev/null 0.46s user 0.16s system 300% cpu 0.208 total
Also noch mal zusammengefasst: Wenn ich in allen C-Dateien nach "foo" greppe, bin ich mit der Git-Version auf meinem System 17.9/0.208 = 86.05 mal so schnell wie reguläres grep. Anders ausgedrückt: Das eine Kommando dauert, das andere ist fast "sofort da".
Wie das geht? Im wesentlichen ist das auf Multithreading zurückzuführen. (Sieht man ja auch an den CPU-Zahlen: grep bei ca. 100% = eine CPU, git-grep bei >300% = drei CPUs.)
Im Mutltithreading-Modus von git-grep gibt es den Haupt-Thread, der einfach alle Blobs einsammelt, die überprüft werden sollen, und die an acht Threads weitergibt, die dann entsprechend asynchron die Matches durchschauen können, aber trozdem alles in einer sinnvollen Reihenfolge ausgeben. (Details: builtin/grep.c)