5 poin oleh GN⁺ 2023-12-01 | 1 komentar | Bagikan ke WhatsApp
  • ripgrep (rg) adalah alat pencarian baris perintah berbasis Rust yang menggabungkan kenyamanan pencarian kode ala The Silver Searcher dengan performa mentah setara GNU grep, dan menyediakan biner untuk Linux, Mac, dan Windows
  • Dalam 25 benchmark, tidak ada alat yang secara jelas mengungguli ripgrep dalam performa maupun akurasi, baik untuk pencarian pada satu file besar maupun direktori berskala besar; biaya dukungan Unicode juga tetap kecil
  • Dengan pemrosesan .gitignore, pengecualian default untuk file tersembunyi dan biner, filter tipe file, dukungan opsional PCRE2, pencarian berbagai encoding dan file terkompresi, hingga filter prapemrosesan, alat ini memperluas cakupan penggunaan praktis alat pencarian kode
  • Perbedaan eksperimen pada repositori kernel Linux dan OpenSubtitles2016 sangat dipengaruhi oleh optimasi literal, pencarian multi-pola SIMD Teddy, Aho-Corasick, metode decoding UTF-8, penghitungan baris, dan biaya pemrosesan .gitignore
  • Saat mencari banyak file kecil secara paralel, memory map bisa menjadi lebih lambat, sedangkan pada satu file besar bisa menguntungkan; karena itu ripgrep menggunakan pencarian dengan buffer perantara dan pencarian memory map secara terpisah sesuai situasi

Posisi yang dituju ripgrep

  • ripgrep adalah alat pencarian baris perintah yang menargetkan sekaligus kenyamanan alat pencarian kode dan performa alat sejenis grep
  • Pembandingnya adalah GNU grep, git grep, The Silver Searcher (ag), Universal Code Grep (ucg), The Platinum Searcher (pt), dan sift
  • Inti yang ingin diverifikasi benchmark ada tiga
    • Tidak ada alat yang secara jelas lebih unggul daripada ripgrep, baik dalam pencarian satu file maupun direktori berskala besar
    • Menyediakan dukungan Unicode dengan benar tanpa menuntut biaya performa besar
    • Saat mencari banyak file sekaligus, memory map umumnya bisa menjadi lebih lambat, bukan lebih cepat
  • Penulis adalah pembuat ripgrep dan engine regular expression yang mendasarinya, serta menyatakan bahwa benchmark dapat dipilih secara selektif dan memiliki bias

Fitur dan perilaku default

  • Nama file executable ripgrep adalah rg
  • Pencarian default menjelajahi direktori saat ini secara rekursif, menghormati .gitignore, serta melewati file tersembunyi dan file biner
  • .rgignore juga didukung, dan pola .rgignore memiliki prioritas di atas .gitignore
  • Dengan -u, -uu, dan -uuu, cakupan dapat diperluas untuk mengabaikan file ignore, menyertakan file tersembunyi, dan menyertakan file biner
    • rg -uuu mirip dengan grep -a -r
  • Mendukung filter tipe file
    • rg -tpy foo: hanya mencari file Python
    • rg -Tjs foo: mengecualikan file JavaScript
    • Aturan tipe file baru dapat ditambahkan dengan --type-add
  • Berbagai fitur grep juga disediakan
    • Output konteks
    • Pencarian beberapa pola
    • Highlight warna
    • Dukungan Unicode penuh
  • Engine regular expression default tidak mendukung look-around dan backreference, tetapi jika engine PCRE2 dipilih dengan -P, fitur tersebut dapat digunakan
  • Juga mendukung deteksi otomatis sebagian UTF-16 dan penetapan encoding berbasis -E/--encoding
    • Termasuk UTF-16, latin-1, GBK, EUC-JP, Shift_JIS, dan lainnya
  • Dengan -z/--search-zip, mendukung pencarian file terkompresi seperti gzip, xz, lzma, bzip2, dan lz4
  • Juga mendukung filter prapemrosesan arbitrer seperti ekstraksi teks PDF, dekompresi tambahan, dekripsi, dan deteksi encoding otomatis

Alasan untuk tidak menggunakannya

  • Jika portabilitas dan ketersediaan di mana saja adalah prioritas utama, grep yang sesuai standar dan terpasang luas lebih cocok
  • Jika bergantung pada fitur tertentu atau bug yang ada di alat lain, ripgrep mungkin tidak cocok
  • Dalam beberapa kasus edge performa, alat lain bisa bekerja lebih baik
  • Jika tidak dapat diinstal atau tidak ada dukungan platform, alat ini juga tidak bisa digunakan

Struktur kerja alat sejenis grep

  • Alat pencarian secara garis besar melalui tiga tahap
    • Mengumpulkan file yang akan dicari
    • Melakukan pencarian sebenarnya
    • Menampilkan hasil
  • Karena alat sejenis grep harus mampu mencari file besar dengan baik, performa engine regular expression menjadi penting
  • Alat sejenis ack harus memproses penjelajahan direktori rekursif dan penerapan aturan ignore seperti .gitignore dengan cepat
  • ripgrep mencoba menggabungkan kedua pendekatan tersebut
    • Engine regular expression yang cepat
    • Pencarian paralel
    • Pemfilteran target pencarian

Pengumpulan file dan pemrosesan ignore

  • Pada alat sejenis ack, penting untuk cepat menentukan file mana di direktori saat ini yang akan dicari
  • Performa traversal direktori dipengaruhi oleh jumlah panggilan stat yang tidak perlu
  • ripgrep menggunakan iterator direktori rekursif yang bertujuan meminimalkan system call
  • Pemrosesan .gitignore memiliki biaya
    • Harus mencari file ignore di setiap direktori
    • Harus mengompilasi pola ignore
    • Harus menerapkan pola ke semua kandidat path
  • Repositori kernel Linux memiliki 4.640 direktori dan 178 file .gitignore
  • ripgrep berupaya mendukung semantik .gitignore secara lebih lengkap, dan memberi prioritas pada pola cocok yang didefinisikan paling baru
  • ucg bisa lebih cepat karena menggunakan aturan glob berbasis whitelist alih-alih .gitignore, tetapi dapat melewatkan file dengan ekstensi yang tidak dikenal

Perbedaan engine regular expression

  • Engine regular expression secara umum terbagi menjadi dua jenis
    • Berbasis backtracking: kaya fitur, tetapi pada input tertentu bisa melambat hingga waktu eksponensial
    • Berbasis finite automata: fiturnya bisa terbatas, tetapi memberikan jaminan waktu linear terhadap panjang teks yang dicari
  • Engine per alat adalah sebagai berikut
    • GNU grep, git grep: engine internal berbasis finite automata
    • ripgrep: library regex Rust, berbasis finite automata
    • ag, ucg: berbasis PCRE dengan backtracking
    • pt, sift: library regex Go, berbasis finite automata
  • ag dan ucg dapat terekspos pada perilaku backtracking kasus terburuk karena penggunaan PCRE
  • Pola contoh (a*)* c dapat menimbulkan masalah pada alat berbasis PCRE, tetapi alat pembanding benchmark lainnya menanganinya tanpa masalah

Optimasi literal dan SIMD

  • Dalam pencarian string sederhana, optimasi pencarian literal bisa menjadi lebih penting daripada engine regular expression
  • Boyer-Moore adalah algoritme pencarian substring klasik, dan dapat memanfaatkan rutin seperti memchr untuk menemukan posisi kandidat dengan cepat
  • Implementasi memchr sering memeriksa 16 byte sekaligus dengan instruksi SIMD, dan dapat mencapai throughput beberapa GB/detik
  • Library regex Rust secara agresif mengekstrak literal prefix dan suffix dari pola
    • foo|bar
    • (a|b)c
    • [ab]foo[yz]
    • (foo)?bar
    • (foo)*bar
    • (foo){3,6}
  • Jika seluruh regular expression dapat diurai menjadi satu literal atau alternation literal, engine regular expression inti sama sekali bisa tidak digunakan
  • ripgrep juga mengekstrak inner literal dengan memanfaatkan karakteristik output hasil per baris
    • Contoh: pada \w+foo\d+, temukan foo terlebih dahulu lalu verifikasi hanya baris kandidat dengan regular expression
  • Untuk pencarian beberapa literal, GNU grep menggunakan algoritme mirip Commentz-Walter, sedangkan regex Rust menggunakan algoritme Aho-Corasick atau Teddy SIMD
  • Teddy adalah algoritme pencarian multi-pola berbasis SIMD yang berasal dari Intel Hyperscan, dan merupakan salah satu optimasi utama yang membuat ripgrep mengungguli GNU grep

Metode pencarian: menghindari pencarian per baris

  • Implementasi naif membaca file baris demi baris dan menerapkan pola pada tiap baris, tetapi pada sebagian besar pencarian, match jarang terjadi sehingga ini tidak efisien
  • Alat pencarian biasanya mencari buffer byte besar sekaligus
    • Memetakan file dengan memory map
    • Membaca seluruh file ke memori
    • Melakukan pencarian bertahap dengan buffer perantara berukuran tetap
  • ripgrep, GNU grep, dan git grep mendukung pencarian bertahap sehingga dapat diterapkan baik pada file maupun stream
  • Pencarian bertahap sulit diimplementasikan
    • Menghitung nomor baris
    • Menangani kasus ketika buffer berakhir di tengah baris
    • Menangani baris panjang
    • Menangani invert match
    • Menangani output konteks di sekitar match
  • ripgrep menggunakan pencarian bertahap meskipun kompleks secara implementasi, dan dalam benchmark menunjukkan hasil lebih cepat daripada memory map saat mencari banyak file kecil

Output dan paralelisme

  • Dalam pencarian paralel, jika setiap thread langsung menulis output, hasil dari file yang berbeda bisa tercampur
  • Semua alat pencarian kode paralel menulis hasil pencarian ke buffer perantara di memori, lalu hanya tahap output yang diserialkan
  • Cara ini memungkinkan thread pencarian menjalankan pencarian sebenarnya secara paralel
  • Kekurangannya, penggunaan memori bisa menjadi besar pada kasus seperti file 2GB yang setiap barisnya cocok
  • ripgrep menulis langsung ke stdout tanpa buffer perantara saat mencari dari stdin atau satu file

Metodologi benchmark

  • Benchmark dibagi berdasarkan masalah pengguna akhir
    • Pencarian repositori kode berskala besar
    • Pencarian satu file berukuran besar
  • Pola pencarian cenderung berfokus pada literal sederhana, alternation, dan regex ringan
  • Karena perilaku default tiap alat berbeda, kondisi seperti nomor baris, Unicode, .gitignore, dan whitelist coba diselaraskan untuk perbandingan yang adil
  • Versi yang menjadi target benchmark adalah sebagai berikut
    • ripgrep v0.1.2
    • GNU grep v2.25
    • git grep v2.7.4
    • commit ag cda635, PCRE 8.38
    • commit ucg 487bfb, PCRE 10.21 JIT
    • commit pt 509368
    • commit sift 2d175c
  • ack dikecualikan karena saat itu jauh lebih lambat daripada alat lain
  • Runner benchmark adalah benchsuite yang membutuhkan Python 3.5 atau lebih baru, dan disertakan dalam repositori ripgrep
  • Setiap perintah menjalankan warm-up 3 kali sebelum pengukuran agar korpus masuk ke OS page cache
  • Setiap perintah diukur 10 kali, lalu rata-rata dan simpangan bakunya dicatat
  • Lingkungan eksekusi adalah Amazon EC2 c3.2xlarge, Ubuntu 16.04, Xeon E5-2680 2.8GHz, memori 16GB, SSD 80GB
  • Log konfigurasi, hasil ringkasan, dan CSV mentah juga dipublikasikan

Hasil pencarian kode kernel Linux

  • Benchmark pencarian kode dijalankan pada repositori kernel Linux yang sudah dibangun, commit d0acc7
  • Alasan memakai repositori kernel yang sudah dibangun adalah karena artefak build yang tertinggal di repositori dapat memengaruhi relevansi hasil pencarian dan performa
  • Pada linux_literal_default, pencarian literal sederhana PM_RESUME memperlihatkan perbedaan perilaku default tiap alat
    • rg menghormati .gitignore dan melewati file tersembunyi serta biner
    • ag dan pt juga serupa, tetapi menghitung jumlah baris
    • ucg tidak membaca .gitignore dan melakukan pencarian berbasis whitelist
    • sift secara default mencari hampir semuanya
    • git grep memiliki keuntungan karena memperoleh kumpulan file pencarian dari git index
  • Menghormati .gitignore meningkatkan relevansi hasil, tetapi bisa menimbulkan biaya performa
  • Pada linux_literal, rg (whitelist) menunjukkan performa yang hampir sama dengan ucg, sedangkan rg (ignore) berada pada level yang mirip dengan git grep
  • rg (ignore) (mmap) dan ag (ignore) (mmap) menjadi lebih lambat karena penggunaan memory map, dan dalam kondisi yang sama rg (ignore) jauh lebih cepat
  • Di mesin lokal pun versi memory map lebih lambat, tetapi selisihnya lebih kecil dibandingkan di EC2

Unicode dan pencarian case-insensitive

  • Pada linux_literal_casei, pt menjadi jauh lebih lambat karena memproses -i sebagai (?i) di Go regexp
  • sift tidak terlalu melambat karena memakai cara mengubah pola dan blok pencarian menjadi huruf kecil, tetapi optimasi ini hanya menangani kapitalisasi ASCII sehingga tidak akurat untuk penanganan kapitalisasi Unicode
  • ripgrep mengubah pencarian case-insensitive menjadi kombinasi literal bila memungkinkan, lalu memakai Teddy untuk menemukan posisi kandidat dengan cepat
  • Pencarian \wAh pada linux_unicode_word memeriksa apakah \w yang sadar Unicode menangkap hasil seperti µAh
  • Hanya rg dan git grep yang bisa mengaktifkan/menonaktifkan Unicode, sedangkan ag, pt, sift, dan ucg menggunakan \w khusus ASCII
  • git grep mengalami biaya performa besar saat dukungan Unicode diaktifkan, tetapi ripgrep hampir tidak mengalami penurunan performa
  • ripgrep memasukkan decoding UTF-8 ke dalam finite state machine sehingga mencocokkan langsung pada string byte UTF-8 tanpa tahap decoding terpisah

Perbedaan menurut kompleksitas regex

  • Pada regex dengan suffix literal seperti [A-Z]+_RESUME, rg dan ucg menggunakan _RESUME untuk menemukan kandidat dengan cepat
  • Pada alternation literal seperti ERR_SYS|PME_TURN_OFF|LINK_REQ_RST|CFG_BME_EVT, ripgrep memakai Teddy dan bisa saja tidak menggunakan mesin regex inti sama sekali
  • Pada alternation case-insensitive pun ripgrep membuat prefix kombinasi huruf besar/kecil, mencari kandidat dengan Teddy, lalu hanya memverifikasi kandidat dengan regex penuh
  • Dalam pencarian \p{Greek}, hanya Rust regex dan Go regex yang mendukung properti Unicode tersebut, dan rg jauh lebih cepat daripada pt dan sift
  • Dalam pencarian case-insensitive \p{Greek}, sift tidak dapat melaporkan match, dan pt tidak menangani kapitalisasi Unicode dengan benar
  • Pada pola tanpa literal seperti \w{5}\s+..., performa mesin regex terlihat langsung
    • rg tergolong cepat bahkan dengan dukungan Unicode aktif
    • git grep membayar biaya besar saat dukungan Unicode aktif
    • Unicode DFA menangani kumpulan status NFA yang jauh lebih besar daripada ASCII DFA; angka contohnya sekitar 250 status NFA untuk ASCII dan sekitar 77.000 status NFA untuk Unicode

Pencarian satu file berukuran besar

  • Benchmark satu file menggunakan sampel OpenSubtitles2016
    • Sampel bahasa Inggris sekitar 1GB
    • Sampel bahasa Rusia sekitar 1,6GB
  • Di area ini, performa mesin regex dan optimasi literal menjadi lebih penting
  • Pada subtitles_literal, rg paling cepat untuk pencarian Sherlock Holmes maupun Шерлок Холмс
  • ripgrep mencoba memilih byte yang jarang muncul dari literal untuk digunakan pada memchr
    • Implementasi Boyer-Moore standar biasanya memakai byte terakhir untuk pencarian kandidat
    • rg mencoba memilih byte yang lebih jarang agar dapat melompati lebih lama dalam loop yang dioptimalkan SIMD
  • Pada UTF-8, banyak karakter dalam pola bahasa Rusia dimulai dengan \xD0 atau \xD1, sehingga pencarian byte pertama bisa tidak efisien
  • rg menggunakan tabel frekuensi 256 byte yang telah dihitung sebelumnya untuk lebih memilih byte yang lebih jarang daripada \xD0 dan \xD1
  • Pada satu file besar, karena memory map hanya perlu dibuat sekali, pencarian memory map rg sekitar 25% lebih cepat daripada rg (no mmap)

Unicode dan alternation pada satu file

  • Pada subtitles_literal_casei, rg tetap cepat sambil menangani pencarian case-insensitive Unicode dengan benar
  • GNU grep membayar biaya besar pada pencarian case-insensitive Unicode
  • Dalam pencarian case-insensitive bahasa Rusia, grep (ASCII) tampaknya pada dasarnya mengabaikan -i, sedangkan ag melaporkan 0 match
  • Pada subtitles_alternate, pencarian alternation beberapa nama tokoh menunjukkan rg paling cepat baik untuk bahasa Inggris maupun Rusia
  • Pada alternation bahasa Inggris, rg sekitar satu orde magnitudo lebih cepat daripada GNU grep
  • Pada subtitles_alternate_casei, rg menjadi jauh lebih lambat daripada sebelumnya, tetapi masih mengungguli alat lain untuk bahasa Inggris
  • Dalam kasus ini, jumlah kandidat literal menjadi terlalu banyak untuk ditangani Teddy, sehingga rg beralih ke Aho-Corasick
  • ripgrep menggunakan Aho-Corasick “advanced” berbasis transition table yang melakukan satu transisi untuk setiap byte input

Inner literal dan pola tanpa literal

  • Pola seperti \w+\s+Holmes\s+\w+ dirancang untuk menghindari optimisasi literal prefix·suffix, tetapi tetap dapat memanfaatkan literal internal Holmes
  • ripgrep dan GNU grep melakukan optimisasi inner literal
  • ripgrep memanfaatkan regex-syntax dari Rust regex untuk mengekstrak literal dari AST pola
  • Pada versi Rusia \w+\s+Холмс\s+\w+, hanya alat yang mendukung Unicode dengan benar yang dapat menghasilkan hasil yang bermakna
  • Pada pola panjang tanpa literal sama sekali seperti \w{5}\s+..., rg termasuk yang tercepat untuk bahasa Inggris, sementara versi GNU grep yang mendukung Unicode memakan waktu lebih dari 90 detik untuk bahasa Inggris dan lebih dari 4 menit untuk bahasa Rusia sehingga dikeluarkan
  • ripgrep mempertahankan dukungan Unicode sekaligus mendapatkan performa dengan memasukkan decoding UTF-8 ke dalam DFA

Benchmark tambahan

  • everything adalah pengujian tidak realistis yang mencocokkan semua baris di repositori Linux dengan .*
    • rg melaporkan 22.065.361 baris dalam 1,081 detik
    • ag dan pt tampaknya memiliki batas kecocokan karena tidak melaporkan semua baris
  • nothing adalah pengujian yang menerapkan invert match pada .* sehingga tidak melaporkan baris apa pun
    • rg mencatat 0,302 detik, sementara git grep mencatat 0,905 detik
    • pt dan ucg tidak mendukung invert search
  • context mencetak konteks 2 baris di sekitar Sherlock Holmes dari korpus subtitle bahasa Inggris
    • rg 0,612 detik dan sift 0,717 detik, jadi keduanya mirip
    • ucg tidak mendukung fitur tersebut
  • huge mencari Sherlock Holmes di seluruh subtitle bahasa Inggris berukuran 9,3 GB
    • rg mencatat 1,786 detik, GNU grep 5,119 detik, dan sift 3,047 detik
    • ucg hanya melaporkan 1.543 baris pada kondisi penghitungan baris sehingga menghasilkan hasil yang keliru, dan diduga bermasalah saat mencari file berukuran lebih dari 2 GB

Kesimpulan

  • ripgrep tidak selalu memenangkan semua benchmark dalam pencarian repositori kernel Linux, tetapi sulit mengatakan ada alat lain yang jelas lebih unggul dalam performa dan akurasi
  • git grep bisa unggul beberapa milidetik pada sebagian kasus sederhana, tetapi ketika pola menjadi kompleks atau Unicode dibutuhkan, ada kasus ketika ripgrep unggul jauh
  • Performa pencarian kode ripgrep dipengaruhi oleh faktor-faktor berikut
    • Traversal direktori cepat yang menargetkan pemanggilan stat seminimal mungkin
    • Pencocokan glob .gitignore menggunakan RegexSet
    • Distribusi pekerjaan melalui Chase-Lev work stealing queue
    • Pilihan untuk tidak memakai memory map saat mencari banyak file kecil
    • Engine regex yang cepat
  • Dalam pencarian file tunggal, ripgrep menjadi yang tercepat atau unggul dengan selisih besar pada semua benchmark utama
  • Performa file tunggal dipengaruhi oleh memchr berbasis sparse byte, Teddy SIMD, Aho-Corasick, dan DFA dengan decoding UTF-8 bawaan
  • Pada benchmark yang membutuhkan fitur Unicode, hanya rg, GNU grep, dan git grep yang menunjukkan dukungan bermakna, dan GNU grep serta git grep umumnya membayar biaya performa besar
  • Memory map merugikan dalam pencarian paralel atas banyak file kecil pada Linux x86_64, menguntungkan dalam pencarian satu file besar, dan dapat memiliki penalti tambahan di lingkungan VM

1 komentar

 
GN⁺ 2023-12-01
Komentar Hacker News
  • Memang cepat, dan saya jadi terus merekomendasikan kombinasi fzf
    Saya memakainya sebagai fungsi PowerShell yang mula-mula mencari dengan ripgrep, lalu menambahkan pencarian fuzzy di atas hasil file+teksnya, dan menampilkan konteks dengan bat
    Di proyek yang mencampur banyak repositori, ini sangat cepat untuk mempersempit pencarian saat “saya tahu ada di suatu tempat, tapi tidak tahu lokasi atau namanya yang tepat”
    Pendekatan ini berasal dari https://github.com/junegunn/fzf/blob/master/ADVANCED.md, dan meski tidak dipakai semuanya, tetap layak dibaca sekilas untuk mencari ide

    • Selangkah lebih jauh, saya juga merekomendasikan mengintegrasikan ripgrep-all(rga) dengan fzf
      Bukan cuma file teks, tapi juga bisa melakukan pencarian fuzzy pada banyak format file seperti PDF dan zip
      Detailnya ada di https://github.com/phiresky/ripgrep-all/wiki/fzf-Integration
    • Saya juga menulis versi bash untuk ini
      Caranya memilih hasil rg dengan fzf, lalu mem-parsing file dan nomor baris yang dipilih, kemudian membukanya dengan $EDITOR +"${linenumber}" "$file"
    • Tanpa fzf+rg di Vim, rasanya hampir seperti rusak
      Seperti menggiling kopi dengan tangan alih-alih memakai penggiling listrik
    • Dengan fzf, kita bisa memilih banyak file untuk ditambahkan ke Git sambil melewati sebagian file
      Jika menambahkan fza = "!git ls-files -m -o --exclude-standard | fzf -m --print0 | xargs -0 git add" ke [alias] di gitconfig, maka git fza akan menampilkan daftar file yang sudah dimodifikasi atau belum ditambahkan, dan kita bisa men-toggle item dengan spasi sambil lanjut ke item berikutnya
      Alias ini dan fzf+fd cukup mempercepat beberapa bagian alur kerja
      Ada juga panduan yang merangkum hal-hal untuk dimasukkan ke pengaturan zsh di macOS: https://gist.github.com/aclarknexient/0ffcb98aa262c585c49d4b...
    • Saya juga memakai ripgrep dengan cara yang hampir sama
      Saya memakainya sebagai titik awal untuk mempersempit file atau proyek dalam codebase yang punya ratusan repositori, lalu menggali lebih dalam setelah itu
  • Di Emacs saya memakai ripgrep dengan project.el dan paket dumb-jump
    Mungkin ini bukan cara yang paling populer, tapi pengalaman keseluruhannya cukup memuaskan
    Cukup instal dumb-jump dengan package-install dan atur (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
    Saat mencari definisi identifier di proyek Python dengan M-. atau C-u M-., dumb-jump akan menjalankan perintah rg sesuai proyek dan tipe file saat ini, lalu menampilkan hasilnya di buffer Xref
    ag juga didukung, dan jika ag atau rg tidak ada maka akan kembali ke grep, yang tentu bisa lambat saat mencari di seluruh home directory

    • Bahkan hanya dengan project.el bawaan Emacs pun, ripgrep cukup mudah dipakai
      Paket eksternal tidak wajib, dan untuk memakai pengganti grep yang lambat di direktori besar, cukup setel (setq xref-search-program 'ripgrep)
      Setelah itu pencarian proyek seperti C-x p g foo RET akan dijalankan di proyek saat ini dalam bentuk rg -i --null -nH --no-heading --no-messages -g '!*/' -e foo
      Hasilnya muncul di buffer Xref, sehingga nyaman memakai tombol seperti n, p, RET, C-o untuk pindah ke kecocokan berikutnya/sebelumnya, lompat ke sumber, atau menampilkannya di jendela terpisah
    • Sebagai penulis ripgrep, menurut saya regex itu tampaknya tidak perlu flag --pcre2, meski saya belum menjalankannya sendiri
      Assertion \b kedua dan ketiga juga sepertinya bisa dihapus, sedangkan yang pertama mungkin memang diperlukan
    • Deadgrep memakai ripgrep dan juga punya binding evil-collection, jadi enak dipakai: https://github.com/Wilfred/deadgrep
    • Cara ini juga bagus, tetapi saat ingin mencari di beberapa proyek sekaligus atau hanya di subfolder tertentu dalam proyek, saya masih memakai rg.el
      Itu situasi yang dulunya akan membuat saya memakai rgrep
  • Hal yang menarik adalah pencarian VS Code sekarang juga berjalan dengan ripgrep melalui wrapper Node.js
    https://www.npmjs.com/package/@vscode/ripgrep

    • Ini sangat berguna jika berada di lingkungan tempat VS Code bisa diminta atau diinstal, tetapi ripgrep tidak bisa dipasang
      Kita bisa menemukan biner rg di dalam path instalasi VS. Setidaknya itu memungkinkan di lingkungan kerja Windows saya
    • Saya selalu penasaran kenapa pencarian di VS Code, padahal aplikasi Electron, bisa begitu cepat, dan sekarang saya tahu alasannya
    • Ini bukan fitur baru; VS Code sudah menyertakannya sejak 7 tahun lalu
  • Saya sudah memakai ripgrep sekitar 2 tahun, dan sekarang ini jadi alat yang tidak tergantikan
    Alasan utama saya beralih dari grep adalah kemudahan penggunaan
    Secara default ia menghormati aturan .gitignore dan melewati file/direktori tersembunyi serta file biner, jadi rg search_term directory jauh lebih baik daripada perintah grep padanannya, dan peningkatan kecepatan itu bonus tambahan
    Saat kecocokannya terlalu panjang sampai terminal jadi berantakan, saya sering memakai opsi -M seperti -M 1000

    • -M benar-benar luar biasa
      Sangat berguna terutama untuk mengabaikan hasil dari file minified yang tidak ingin dilihat, dan opsi -g seperti -g *.cs untuk mencari hanya file dengan ekstensi tertentu juga bagus
      Fakta bahwa ini adalah biner portabel yang dapat dijalankan mandiri juga berguna; saat bekerja di mesin baru, kita tinggal meletakkan executable-nya dan menjadikan grep sebagai alias ke rg, jadi ketika mengetik grep seperti biasa, yang berjalan sebenarnya rg
  • Ini mungkin masih benar pada 2023, tetapi masalahnya adalah alat pengganti grep yang diparalelkan, misalnya ripgrep atau ag, terlalu cepat dibanding grep lama sehingga selisih kecepatan kecil di antara mereka sulit dijadikan pembeda.
    Saya memakai ag di dalam Emacs pada codebase 900 ribu baris, dan di Ryzen Threadripper 2950X 16-core hasilnya praktis instan.
    Saya tidak merasa perlu mengurangi waktu “kurang dari 1 detik” menjadi “sedikit lebih kurang dari 1 detik”.
    Sifat utama alat-alat grep baru bukan lagi kecepatan, dan sebaiknya dievaluasi serta dibandingkan dengan cara lain.

    • Menurut saya, pada 2016 kecepatan memang jelas merupakan sifat utama.
      ag punya performance cliff yang cukup besar, dan itu juga terlihat di tulisan blog tersebut.
      Namun workload tiap orang berbeda, jadi dalam beberapa kasus perbedaan performa mungkin tidak penting.
      900 ribu baris bukan ukuran yang terlalu besar, dan untuk kueri sederhana sebagian besar alat sejenis grep yang tidak naif akan memprosesnya dengan sangat cepat.
      Jika dilihat dari kriteria pembanding lain, ag nyaris dalam status pemeliharaan minimum, dan tampaknya sempat hampir dihapus dari Debian lalu diselamatkan seseorang: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=999962
      Tulisan blog itu juga membandingkan dukungan Unicode, dan ag pada praktiknya tidak punya dukungan Unicode. Ini mungkin tidak penting bagi semua orang, tetapi cukup sebagai kriteria pembanding non-performa.
    • Dalam pengalaman saya, semua alat seperti ini sangat terikat pada bottleneck I/O.
      Waktu pencarian berlangsung selama waktu yang dibutuhkan untuk memuat file dari disk, dan setelah itu selisihnya sulit menjadi bermakna.
      Jika file sudah ada di cache, waktu untuk menjelajahi filesystem dan mengetik perintah lebih dominan daripada waktu pencarian, jadi perbedaan performa juga sulit punya arti.
  • Judulnya perlu (2016).
    Ini tulisan pengumuman asli, bukan informasi baru.

  • Ini tidak lebih cepat daripada qgrep.
    Cara kerja keduanya sangat berbeda, dan qgrep berbasis re2, tetapi kecepatannya datang dari adanya indeks.
    Pada repositori file besar, menggunakan qgrep dan indeks lebih masuk akal daripada memindai semua file setiap kali, jadi saya penasaran kenapa orang-orang melupakan opsi qgrep.
    Namun jika butuh pencocokan multi-baris di UTF-8, saya rasa ripgrep harus beralih ke library PCRE2 lain sehingga tidak akan secepat itu.

    • Sebagai penulis ripgrep, memang benar bahwa qgrep diuntungkan karena memakai indexing dibanding alat yang tidak melakukan indexing.
      Sebagai gantinya, indeks harus disiapkan dan dipelihara, jadi UX-nya tidak sesederhana “langsung jalankan pencarian”.
      Alasan orang tidak memakai qgrep mirip dengan alasan mereka tidak memakai ripgrep karena “buat saya grep saja sudah cukup cepat”.
      Pada target pencarian kecil, sering kali orang tidak merasakan perbedaan kecepatan antara ripgrep dan grep, atau antara qgrep dan ripgrep.
      Jika ripgrep bisa menyelesaikan pencarian kernel Linux dalam waktu di bawah 100ms, apakah cukup merepotkan untuk beralih ke alat berbasis indeks dalam penggunaan interaktif standar akan bergantung pada situasinya, tetapi biasanya tidak.
      Saya memang pernah memikirkan ide menambahkan indexing ke ripgrep: https://github.com/BurntSushi/ripgrep/issues/1497
      Dan pencarian multi-baris tidak memerlukan PCRE2. Mesin regex bawaan juga mendukung Unicode, dan dukungan pencarian multi-baris tetap ada bahkan jika dibangun tanpa PCRE2.
  • Setelah beralih dari ripgrep ke ugrep, saya tidak pernah menoleh lagi.
    Kecepatannya mirip, tetapi ada fuzzy matching, TUI yang berguna untuk code review, dan juga bisa mencari di dalam PDF maupun arsip terkompresi.
    Juga praktis karena secara opsional bisa memakai sintaks pencarian Google.
    https://ugrep.com

    • Saya penggemar berat ripgrep, tetapi belakangan saya menemukan ugrep karena fitur yang tidak dimiliki ripgrep, yaitu pencarian di dalam file zip.
      Bisa mencari tanpa mengekstraknya ke disk.
      Saya menangani korpus arsip yang berisi jutaan file teks kecil, dan bagus sekali karena tidak perlu mengekstrak semuanya ke filesystem. Beberapa filesystem kesulitan pada skala seperti ini.
      Terima kasih untuk kedua alat ini, dan terima kasih kepada masing-masing pembuatnya.
    • Saya takut kalau mulai memakai sintaks pencarian Google di grep, sebagian besar hasilnya malah akan mencoba menjual sesuatu kepada saya.
    • Saat mencari santai tulisan “ugrep vs ripgrep”, saya melihat postingan yang tampaknya menunjukkan penulis ugrep dan ripgrep bertengkar di Reddit selama beberapa tahun.
      Misalnya https://www.reddit.com/r/programming/comments/120wqvr/ripgre...
      Ini cuma soal alat open source, jadi rasanya agak aneh.
    • Saya penasaran apakah TUI ini lebih baik daripada mengoper hasil ke fzf.
      Bagi saya, sulit mengalahkan kemampuan konfigurasi dan fleksibilitas fzf.
    • Terima kasih sudah memberi tahu soal ini.
      Fitur pembunuhnya tampaknya adalah kompatibilitas dengan opsi command line grep yang sudah ada.
      Cukup menyenangkan karena tidak perlu mempelajari kumpulan opsi yang benar-benar baru.
  • Bertanya-tanya mengapa grep tidak digantikan atau diperbaiki
    Topik ini juga sekarang terasa sudah agak lama

    • Ada banyak alasan yang bisa menjelaskannya
      Hal-hal seperti inersia, kompatibilitas, resistensi terhadap perubahan, dan dilema inovator. Bukan bermaksud mengatakan ini secara negatif, karena semuanya juga berlaku pada saya
      Untuk soal kompatibilitas, lihat FAQ: https://github.com/BurntSushi/ripgrep/blob/master/FAQ.md#pos...
    • Mirip dengan alasan saya tidak mengganti kursi berusia 40 tahun yang saya duduki sekarang dengan Razer UltraSeat XR3000-A
      Kursinya nyaman, cocok dengan lingkungan kerja di sekitar saya, dan tidak ada alasan kuat untuk menggantinya lalu menyesuaikan semuanya lagi
      Analogi itu hanya berlaku sampai pada fakta bahwa ada kursi seperti Razer di dekat sini yang sudah dipakai untuk menaruh pakaian
    • Seseorang yang merancang Unix menjadikan beberapa fungsi sistem sebagai fitur inti OS sekaligus alat yang dipakai manusia, dan akibatnya beberapa dekade kemudian muncul hasil aneh seperti “harus ada program bernama xyz, harus menerima argumen ini, dan harus berperilaku persis seperti ini”
    • Sudah ada banyak alat pengganti seperti ripgrep yang bisa dipakai
      Jika yang dimaksud adalah mengganti perintah grep itu sendiri dengan utilitas lain, rasanya terlalu banyak yang akan rusak dibanding nilai yang didapat
      Orang yang ingin grep lebih cepat bisa memakai alat lain, dan orang yang memakai grep lama bisa tetap memakainya, jadi kondisi sekarang sudah mendekati ideal
    • grep adalah alat serbaguna untuk mencari teks di semua jenis file, dan sudah tertanam dalam standar UNIX
      Sebagian programmer memakainya untuk mencari dalam source code, tetapi orang lain memakainya untuk pencarian teks yang tidak berkaitan dengan source code atau di dalam skrip, dan mereka berharap alat itu sama sekali tidak pernah crash
      Sebaliknya, ripgrep adalah alat yang lebih khusus dan memiliki opini kuat, yang terutama dirancang untuk menelusuri repositori source code
      Tidak banyak ruang untuk membuat pencarian teks serbaguna menjadi lebih cepat. Anda bisa memakai mmap() tetapi ada risiko crash pada file yang terpotong, bisa juga mempercepatnya dengan mengurangi kemampuan ekspresi regex, dan bahkan bisa membuang dukungan semua locale dan charset lalu meng-hardcode hanya UTF-8/UTF-16, tetapi itu tidak seharusnya dilakukan
  • Setelah mencarinya di Portage, sepertinya ada juga versi yang menangani dokumen lain seperti PDF dan doc
    https://github.com/phiresky/ripgrep-all