この記事はLinuxその2 Advent Calendar 2020の4日目の記事です。
今回はtoolネタです。vgrepというgrep系のツールがあって結構便利です。これは今年のOpen Source Summit + Embedded Linux Conference North America 2020でのAsk the Expert SessionでGreg KHさんがコードを調べる時にvgrepを使ってると言っていたので知りました。
使い方はわりと簡単なのでREADME.mdを見ればOKだと思います。
grepとの比較
grep系のコマンドなので速さはどうなの?というところですが、qemu上のこんなriscv64環境(cpu4個、メモリ8GB)で試してみます。fedoraのriscv64版にもvgrepパッケージあります。
masami@fedora-riscv:~/linux-kernel$ uname -a Linux fedora-riscv 5.10.0-rc7-ktest+ #8 SMP Mon Dec 7 10:35:20 EST 2020 riscv64 riscv64 riscv64 GNU/Linux
vgrepの実行。
masami@fedora-riscv:~/linux-kernel$ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
masami@fedora-riscv:~/linux-kernel$ time vgrep --no-less "kmem_cache_alloc(" >/dev/null
real 0m49.499s
user 0m20.440s
sys 1m2.571s
find+grep(with xargs)の実行。
masami@fedora-riscv:~/linux-kernel$ sudo sh -c "echo 3 > /proc/sys/vm/drop_caches"
masami@fedora-riscv:~/linux-kernel$ time (find . -name "*.c" -o -name "*.h" | xargs grep "kmem_cache_alloc(" >/dev/null)
real 1m0.191s
user 0m4.412s
sys 0m48.670s
find+grepはコマンドをパイプ繋いでいるしというのはありますがvgrep良い感じですね。
使ってみる
まずは普通に検索してみます(ここからは普通にx86_64のデスクトップ環境で)。
masami@moon:~/linux-kernel$ vgrep "kmem_cache_alloc("
Index File Line Content
0 Documentation/core-api/memory-allocation.rst 163 cache allocator. The cache should be set up with kmem_cache_create() or
1 arch/arm64/mm/pgd.c 54 pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_SIZE,
2 arch/powerpc/kernel/rtas_flash.c 713 flash_block_cache = kmem_cache_create("rtas_flash_cache",
3 arch/powerpc/kvm/book3s_64_mmu_radix.c 1442 kvm_pte_cache = kmem_cache_create("kvm-pte", size, size, 0, pte_ctor);
4 arch/powerpc/kvm/book3s_64_mmu_radix.c 1448 kvm_pmd_cache = kmem_cache_create("kvm-pmd", size, size, 0, pmd_ctor);
5 arch/powerpc/kvm/book3s_mmu_hpte.c 377 hpte_cache = kmem_cache_create("kvm-spt", sizeof(struct hpte_cache),
6 arch/powerpc/mm/init-common.c 127 new = kmem_cache_create(name, table_size, align, 0, ctor(shift));
7 arch/powerpc/perf/hv-24x7.c 1732 hv_page_cache = kmem_cache_create("hv-page-4096", 4096, 4096, 0, NULL);
8 arch/powerpc/platforms/cell/spufs/inode.c 786 spufs_inode_cache = kmem_cache_create("spufs_inode_cache",
9 arch/powerpc/platforms/pseries/setup.c 315 dtl_cache = kmem_cache_create("dtl", DISPATCH_LOG_BYTES,
10 arch/powerpc/sysdev/xive/native.c 518 xive_provision_cache = kmem_cache_create("xive-provision",
11 arch/s390/kernel/nmi.c 86 mcesa_cache = kmem_cache_create("nmi_save_areas", size, size, 0, NULL);
12 arch/s390/mm/pgalloc.c 557 base_pgt_cache = kmem_cache_create("base_pgt", sz, sz, 0, NULL);
13 arch/s390/pci/pci.c 782 zdev_fmb_cache = kmem_cache_create("PCI_FMB_cache", sizeof(struct zpci_fmb),
14 arch/s390/pci/pci_dma.c 635 dma_region_table_cache = kmem_cache_create("PCI_DMA_region_tables",
15 arch/s390/pci/pci_dma.c 641 dma_page_table_cache = kmem_cache_create("PCI_DMA_page_tables",
16 arch/sh/kernel/cpu/sh4/sq.c 379 sq_cache = kmem_cache_create("store_queue_cache",
17 arch/sh/kernel/dwarf.c 1171 dwarf_frame_cachep = kmem_cache_create("dwarf_frames",
18 arch/sh/kernel/dwarf.c 1175 dwarf_reg_cachep = kmem_cache_create("dwarf_regs",
19 arch/sh/kernel/process.c 58 task_xstate_cachep = kmem_cache_create("task_xstate", xstate_size,
20 arch/sh/mm/pgtable.c 22 pgd_cachep = kmem_cache_create("pgd_cache",
21 arch/sh/mm/pgtable.c 26 pmd_cachep = kmem_cache_create("pmd_cache",
22 arch/sparc/mm/tsb.c 345 pgtable_cache = kmem_cache_create("pgtable_cache",
23 arch/sparc/mm/tsb.c 358 tsb_caches[i] = kmem_cache_create(name,
24 arch/x86/events/intel/lbr.c 1596 return kmem_cache_create("x86_lbr", size, align, 0, NULL);
25 arch/x86/kvm/mmu/mmu.c 5876 pte_list_desc_cache = kmem_cache_create("pte_list_desc",
26 arch/x86/kvm/mmu/mmu.c 5882 mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
27 arch/x86/kvm/x86.c 7876 x86_fpu_cache = kmem_cache_create("x86_fpu", sizeof(struct fpu),
28 arch/x86/mm/pgtable.c 382 pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_ALIGN,
29 block/bio-integrity.c 471 bip_slab = kmem_cache_create("bio_integrity_payload",
30 block/bio.c 107 slab = kmem_cache_create(bslab->name, sz, ARCH_KMALLOC_MINALIGN,
検索結果はデフォルトではページャとしてlessが使われます。表示内容は次のような感じです。
- 見つかったファイルの検索結果の番号
- ファイルのpath
- 見つかった行の行番号
- 検索結果の文字列
これだけだと単に検索しただけですが、この検索結果を利用してさらに操作ができます。ここで検索結果27番のファイルをエディタで見たいとします。その場合は次のように-sオプションに検索結果の番号を引数で渡すとEDITOR環境変数に設定されているエディタで該当ファイルの該当行の辺りを開いてくれます。
masami@moon:~/linux-kernel$ vgrep -s 27
全体的に前後の行をみたいという時(grepコマンドの-A、-Bオプションみたいに)はc/contextコマンドを使います。つぎの例だと検索で見つかった行を中心として前後5行ずつ表示します。
masami@moon:~/linux-kernel$ vgrep -s c5
~~~
--- 26 arch/x86/kvm/mmu/mmu.c ---------------------------------------
5877 sizeof(struct pte_list_desc),
5878 0, SLAB_ACCOUNT, NULL);
5879 if (!pte_list_desc_cache)
5880 goto out;
5881
5882 mmu_page_header_cache = kmem_cache_create("kvm_mmu_page_header",
5883 sizeof(struct kvm_mmu_page),
5884 0, SLAB_ACCOUNT, NULL);
5885 if (!mmu_page_header_cache)
5886 goto out;
5887
--- 27 arch/x86/kvm/x86.c ------------------------------------------
7871 r = -EOPNOTSUPP;
7872 goto out;
7873 }
7874
7875 r = -ENOMEM;
7876 x86_fpu_cache = kmem_cache_create("x86_fpu", sizeof(struct fpu),
7877 __alignof__(struct fpu), SLAB_ACCOUNT,
7878 NULL);
7879 if (!x86_fpu_cache) {
7880 printk(KERN_ERR "kvm: failed to allocate cache for x86 fpu\n");
7881 goto out;
特定のファイル(1つもしくは複数)のみを対象にするなら検索結果の番号をさらに引数として渡します。この例では27と28、それに30番を指定してます。
masami@moon:~/linux-kernel$ vgrep -s c3 27-28,30
--- 27 arch/x86/kvm/x86.c ------------------------------------------
7873 }
7874
7875 r = -ENOMEM;
7876 x86_fpu_cache = kmem_cache_create("x86_fpu", sizeof(struct fpu),
7877 __alignof__(struct fpu), SLAB_ACCOUNT,
7878 NULL);
7879 if (!x86_fpu_cache) {
--- 28 arch/x86/mm/pgtable.c ---------------------------------------
379 * page for pgd. We are able to just allocate a 32-byte for pgd.
380 * During boot time, we create a 32-byte slab for pgd table allocation.
381 */
382 pgd_cache = kmem_cache_create("pgd_cache", PGD_SIZE, PGD_ALIGN,
383 SLAB_PANIC, NULL);
384 }
385
--- 30 block/bio.c ------------------------------------------------
104 bslab = &bio_slabs[entry];
105
106 snprintf(bslab->name, sizeof(bslab->name), "bio-%d", entry);
107 slab = kmem_cache_create(bslab->name, sz, ARCH_KMALLOC_MINALIGN,
108 SLAB_HWCACHE_ALIGN, NULL);
109 if (!slab)
110 goto out_unlock;
ディレクトリごとに何個のhitが合ったかなんてのも見れます。
masami@moon:~/linux-kernel$ vgrep -s tree
Matches Directory
493
1 Documentation
1 Documentation/core-api
28 arch
1 arch/arm64
1 arch/arm64/mm
9 arch/powerpc
1 arch/powerpc/kernel
3 arch/powerpc/kvm
1 arch/powerpc/mm
1 arch/powerpc/perf
2 arch/powerpc/platforms
1 arch/powerpc/platforms/cell
1 arch/powerpc/platforms/cell/spufs
1 arch/powerpc/platforms/pseries
1 arch/powerpc/sysdev
1 arch/powerpc/sysdev/xive
5 arch/s390
1 arch/s390/kernel
1 arch/s390/mm
3 arch/s390/pci
6 arch/sh
4 arch/sh/kernel
1 arch/sh/kernel/cpu
1 arch/sh/kernel/cpu/sh4
2 arch/sh/mm
2 arch/sparc
2 arch/sparc/mm
5 arch/x86
1 arch/x86/events
1 arch/x86/events/intel
3 arch/x86/kvm
2 arch/x86/kvm/mmu
1 arch/x86/mm
6 block
141 drivers
1 drivers/acpi
9 drivers/block
1 drivers/block/aoe
4 drivers/block/drbd
1 drivers/block/xen-blkback
7 drivers/crypto
1 drivers/crypto/axis
2 drivers/crypto/caam
別の検索を行いたい場合は最初にやったみたいにvgrep 検索ワードでも出来ますし、g/grepコマンドを利用して再検索することもできます。
masami@moon:~/linux-kernel$ vgrep -s g "bootconfig"
Index File Line Content
0 Documentation/admin-guide/bootconfig.rst 3 .. _bootconfig:
1 Documentation/admin-guide/bootconfig.rst 81 overriding the default value by adding (partial) custom bootconfigs
2 Documentation/admin-guide/bootconfig.rst 82 without parsing the default bootconfig.
3 Documentation/admin-guide/bootconfig.rst 126 /proc/bootconfig
4 Documentation/admin-guide/bootconfig.rst 129 /proc/bootconfig is a user-space interface of the boot config.
5 Documentation/admin-guide/bootconfig.rst 143 [initrd][bootconfig][padding][size(le32)][checksum(le32)][#BOOTCONFIG\n]
6 Documentation/admin-guide/bootconfig.rst 149 (``\0``) will be added. Thus the ``size`` is the length of the bootconfig
7 Documentation/admin-guide/bootconfig.rst 157 loader passes a longer size, the kernel feils to find the bootconfig data.
8 Documentation/admin-guide/bootconfig.rst 159 To do this operation, Linux kernel provides "bootconfig" command under
9 Documentation/admin-guide/bootconfig.rst 160 tools/bootconfig, which allows admin to apply or delete the config file
10 Documentation/admin-guide/bootconfig.rst 163 # make -C tools/bootconfig
11 Documentation/admin-guide/bootconfig.rst 165 To add your boot config file to initrd image, run bootconfig as below
12 Documentation/admin-guide/bootconfig.rst 168 # tools/bootconfig/bootconfig -a your-config /boot/initrd.img-X.Y.Z
13 Documentation/admin-guide/bootconfig.rst 172 # tools/bootconfig/bootconfig -d /boot/initrd.img-X.Y.Z
14 Documentation/admin-guide/bootconfig.rst 174 Then add "bootconfig" on the normal kernel command line to tell the
15 Documentation/admin-guide/bootconfig.rst 175 kernel to look for the bootconfig at the end of the initrd file.
16 Documentation/admin-guide/bootconfig.rst 190 Anyway, since bootconfig command verifies it when appending a boot config
17 Documentation/admin-guide/bootconfig.rst 237 .. kernel-doc:: include/linux/bootconfig.h
18 Documentation/admin-guide/bootconfig.rst 238 .. kernel-doc:: lib/bootconfig.c
19 Documentation/admin-guide/index.rst 70 bootconfig
20 Documentation/admin-guide/kernel-parameters.txt 446 bootconfig [KNL]
21 Documentation/admin-guide/kernel-parameters.txt 450 See Documentation/admin-guide/bootconfig.rst
22 Documentation/trace/boottime-trace.rst 17 this uses bootconfig file to describe tracing feature programming.
23 Documentation/trace/boottime-trace.rst 27 .. [1] See :ref:`Documentation/admin-guide/bootconfig.rst <bootconfig>`
24 Documentation/translations/zh_CN/admin-guide/index.rst 69 bootconfig
vgrepはこんな感じの使い方です。わりとシンプルで使いやすいので気になった人は使ってみてください。