contrib/slabinfo: add scripts to dump slabinfo

Sample output:

python3 drgn -s vmlinux -c vmcore contrib/slabinfo.py

struct kmem_cache *  |         name         | active_objs  |   num_objs   | objsize  | objperslab  | pagesperslab
-------------------- | -------------------- | ------------ | ------------ | -------- | ----------- | -------------
0xffff00000632cf40   | 9p-fcall-cache       |            0 |            0 |   131192 |           1 |            64
0xffff00000632cdc0   | p9_req_t             |            0 |           33 |      248 |          33 |             2
0xffff00000632cc40   | isp1760_qh           |            0 |            0 |      144 |          28 |             1
0xffff00000632cac0   | isp1760_qtd          |            0 |            0 |      168 |          24 |             1
0xffff00000632c940   | isp1760_urb_listite  |            0 |            0 |      120 |          34 |             1
0xffff00000632c7c0   | asd_sas_event        |            0 |            0 |      256 |          32 |             2
0xffff00000632c640   | sas_task             |            0 |            0 |      448 |          36 |             4
0xffff00000632c4c0   | bio-120              |           50 |           50 |      320 |          25 |             2
0xffff00000632c340   | io_buffer            |            0 |            0 |      160 |          25 |             1
0xffff00000632c1c0   | io_kiocb             |            0 |            0 |      448 |          36 |             4
0xffff00000632c040   | bfq_io_cq            |            0 |            0 |     1456 |          22 |             8
0xffff000006321e40   | bfq_queue            |            0 |            0 |      672 |          24 |             4
0xffff000006321cc0   | bio-248              |            4 |           36 |      448 |          36 |             4
0xffff000006321b40   | mqueue_inode_cache   |            1 |           30 |     1088 |          30 |             8
0xffff0000063219c0   | v9fs_inode_cache     |            1 |           39 |      832 |          39 |             8
0xffff000006321840   | nfs4_xattr_cache_ca  |            0 |            0 |     2216 |          14 |             8
...

Signed-off-by: Kuan-Ying Lee <kuan-ying.lee@canonical.com>
This commit is contained in:
Kuan-Ying Lee 2024-07-19 11:38:05 +08:00 committed by Omar Sandoval
parent f8168da4e2
commit 3540cfa992

91
contrib/slabinfo.py Executable file
View File

@ -0,0 +1,91 @@
#!/usr/bin/env drgn
# Copyright (c) Canonical Ltd.
# SPDX-License-Identifier: LGPL-2.1-or-later
""" Script to dump slabinfo status using drgn"""
from typing import Iterator, Optional
from drgn import Object
from drgn.helpers.common.format import escape_ascii_string
from drgn.helpers.linux.list import list_for_each_entry, list_for_each_entry_reverse
from drgn.helpers.linux.slab import for_each_slab_cache
MAX_PARTIAL_TO_SCAN = 10000
OO_SHIFT = 16
OO_MASK = (1 << OO_SHIFT) - 1
def for_each_kmem_cache_node(slab_cache: Object) -> Iterator[Object]:
"""
Iterate over all kmem_cache_node of specific slab cache.
:return: Iterator of ``struct kmem_cache_node *`` objects.
"""
for nid in range(0, prog["nr_node_ids"].value_()):
yield slab_cache.node[nid]
def count_partial_free_approx(kmem_cache_node: Object) -> Optional[Object]:
x = Object(prog, "unsigned long", 0)
n = kmem_cache_node
if n.nr_partial <= MAX_PARTIAL_TO_SCAN:
for slab in list_for_each_entry(
"struct slab", n.partial.address_of_(), "slab_list"
):
x += slab.objects - slab.inuse
else:
scanned = 0
for slab in list_for_each_entry(
"struct slab", n.partial.address_of_(), "slab_list"
):
x += slab.objects - slab.inuse
scanned += 1
if scanned == MAX_PARTIAL_TO_SCAN / 2:
break
for slab in list_for_each_entry_reverse(
"struct slab", n.partial.address_of_(), "slab_list"
):
x += slab.objects - slab.inuse
scanned += 1
if scanned == MAX_PARTIAL_TO_SCAN / 2:
break
x = x * n.nr_partial / scanned
x = min(x, n.total_objects)
return x
def oo_objects(kmem_cache_order_objects: Object) -> Optional[Object]:
return kmem_cache_order_objects.x & OO_MASK
def oo_order(kmem_cache_order_objects: Object) -> Optional[Object]:
return kmem_cache_order_objects.x >> OO_SHIFT
print(
f"{'struct kmem_cache *':^20} | {'name':^20} | {'active_objs':^12} | {'num_objs':^12} | {'objsize':^8} | {'objperslab':^11} | {'pageperslab':^13}"
)
print(
f"{'':-^20} | {'':-^20} | {'':-^12} | {'':-^12} | {'':-^8} | {'':-^11} | {'':-^13}"
)
for s in for_each_slab_cache(prog):
nr_slabs = 0
nr_objs = 0
nr_free = 0
for node in for_each_kmem_cache_node(s):
nr_slabs += node.nr_slabs.counter.value_()
nr_objs += node.total_objects.counter.value_()
nr_free += count_partial_free_approx(node).value_()
active_objs = nr_objs - nr_free
num_objs = nr_objs
active_slab = nr_slabs
num_slabs = nr_slabs
objects_per_slab = oo_objects(s.oo).value_()
cache_order = oo_order(s.oo).value_()
name = escape_ascii_string(s.name.string_(), escape_backslash=True)
print(
f"0x{s.value_():<18x} | {name:20.19s} | {active_objs:12} | {num_objs:12} | {s.size.value_():8} | {objects_per_slab:11} | {1<<cache_order:13}"
)