Skip to content

Instantly share code, notes, and snippets.

@chapmanjacobd
Last active January 28, 2023 22:15
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save chapmanjacobd/32d1f92ac389a17341f4861ef38ae7fd to your computer and use it in GitHub Desktop.
Save chapmanjacobd/32d1f92ac389a17341f4861ef38ae7fd to your computer and use it in GitHub Desktop.
import argparse
from multiprocessing import Pool
import btrfs
parser = argparse.ArgumentParser()
parser.add_argument("btrfs_fs_mountpoint")
args = parser.parse_args()
def sizeof_fmt(num, suffix="B"):
for unit in ["", "Ki", "Mi", "Gi", "Ti", "Pi", "Ei", "Zi"]:
if abs(num) < 1024.0:
return f"{num:3.1f}{unit}{suffix}"
num /= 1024.0
return f"{num:.1f}Yi{suffix}"
def safe_get_block_group(vaddr):
try:
return fs.block_group(vaddr)
except IndexError:
return None
with btrfs.FileSystem(args.btrfs_fs_mountpoint) as fs:
devices = fs.devices()
devids = [d.devid for d in devices]
fs_chunks = list(fs.chunks())
print(args.btrfs_fs_mountpoint, '\t', fs.usage().virtual_used_str, '\t', len(fs_chunks), 'fs chunks')
for devid in devids:
dev_info = fs.dev_info(devid)
dev_vaddrs = [d.vaddr for d in fs.dev_extents(devid)]
print(
dev_info.path,
'\t',
dev_info.bytes_used_str,
'\t',
len(dev_vaddrs),
'chunk extents',
"({:.0%})".format(len(dev_vaddrs) / len(fs_chunks)),
)
print('\nCalculating chunk use (may take a few minutes)...\n')
for devid in devids:
print(fs.dev_info(devid).path)
dev_vaddrs = [d.vaddr for d in fs.dev_extents(devid)]
chunk_stats = {}
with Pool() as pool:
results = pool.map(safe_get_block_group, dev_vaddrs)
for bg in [r for r in results if r is not None]:
if bg.flags_str in chunk_stats:
chunk_stats[bg.flags_str]['count'] += 1
chunk_stats[bg.flags_str]['size_used'] += bg.used
chunk_stats[bg.flags_str]['percent_used'].append(bg.used_pct)
else:
chunk_stats[bg.flags_str] = {'count': 1, 'size_used': bg.used, 'percent_used': [bg.used_pct]}
for data_flag in sorted(chunk_stats):
stats = chunk_stats[data_flag]
print('\t', data_flag)
print('\t' * 2, 'Chunks at least partially on disk:', stats['count'])
print('\t' * 2, 'Data-device dependance:', sizeof_fmt(stats['size_used']))
print('\t' * 2, 'Approx. chunk percentage used:')
grouped_stats = {}
for percent in stats['percent_used']:
group = (percent // 10) * 10
if group in grouped_stats:
grouped_stats[group] += 1
else:
grouped_stats[group] = 1
min_count = min(count for _group, count in grouped_stats.items())
max_count = max(count for _group, count in grouped_stats.items())
for group, count in sorted(grouped_stats.items()):
try:
scaled_count = int(60 * (count - min_count) / (max_count - min_count))
except ZeroDivisionError:
scaled_count = 1
print('\t' * 2, f' {str(group).rjust(3)}% packed', '*' * max(scaled_count, 1), f"({count} chunks)")
print('\n')
@chapmanjacobd
Copy link
Author

chapmanjacobd commented Jan 28, 2023

"""

fs.devices()
╭─────────────── <class 'btrfs.ctree.DevItem'> ───────────────╮
│ Object representation of struct `btrfs_dev_item`.           │
│                                                             │
│ ╭─────────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.DevItem object at 0x7fa0219707d0>          │ │
│ ╰─────────────────────────────────────────────────────────╯ │
│                                                             │
│    bandwidth = 0                                            │
│   bytes_used = 13212426698752                               │
│    dev_group = 0                                            │
│        devid = 5                                            │
│         fsid = UUID('8da156d7-abd4-4c84-a2f0-8c17f43eb60c') │
│   generation = 0                                            │
│     io_align = 4096                                         │
│     io_width = 4096                                         │
│          key = Key(1, 216, 5)                               │
│  sector_size = 4096                                         │
│   seek_speed = 0                                            │
│ start_offset = 0                                            │
│  total_bytes = 15801184681984                               │
│         type = 0                                            │
│         uuid = UUID('3c38464b-b1b7-4e1e-80fd-c33e4fe30333') │


ipdb> inspect(fs.dev_info(1))
╭──────────────── <class 'btrfs.ioctl.DevInfo'> ─────────────────╮
│ Object representation of struct btrfs_ioctl_dev_info_args.     │
│                                                                │
│ ╭────────────────────────────────────────────────────────────╮ │
│ │ <btrfs.ioctl.DevInfo object at 0x7fa0238a8150>             │ │
│ ╰────────────────────────────────────────────────────────────╯ │
│                                                                │
│      bytes_used = 17711370338304                               │
│  bytes_used_str = '16.11TiB'                                   │
│           devid = 1                                            │
│            path = '/dev/sda'                                   │
│     total_bytes = 18000207937536                               │
│ total_bytes_str = '16.37TiB'                                   │
│            uuid = UUID('a36793e0-ff10-4d8d-bc61-7f70bcc3e759') │
╰────────────────────────────────────────────────────────────────╯


inspect(next(fs.dev_extents(1)))
╭─────────────── <class 'btrfs.ctree.DevExtent'> ────────────────╮
│ Object representation of struct `btrfs_dev_extent`.            │
│                                                                │
│ ╭────────────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.DevExtent object at 0x7fa021aeda90>           │ │
│ ╰────────────────────────────────────────────────────────────╯ │
│                                                                │
│  chunk_objectid = 256                                          │
│    chunk_offset = 185118663376896                              │
│      chunk_tree = 3                                            │
│ chunk_tree_uuid = UUID('00000000-0000-0000-0000-000000000000') │
│           devid = 1                                            │
│             key = Key(1, 204, 1048576)                         │
│          length = 33554432                                     │
│      length_str = '32.00MiB'                                   │
│           paddr = 1048576                                      │
│           vaddr = 185118663376896                              │
╰─────────────────────────────────────────────────────

inspect(next(fs.dev_extents(1)))
╭─────────────── <class 'btrfs.ctree.DevExtent'> ────────────────╮
│ Object representation of struct `btrfs_dev_extent`.            │
│                                                                │
│ ╭────────────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.DevExtent object at 0x7fa021b1f010>           │ │
│ ╰────────────────────────────────────────────────────────────╯ │
│                                                                │
│  chunk_objectid = 256                                          │
│    chunk_offset = 185118663376896                              │
│      chunk_tree = 3                                            │
│ chunk_tree_uuid = UUID('00000000-0000-0000-0000-000000000000') │
│           devid = 1                                            │
│             key = Key(1, 204, 1048576)                         │
│          length = 33554432                                     │
│      length_str = '32.00MiB'                                   │
│           paddr = 1048576                                      │
│           vaddr = 185118663376896

inspect(next(fs.chunks()))
╭─────────────────── <class 'btrfs.ctree.Chunk'> ───────────────────╮
│ Object representation of struct `btrfs_chunk`.                    │
│                                                                   │
│ ╭───────────────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.Chunk object at 0x7f867e938950>                  │ │
│ ╰───────────────────────────────────────────────────────────────╯ │
│                                                                   │
│        io_align = 65536                                           │
│    io_align_str = '64.00KiB'                                      │
│        io_width = 65536                                           │
│    io_width_str = '64.00KiB'                                      │
│             key = Key(256, 228, 113020339814400)                  │
│          length = 1073741824                                      │
│      length_str = '1.00GiB'                                       │
│     num_stripes = 1                                               │
│           owner = 2                                               │
│     sector_size = 4096                                            │
│ sector_size_str = '4.00KiB'                                       │
│      stripe_len = 65536                                           │
│  stripe_len_str = '64.00KiB'                                      │
│         stripes = [<btrfs.ctree.Stripe object at 0x7f867f4fa750>] │
│     sub_stripes = 1                                               │
│            type = 1                                               │
│        type_str = 'DATA'                                          │
│           vaddr = 113020339814400

ipdb> inspect(fs.block_group(113020339814400))
╭────────── <class 'btrfs.ctree.BlockGroupItem'> ───────────╮
│ Object representation of struct `btrfs_block_group_item`. │
│                                                           │
│ ╭───────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.BlockGroupItem object at 0x7f867eb48990> │ │
│ ╰───────────────────────────────────────────────────────╯ │
│                                                           │
│ chunk_objectid = 256                                      │
│          flags = 1                                        │
│      flags_str = 'DATA'                                   │
│            key = Key(113020339814400, 192, 1073741824)    │
│         length = 1073741824                               │
│     length_str = '1.00GiB'                                │
│           used = 1072644096                               │
│       used_pct = 100                                      │
│       used_str = '1022.95MiB'                             │
│          vaddr = 113020339814400                          │
╰───────────────────────────────────────────────────────────╯
ipdb> inspect(fs.block_group(185118663376896))
╭────────── <class 'btrfs.ctree.BlockGroupItem'> ───────────╮
│ Object representation of struct `btrfs_block_group_item`. │
│                                                           │
│ ╭───────────────────────────────────────────────────────╮ │
│ │ <btrfs.ctree.BlockGroupItem object at 0x7f867e9c6810> │ │
│ ╰───────────────────────────────────────────────────────╯ │
│                                                           │
│ chunk_objectid = 256                                      │
│          flags = 18                                       │
│      flags_str = 'SYSTEM|RAID1'                           │
│            key = Key(185118663376896, 192, 33554432)      │
│         length = 33554432                                 │
│     length_str = '32.00MiB'                               │
│           used = 6701056                                  │
│       used_pct = 20                                       │
│       used_str = '6.39MiB'                                │
│          vaddr = 185118663376896
"""

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment