From 30e58fb383bd2d3a767648fd104b46a6f83cb4f5 Mon Sep 17 00:00:00 2001 From: Kajetan Staszkiewicz Date: Tue, 13 Feb 2024 18:22:15 +0100 Subject: [PATCH] Collect UMA stats --- igcollect/freebsd_memory.py | 74 ++++++++++++++++++++++++++----------- 1 file changed, 53 insertions(+), 21 deletions(-) diff --git a/igcollect/freebsd_memory.py b/igcollect/freebsd_memory.py index 8f95f9a..9937a60 100755 --- a/igcollect/freebsd_memory.py +++ b/igcollect/freebsd_memory.py @@ -1,14 +1,15 @@ #!/usr/bin/env python """igcollect - FreeBSD Memory Usage -Copyright (c) 2016 InnoGames GmbH +Copyright (c) 2024 InnoGames GmbH """ -from __future__ import print_function +import re from argparse import ArgumentParser from time import time import sysctl +UMA_STATS = ('size', 'stats.frees', 'stats.allocs', 'stats.current') def parse_args(): parser = ArgumentParser() @@ -16,6 +17,55 @@ def parse_args(): return parser.parse_args() +def main(): + args = parse_args() + now = str(int(time())) + + mi = parse_memory_info() + mem_gap_sys = mi['physmem'] - mi['v_page'] + + template = args.prefix + '.{} {} ' + now + print(template.format('total', mi['physmem'])) + print(template.format('active', mi['v_active'])) + print(template.format('inactive', mi['v_inactive'])) + print(template.format('wired', mi['v_wire'])) + print(template.format('cache', mi['v_cache'])) + print(template.format('free', mi['v_free'])) + print(template.format('gap_sys', mem_gap_sys)) + + ui = parse_uma_info() + for zone, data in ui.items(): + for metric, value in data.items(): + print(template.format(f'uma.{zone}.{metric}', value)) + + +# Fix for missing long types +def parse_sysctl_value(a): + if type(a.value) == bytearray: + return int.from_bytes(a.value, byteorder='little', signed=False) + return a.value + + +def parse_uma_info(): + uma_info = {} + + # The sysctl python module does not seem to dig into sysctl data correctly. + # It retrieves all OIDs with proper names but the values are always None. + # Fetch the list once, build the list of known UMA zones. + for line in sysctl.filter('vm.uma'): + s = line.name.split('.') + if len(s) == 3: + uma_info[s[2]] = {} + + # Fetch the real data in a separate step only for wanted OIDs. + for oid in uma_info.keys(): + for metric in UMA_STATS: + for line in sysctl.filter(f'vm.uma.{oid}.{metric}'): + uma_info[oid][metric] = parse_sysctl_value(line) + uma_info[oid]['malloc'] = uma_info[oid]['size'] * uma_info[oid]['stats.current'] + + return uma_info + def parse_memory_info(): memory_info={} @@ -28,31 +78,13 @@ def parse_memory_info(): # After multiplying by page size they are not _count anymore if name.endswith('_count'): name = name.replace('_count', '') - if type(line.value) == bytearray: - # py-sysctl lack support for CTLTYPE_U32 - # https://lists.freebsd.org/pipermail/freebsd-current/2018-July/070344.html - value = int.from_bytes(line.value, byteorder='little', signed=False) - else: - value = line.value + value = parse_sysctl_value(line) memory_info[name] = value * pagesize return memory_info -def main(): - args = parse_args() - mi = parse_memory_info() - mem_gap_sys = mi['physmem'] - mi['v_page'] - - template = args.prefix + '.{} {} ' + str(int(time())) - print(template.format('total', mi['physmem'])) - print(template.format('active', mi['v_active'])) - print(template.format('inactive', mi['v_inactive'])) - print(template.format('wired', mi['v_wire'])) - print(template.format('cache', mi['v_cache'])) - print(template.format('free', mi['v_free'])) - print(template.format('gap_sys', mem_gap_sys)) if __name__ == '__main__': main()