From 779452e9d16e820a9e3b91b208deebfe87058db7 Mon Sep 17 00:00:00 2001 From: ndwarshuis Date: Thu, 14 Jul 2022 18:02:47 -0400 Subject: [PATCH] ENH parameterize mem module --- drawing/memory.lua | 323 ++++++++++++++++++++++++--------------------- 1 file changed, 169 insertions(+), 154 deletions(-) diff --git a/drawing/memory.lua b/drawing/memory.lua index aa913f5..c69960b 100644 --- a/drawing/memory.lua +++ b/drawing/memory.lua @@ -5,7 +5,6 @@ local common = require 'common' local geometry = require 'geometry' local pure = require 'pure' - return function(update_freq) local MODULE_Y = 712 local DIAL_THICKNESS = 8 @@ -19,6 +18,140 @@ return function(update_freq) local TABLE_SECTION_BREAK = 20 local TABLE_HEIGHT = 114 + local __string_match = string.match + local __math_floor = math.floor + + ----------------------------------------------------------------------------- + -- header + + local mk_header = pure.partial( + common.mk_header, + 'MEMORY', + geometry.SECTION_WIDTH, + geometry.RIGHT_X + ) + + ----------------------------------------------------------------------------- + -- mem stats (dial + text) + + local mk_stats = function(y) + local MEM_X = geometry.RIGHT_X + DIAL_RADIUS + DIAL_THICKNESS / 2 + local DIAL_DIAMETER = DIAL_RADIUS * 2 + DIAL_THICKNESS + local SWAP_X = MEM_X + DIAL_DIAMETER + DIAL_SPACING + local CACHE_X = SWAP_X + CACHE_X_OFFSET + DIAL_DIAMETER / 2 + local CACHE_WIDTH = geometry.RIGHT_X + geometry.SECTION_WIDTH - CACHE_X + local format_percent = function(x) + return string.format('%i%%', x) + end + local mem = common.make_dial( + MEM_X, + y + DIAL_RADIUS, + DIAL_RADIUS, + DIAL_THICKNESS, + 80, + format_percent, + __math_floor + ) + local swap = common.make_dial( + SWAP_X, + y + DIAL_RADIUS, + DIAL_RADIUS, + DIAL_THICKNESS, + 80, + format_percent, + __math_floor + ) + local cache = common.make_text_rows_formatted( + CACHE_X, + y + CACHE_Y_OFFSET, + CACHE_WIDTH, + TEXT_SPACING, + {'Page Cache', 'Buffers', 'Shared', 'Kernel Slab'}, + '%.1f%%' + ) + local update = function(s) + local m = s.mem + local w = s.swap + common.dial_set(mem, m.used_percent * 100) + common.dial_set(swap, (w.total - w.free) / w.total * 100) + + common.text_rows_set(cache, 1, m.cached / m.total * 100) + common.text_rows_set(cache, 2, m.buffers / m.total * 100) + common.text_rows_set(cache, 3, m.shmem / m.total * 100) + common.text_rows_set(cache, 4, m.sreclaimable / m.total * 100) + end + local static = function(cr) + common.dial_draw_static(mem, cr) + common.dial_draw_static(swap, cr) + common.text_rows_draw_static(cache, cr) + end + local dynamic = function(cr) + common.dial_draw_dynamic(mem, cr) + common.dial_draw_dynamic(swap, cr) + common.text_rows_draw_dynamic(cache, cr) + end + return common.mk_acc(DIAL_DIAMETER, update, static, dynamic) + end + + ----------------------------------------------------------------------------- + -- memory consumption plot + + local mk_plot = function(y) + local obj = common.make_percent_timeseries( + geometry.RIGHT_X, + y, + geometry.SECTION_WIDTH, + PLOT_HEIGHT, + update_freq + ) + return common.mk_acc( + PLOT_HEIGHT, + function(s) timeseries.update(obj, s.mem.used_percent) end, + pure.partial(timeseries.draw_static, obj), + pure.partial(timeseries.draw_dynamic, obj) + ) + end + + ----------------------------------------------------------------------------- + -- memory top table + + local mk_tbl = function(y) + local NUM_ROWS = 5 + local TABLE_CONKY = pure.map_n( + function(i) + return { + comm = '${top_mem name '..i..'}', + pid = '${top_mem pid '..i..'}', + mem = '${top_mem mem '..i..'}', + } + end, + NUM_ROWS) + local obj = common.make_text_table( + geometry.RIGHT_X, + y, + geometry.SECTION_WIDTH, + TABLE_HEIGHT, + NUM_ROWS, + 'Mem (%)' + ) + local update = function(_) + for r = 1, NUM_ROWS do + text_table.set(obj, 1, r, i_o.conky(TABLE_CONKY[r].comm, '(%S+)')) + text_table.set(obj, 2, r, i_o.conky(TABLE_CONKY[r].pid)) + text_table.set(obj, 3, r, i_o.conky(TABLE_CONKY[r].mem)) + end + end + return common.mk_acc( + TABLE_HEIGHT, + update, + pure.partial(text_table.draw_static, obj), + pure.partial(text_table.draw_dynamic, obj) + ) + end + + ----------------------------------------------------------------------------- + -- state + local MEMINFO_REGEX = '\nMemFree:%s+(%d+).+'.. '\nBuffers:%s+(%d+).+'.. '\nCached:%s+(%d+).+'.. @@ -26,167 +159,49 @@ return function(update_freq) '\nShmem:%s+(%d+).+'.. '\nSReclaimable:%s+(%d+)' - local __string_match = string.match - local __math_floor = math.floor - - ----------------------------------------------------------------------------- - -- header - - local header = common.make_header( - geometry.RIGHT_X, - MODULE_Y, - geometry.SECTION_WIDTH, - 'MEMORY' - ) - - ----------------------------------------------------------------------------- - -- mem consumption dial - local get_meminfo_field = function(field) return tonumber(i_o.read_file('/proc/meminfo', field..':%s+(%d+)')) end - local memtotal = get_meminfo_field('MemTotal') - local swaptotal = get_meminfo_field('SwapTotal') - - local FORMAT_PERCENT = function(x) - return string.format('%i%%', x) + local state = { + mem = {total = get_meminfo_field('MemTotal')}, + swap = {total = get_meminfo_field('SwapTotal')} + } + local read_state = function() + local m = state.mem + -- see manpage for free command for formulas + m.memfree, + m.buffers, + m.cached, + state.swap.free, + m.shmem, + m.sreclaimable + = __string_match(i_o.read_file('/proc/meminfo'), MEMINFO_REGEX) + m.used_percent = + (m.total - + m.memfree - + m.cached - + m.buffers - + m.sreclaimable) / m.total + return state end - local MEM_X = geometry.RIGHT_X + DIAL_RADIUS + DIAL_THICKNESS / 2 - local MEM_Y = header.bottom_y + DIAL_RADIUS + DIAL_THICKNESS / 2 - local DIAL_DIAMETER = DIAL_RADIUS * 2 + DIAL_THICKNESS - - local mem = common.make_dial( - MEM_X, - MEM_Y, - DIAL_RADIUS, - DIAL_THICKNESS, - 80, - FORMAT_PERCENT, - __math_floor - ) - - ----------------------------------------------------------------------------- - -- swap consumption dial - - local SWAP_X = MEM_X + DIAL_DIAMETER + DIAL_SPACING - - local swap = common.make_dial( - SWAP_X, - MEM_Y, - DIAL_RADIUS, - DIAL_THICKNESS, - 80, - FORMAT_PERCENT, - __math_floor - ) - - ----------------------------------------------------------------------------- - -- swap/buffers stats - - local CACHE_Y = header.bottom_y + CACHE_Y_OFFSET - local CACHE_X = SWAP_X + CACHE_X_OFFSET + DIAL_DIAMETER / 2 - local CACHE_WIDTH = geometry.RIGHT_X + geometry.SECTION_WIDTH - CACHE_X - - local cache = common.make_text_rows_formatted( - CACHE_X, - CACHE_Y, - CACHE_WIDTH, - TEXT_SPACING, - {'Page Cache', 'Buffers', 'Shared', 'Kernel Slab'}, - '%.1f%%' - ) - - ----------------------------------------------------------------------------- - -- memory consumption plot - - local PLOT_Y = header.bottom_y + PLOT_SECTION_BREAK + DIAL_DIAMETER - - local plot = common.make_percent_timeseries( - geometry.RIGHT_X, - PLOT_Y, - geometry.SECTION_WIDTH, - PLOT_HEIGHT, - update_freq - ) - - ----------------------------------------------------------------------------- - -- memory top table - - local NUM_ROWS = 5 - local TABLE_CONKY = pure.map_n( - function(i) - return { - comm = '${top_mem name '..i..'}', - pid = '${top_mem pid '..i..'}', - mem = '${top_mem mem '..i..'}', - } - end, - NUM_ROWS) - - local tbl = common.make_text_table( - geometry.RIGHT_X, - PLOT_Y + PLOT_HEIGHT + TABLE_SECTION_BREAK, - geometry.SECTION_WIDTH, - TABLE_HEIGHT, - NUM_ROWS, - 'Mem (%)' - ) - ----------------------------------------------------------------------------- -- main functions - local update = function() - -- see manpage for free command for formulas - local memfree, - buffers, - cached, - swapfree, - shmem, - sreclaimable - = __string_match(i_o.read_file('/proc/meminfo'), MEMINFO_REGEX) + local rbs = common.reduce_blocks_( + MODULE_Y, + { + common.mk_block(mk_header, true, 0), + common.mk_block(mk_stats, true, 0), + common.mk_block(mk_plot, true, PLOT_SECTION_BREAK), + common.mk_block(mk_tbl, true, TABLE_SECTION_BREAK), + } + ) - local used_percent = - (memtotal - - memfree - - cached - - buffers - - sreclaimable) / memtotal - - common.dial_set(mem, used_percent * 100) - common.dial_set(swap, (swaptotal - swapfree) / swaptotal * 100) - - common.text_rows_set(cache, 1, cached / memtotal * 100) - common.text_rows_set(cache, 2, buffers / memtotal * 100) - common.text_rows_set(cache, 3, shmem / memtotal * 100) - common.text_rows_set(cache, 4, sreclaimable / memtotal * 100) - - timeseries.update(plot, used_percent) - - for r = 1, NUM_ROWS do - text_table.set(tbl, 1, r, i_o.conky(TABLE_CONKY[r].comm, '(%S+)')) - text_table.set(tbl, 2, r, i_o.conky(TABLE_CONKY[r].pid)) - text_table.set(tbl, 3, r, i_o.conky(TABLE_CONKY[r].mem)) - end - end - - local draw_static = function(cr) - common.draw_header(cr, header) - common.dial_draw_static(mem, cr) - common.dial_draw_static(swap, cr) - common.text_rows_draw_static(cache, cr) - timeseries.draw_static(plot, cr) - text_table.draw_static(tbl, cr) - end - - local draw_dynamic = function(cr) - common.dial_draw_dynamic(mem, cr) - common.dial_draw_dynamic(swap, cr) - common.text_rows_draw_dynamic(cache, cr) - timeseries.draw_dynamic(plot, cr) - text_table.draw_dynamic(tbl, cr) - end - - return {dynamic = draw_dynamic, static = draw_static, update = update} + return { + static = rbs.static_drawer, + dynamic = rbs.dynamic_drawer, + update = function() rbs.updater(read_state()) end, + } end