ZFS ARC/cache not reported as cache memory usage #3279

This commit is contained in:
nicolargo 2025-09-14 12:35:59 +02:00 committed by Bennett Kanuka
parent 6631b37d67
commit b26dac4dd5
5 changed files with 223 additions and 1 deletions

34
glances/plugins/fs/zfs.py Normal file
View File

@ -0,0 +1,34 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2025 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
# For the moment, thoses functions are only used in the MEM plugin (see #3979)
import os
from glances.logger import logger
def zfs_enable(zfs_stats_path='/proc/spl/kstat/zfs'):
"""Check if ZFS is enabled on this system."""
return os.path.isdir(zfs_stats_path)
def zfs_stats(zfs_stats_files=['/proc/spl/kstat/zfs/arcstats']):
"""Get ZFS stats from /proc/spl/kstat/zfs files."""
stats = {}
for zfs_stats_file in zfs_stats_files:
try:
with open(zfs_stats_file) as f:
lines = f.readlines()
namespace = os.path.basename(zfs_stats_file)
for line in lines[2:]: # Skip the first two header lines
parts = line.split()
stats[namespace + '.' + parts[0]] = int(parts[2])
except Exception as e:
logger.error(f"Error reading ZFS stats in {zfs_stats_file}: {e}")
return stats

View File

@ -1,7 +1,7 @@
#
# This file is part of Glances.
#
# SPDX-FileCopyrightText: 2022 Nicolas Hennion <nicolas@nicolargo.com>
# SPDX-FileCopyrightText: 2025 Nicolas Hennion <nicolas@nicolargo.com>
#
# SPDX-License-Identifier: LGPL-3.0-only
#
@ -10,6 +10,7 @@
import psutil
from glances.plugins.fs.zfs import zfs_enable, zfs_stats
from glances.plugins.plugin.model import GlancesPluginModel
# Fields description
@ -124,6 +125,9 @@ class MemPlugin(GlancesPluginModel):
args=args, config=config, items_history_list=items_history_list, fields_description=fields_description
)
# ZFS
self.zfs_enabled = zfs_enable()
# We want to display the stat in the curse interface
self.display_curse = True
@ -167,6 +171,26 @@ class MemPlugin(GlancesPluginModel):
if hasattr(vm_stats, mem):
stats[mem] = getattr(vm_stats, mem)
# Manage ZFS cache (see #3979 for details)
if self.zfs_enabled:
zfs_shrink = 0
zfs_cache_stats = zfs_stats()
# Uncomment the following line to use the test data
# zfs_cache_stats = zfs_stats(['./tests-data/plugins/fs/zfs/arcstats'])
if 'arcstats.size' in zfs_cache_stats:
zfs_size = zfs_cache_stats['arcstats.size']
if 'arcstats.c_min' in zfs_cache_stats:
zfs_cmin = zfs_cache_stats['arcstats.c_min']
else:
zfs_cmin = 0
if zfs_size > zfs_cmin:
zfs_shrink = zfs_size - zfs_cmin
# Add the ZFS cache to the 'cached' memory
if 'cached' in stats:
stats['cached'] += zfs_shrink
else:
stats['cached'] = zfs_shrink
# Use the 'free'/htop calculation
# free=available+buffer+cached
stats['free'] = stats['available']

View File

@ -247,3 +247,6 @@ log_cli = false
log_level = "INFO"
#log_cli_format = "%(asctime)s [%(levelname)8s] %(message)s (%(filename)s:%(lineno)s)"
#log_cli_date_format = "%Y-%m-%d %H:%M:%S"
[tool.flake8]
max-line-length = 120

View File

@ -0,0 +1,149 @@
9 1 0x01 147 39984 22179924650 77805722884984
name type data
hits 4 163573507
iohits 4 1112419
misses 4 16368761
demand_data_hits 4 72451565
demand_data_iohits 4 803830
demand_data_misses 4 2130504
demand_metadata_hits 4 90322004
demand_metadata_iohits 4 33395
demand_metadata_misses 4 1259616
prefetch_data_hits 4 5100
prefetch_data_iohits 4 54
prefetch_data_misses 4 12846585
prefetch_metadata_hits 4 794838
prefetch_metadata_iohits 4 275140
prefetch_metadata_misses 4 132056
mru_hits 4 40587444
mru_ghost_hits 4 119612
mfu_hits 4 122986063
mfu_ghost_hits 4 792
uncached_hits 4 0
deleted 4 240714336
mutex_miss 4 29651
access_skip 4 17
evict_skip 4 3
evict_not_enough 4 0
evict_l2_cached 4 779348272640
evict_l2_eligible 4 3032617077760
evict_l2_eligible_mfu 4 64470016
evict_l2_eligible_mru 4 3032552607744
evict_l2_ineligible 4 112752640
evict_l2_skip 4 0
hash_elements 4 4708410
hash_elements_max 4 9041764
hash_collisions 4 80682806
hash_chains 4 549398
hash_chain_max 4 8
meta 4 1120493253
pd 4 2140686966
pm 4 2225035009
c 4 60312499360
c_min 4 2637352832
c_max 4 69793218560
size 4 41321273080
compressed_size 4 35897732096
uncompressed_size 4 65567515648
overhead_size 4 2501788672
hdr_size 4 1134386336
data_size 4 32250192896
metadata_size 4 6149327872
dbuf_size 4 450035208
dnode_size 4 984383760
bonus_size 4 308172480
anon_size 4 20157952
anon_data 4 19607552
anon_metadata 4 550400
anon_evictable_data 4 0
anon_evictable_metadata 4 0
mru_size 4 35167577600
mru_data 4 29692877824
mru_metadata 4 5474699776
mru_evictable_data 4 27496793600
mru_evictable_metadata 4 4834513920
mru_ghost_size 4 21166751744
mru_ghost_data 4 2506145792
mru_ghost_metadata 4 18660605952
mru_ghost_evictable_data 4 2506145792
mru_ghost_evictable_metadata 4 18660605952
mfu_size 4 3211785216
mfu_data 4 2537707520
mfu_metadata 4 674077696
mfu_evictable_data 4 1617436160
mfu_evictable_metadata 4 204706304
mfu_ghost_size 4 76094464
mfu_ghost_data 4 76094464
mfu_ghost_metadata 4 0
mfu_ghost_evictable_data 4 76094464
mfu_ghost_evictable_metadata 4 0
uncached_size 4 0
uncached_data 4 0
uncached_metadata 4 0
uncached_evictable_data 4 0
uncached_evictable_metadata 4 0
l2_hits 4 143402
l2_misses 4 12645465
l2_prefetch_asize 4 6069248
l2_mru_asize 4 361556480
l2_mfu_asize 4 1765280768
l2_bufc_data_asize 4 2019670016
l2_bufc_metadata_asize 4 113236480
l2_feeds 4 127414
l2_rw_clash 4 0
l2_read_bytes 4 1315843584
l2_write_bytes 4 763235489792
l2_writes_sent 4 90085
l2_writes_done 4 90085
l2_writes_error 4 0
l2_writes_lock_retry 4 256
l2_evict_lock_retry 4 93
l2_evict_reading 4 0
l2_evict_l1cached 4 12729
l2_free_on_write 4 76388
l2_abort_lowmem 4 18
l2_cksum_bad 4 0
l2_io_error 4 0
l2_size 4 3095654400
l2_asize 4 2132906496
l2_hdr_size 4 852096
l2_log_blk_writes 4 6134
l2_log_blk_avg_asize 4 16195
l2_log_blk_asize 4 60463616
l2_log_blk_count 4 4242
l2_data_to_meta_ratio 4 220
l2_rebuild_success 4 0
l2_rebuild_unsupported 4 1
l2_rebuild_io_errors 4 0
l2_rebuild_dh_errors 4 0
l2_rebuild_cksum_lb_errors 4 0
l2_rebuild_lowmem 4 0
l2_rebuild_size 4 0
l2_rebuild_asize 4 0
l2_rebuild_bufs 4 0
l2_rebuild_bufs_precached 4 0
l2_rebuild_log_blks 4 0
memory_throttle_count 4 0
memory_direct_count 4 0
memory_indirect_count 4 2690
memory_all_bytes 4 84395290624
memory_free_bytes 4 26664001536
memory_available_bytes 3 23747772544
arc_no_grow 4 0
arc_tempreserve 4 0
arc_loaned_bytes 4 0
arc_prune 4 0
arc_meta_used 4 9027157752
arc_dnode_limit 4 6979321856
async_upgrade_sync 4 804060
predictive_prefetch 4 14053359
demand_hit_predictive_prefetch 4 12183015
demand_iohit_predictive_prefetch 4 828711
prescient_prefetch 4 414
demand_hit_prescient_prefetch 4 333
demand_iohit_prescient_prefetch 4 81
arc_need_free 4 0
arc_sys_free 4 2916228992
arc_raw_size 4 0
cached_only_in_progress 4 0
abd_chunk_waste_size 4 43922432

View File

@ -29,6 +29,7 @@ from glances.filter import GlancesFilter, GlancesFilterList
from glances.globals import LINUX, WINDOWS, pretty_date, string_value_to_float, subsample
from glances.main import GlancesMain
from glances.outputs.glances_bars import Bar
from glances.plugins.fs.zfs import zfs_enable, zfs_stats
from glances.plugins.plugin.model import GlancesPluginModel
from glances.stats import GlancesStats
from glances.thresholds import (
@ -671,6 +672,17 @@ class TestGlances(unittest.TestCase):
print('INFO: [TEST_107] Test fs plugin methods')
self._common_plugin_tests('fs')
def test_108_fs_zfs_(self):
"""Test zfs functions"""
print('INFO: [TEST_108] Test zfs functions')
self.assertTrue(zfs_enable('./tests-data/plugins/fs/zfs'))
stats = zfs_stats(['./tests-data/plugins/fs/zfs/arcstats'])
self.assertTrue(isinstance(stats, dict))
self.assertTrue('arcstats.c_min' in stats)
self.assertEqual(stats['arcstats.c_min'], 2637352832)
self.assertTrue('arcstats.size' in stats)
self.assertEqual(stats['arcstats.size'], 41321273080)
def test_200_views_hidden(self):
"""Test hide feature"""
print('INFO: [TEST_200] Test views hidden feature')