#!/usr/bin/python3 import json import subprocess def main(args): res = {} ARCSTATS = open('/proc/spl/kstat/zfs/arcstats', 'r') LINES = ARCSTATS.readlines() LINES = [x.strip() for x in LINES] STATS = {} for line in LINES[2:]: splitline = line.split() STATS[splitline[0]] = int(splitline[2]) # ARC misc DELETED = STATS['deleted'] EVICT_SKIP = STATS['evict_skip'] MUTEX_SKIP = STATS['mutex_miss'] RECYCLE_MISS = STATS['recycle_miss'] if 'recycle_miss' in STATS else 0 # ARC size ARC_SIZE = STATS['size'] TARGET_SIZE_MAX = STATS['c_max'] TARGET_SIZE_MIN = STATS['c_min'] TARGET_SIZE = STATS['c'] TARGET_SIZE_PERCENT = TARGET_SIZE / TARGET_SIZE_MAX * 100 ARC_SIZE_PERCENT = ARC_SIZE / TARGET_SIZE_MAX * 100 TARGET_SIZE_ADAPTIVE_RATIO = TARGET_SIZE / TARGET_SIZE_MAX MIN_SIZE_PERCENT = TARGET_SIZE_MIN / TARGET_SIZE_MAX * 100 # ARC size breakdown MFU_SIZE = 0 RECENTLY_USED_PERCENT = 0 FREQUENTLY_USED_PERCENT = 0 P = STATS['p'] if ARC_SIZE >= TARGET_SIZE: MFU_SIZE = ARC_SIZE - P RECENTLY_USED_PERCENT = P / ARC_SIZE * 100 FREQUENTLY_USED_PERCENT = MFU_SIZE / ARC_SIZE * 100 else: MFU_SIZE = TARGET_SIZE - P RECENTLY_USED_PERCENT = P / TARGET_SIZE * 100 FREQUENTLY_USED_PERCENT = MFU_SIZE / TARGET_SIZE * 100 # ARC misc. efficient stats ARC_HITS = STATS['hits'] ARC_MISSES = STATS['misses'] DEMAND_DATA_HITS = STATS['demand_data_hits'] DEMAND_DATA_MISSES = STATS['demand_data_misses'] DEMAND_METADATA_HITS = STATS['demand_metadata_hits'] DEMAND_METADATA_MISSES = STATS['demand_metadata_misses'] MFU_GHOST_HITS = STATS['mfu_ghost_hits'] MFU_HITS = STATS['mfu_hits'] MRU_GHOST_HITS = STATS['mru_ghost_hits'] MRU_HITS = STATS['mru_hits'] PREFETCH_DATA_HITS = STATS['prefetch_data_hits'] PREFETCH_DATA_MISSES = STATS['prefetch_data_misses'] PREFETCH_METADATA_HITS = STATS['prefetch_metadata_hits'] PREFETCH_METADATA_MISSES = STATS['prefetch_metadata_misses'] ANON_HITS = ARC_HITS - (MFU_HITS + MRU_HITS + MFU_GHOST_HITS + MRU_GHOST_HITS) ARC_ACCESSES_TOTAL = ARC_HITS + ARC_MISSES DEMAND_DATA_TOTAL = DEMAND_DATA_HITS + DEMAND_DATA_MISSES PREFETCH_DATA_TOTAL = PREFETCH_DATA_HITS + PREFETCH_DATA_MISSES REAL_HITS = MFU_HITS + MRU_HITS # ARC efficiency percentages CACHE_HIT_PERCENT = ARC_HITS / ARC_ACCESSES_TOTAL * 100 CACHE_MISS_PERCENT = ARC_MISSES / ARC_ACCESSES_TOTAL * 100 ACTUAL_HIT_PERCENT = REAL_HITS / ARC_ACCESSES_TOTAL * 100 DATA_DEMAND_PERCENT = DEMAND_DATA_HITS / DEMAND_DATA_TOTAL * 100 DATA_PREFETCH_PERCENT = PREFETCH_DATA_HITS / PREFETCH_DATA_TOTAL * 100 if PREFETCH_DATA_TOTAL != 0 else 0 ANON_HITS_PERCENT = ANON_HITS / ARC_HITS * 100 if ANON_HITS != 0 else 0 MRU_PERCENT = MRU_HITS / ARC_HITS * 100 MFU_PERCENT = MFU_HITS / ARC_HITS * 100 MRU_GHOST_PERCENT = MRU_GHOST_HITS / ARC_HITS * 100 MFU_GHOST_PERCENT = MFU_GHOST_HITS / ARC_HITS * 100 DEMAND_HITS_PERCENT = DEMAND_DATA_HITS / ARC_HITS * 100 PREFETCH_HITS_PERCENT = PREFETCH_DATA_HITS / ARC_HITS * 100 METADATA_HITS_PERCENT = DEMAND_METADATA_HITS / ARC_HITS * 100 PREFETCH_METADATA_HITS_PERCENT = DEMAND_METADATA_HITS / ARC_HITS * 100 DEMAND_MISSES_PERCENT = DEMAND_DATA_MISSES / ARC_MISSES * 100 PREFETCH_MISSES_PERCENT = PREFETCH_DATA_MISSES / ARC_MISSES * 100 METADATA_MISSES_PERCENT = DEMAND_METADATA_MISSES / ARC_MISSES * 100 PREFETCH_METADATA_MISSES_PERCENT = DEMAND_METADATA_MISSES / ARC_MISSES * 100 # pools proc = subprocess.run(['/sbin/zpool', 'list', '-pH'], stdout=subprocess.PIPE, universal_newlines=True) if proc.returncode != 0: return proc.returncode pools = [] FIELDS = ['name', 'size', 'alloc', 'free', 'expandsz', 'frag', 'cap', 'dedup'] for line in proc.stdout.splitlines(): info = dict(zip(FIELDS, line.split('\t'))) info['expandsz'] = 0 if info['expandsz'] == '-' else info['expandsz'] info['frag'] = info['frag'].rstrip('%') info['frag'] = 0 if info['frag'] == '-' else info['frag'] info['dedup'] = info['dedup'].rstrip('x') info['cap'] = info['cap'].rstrip('%') pools.append(info) res = { 'deleted': DELETED, # ARC misc 'evict_skip': EVICT_SKIP, 'mutex_skip': MUTEX_SKIP, 'recycle_miss': RECYCLE_MISS, 'arc_size': ARC_SIZE, # ARC size 'target_size_max': TARGET_SIZE_MAX, 'target_size_min': TARGET_SIZE_MIN, 'target_size': TARGET_SIZE, 'target_size_per': TARGET_SIZE_PERCENT, 'arc_size_per': ARC_SIZE_PERCENT, 'target_size_arat': TARGET_SIZE_ADAPTIVE_RATIO, 'min_size_per': MIN_SIZE_PERCENT, 'mfu_size': MFU_SIZE, # ARC size breakdown 'p': P, 'rec_used_per': RECENTLY_USED_PERCENT, 'freq_used_per': FREQUENTLY_USED_PERCENT, 'arc_hits': ARC_HITS, # ARC efficiency 'arc_misses': ARC_MISSES, 'demand_data_hits': DEMAND_DATA_HITS, 'demand_data_misses': DEMAND_DATA_MISSES, 'demand_meta_hits': DEMAND_METADATA_HITS, 'demand_meta_misses': DEMAND_METADATA_MISSES, 'mfu_ghost_hits': MFU_GHOST_HITS, 'mfu_hits': MFU_HITS, 'mru_ghost_hits': MRU_GHOST_HITS, 'mru_hits': MRU_HITS, 'pre_data_hits': PREFETCH_DATA_HITS, 'pre_data_misses': PREFETCH_DATA_MISSES, 'pre_meta_hits': PREFETCH_METADATA_HITS, 'pre_meta_misses': PREFETCH_METADATA_HITS, 'anon_hits': ANON_HITS, 'arc_accesses_total': ARC_ACCESSES_TOTAL, 'demand_data_total': DEMAND_DATA_TOTAL, 'pre_data_total': PREFETCH_DATA_TOTAL, 'real_hits': REAL_HITS, 'cache_hits_per': CACHE_HIT_PERCENT, # ARC efficiency percentages 'cache_miss_per': CACHE_MISS_PERCENT, 'actual_hit_per': ACTUAL_HIT_PERCENT, 'data_demand_per': DATA_DEMAND_PERCENT, 'data_pre_per': DATA_PREFETCH_PERCENT, 'anon_hits_per': ANON_HITS_PERCENT, 'mru_per': MRU_PERCENT, 'mfu_per': MFU_PERCENT, 'mru_ghost_per': MRU_GHOST_PERCENT, 'mfu_ghost_per': MFU_GHOST_PERCENT, 'demand_hits_per': DEMAND_HITS_PERCENT, 'pre_hits_per': PREFETCH_HITS_PERCENT, 'meta_hits_per': METADATA_HITS_PERCENT, 'pre_meta_hits_per': PREFETCH_METADATA_HITS_PERCENT, 'demand_misses_per': DEMAND_MISSES_PERCENT, 'pre_misses_per': PREFETCH_MISSES_PERCENT, 'meta_misses_per': METADATA_MISSES_PERCENT, 'pre_meta_misses_per': PREFETCH_METADATA_MISSES_PERCENT, 'pools': pools } print(json.dumps(res)) return 0 if __name__ == '__main__': import sys sys.exit(main(sys.argv[1:]))