ENH make processor and other low level functions more functional

This commit is contained in:
Nathan Dwarshuis 2022-07-23 21:50:31 -04:00
parent e5f5e54eec
commit 75359e281f
3 changed files with 105 additions and 58 deletions

View File

@ -85,22 +85,19 @@ return function(update_freq, config, main_state, common, width, point)
cores[c] = create_core(dial_x, dial_y) cores[c] = create_core(dial_x, dial_y)
end end
local coretemp_paths = cpu.get_coretemp_paths() local coretemp_paths = cpu.get_coretemp_paths()
local update_coretemps if #coretemp_paths ~= ncores then
if coretemp_paths ~= nil then i_o.warnf('could not find all coretemp paths')
update_coretemps = function() end
for conky_core_id, path in pairs(coretemp_paths) do local update_coretemps = function()
local temp = __math_floor(0.001 * i_o.read_file(path, nil, '*n')) for conky_core_idx, path in pairs(coretemp_paths) do
common.text_circle_set(cores[conky_core_id].coretemp, temp) local temp = __math_floor(0.001 * i_o.read_file(path, nil, '*n'))
end common.text_circle_set(cores[conky_core_idx].coretemp, temp)
end end
else
i_o.warnf('could not find coretemp paths; disabling temp readings')
update_coretemps = function() end
end end
local update = function() local update = function()
for _, load_data in pairs(mod_state) do for _, load_data in pairs(mod_state) do
compound_dial.set( compound_dial.set(
cores[load_data.conky_core_id].loads, cores[load_data.conky_core_idx].loads,
load_data.conky_thread_id, load_data.conky_thread_id,
load_data.percent_active * 100 load_data.percent_active * 100
) )

View File

@ -2,7 +2,6 @@ local M = {}
local err = require 'err' local err = require 'err'
local __string_gmatch = string.gmatch
local __math_floor = math.floor local __math_floor = math.floor
local __table_insert = table.insert local __table_insert = table.insert
@ -118,6 +117,14 @@ M.rep = function(n, x)
return r return r
end end
M.array_to_map = function(arr)
local r = {}
for i = 1, #arr do
r[arr[i][1]] = arr[i][2]
end
return r
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- random list things -- random list things
@ -177,10 +184,20 @@ M.table_array = function(tbl)
return r return r
end end
M.gmatch_table = function(pat, s) M.iter_to_table1 = function(iter)
local r = {} local r = {}
for m in __string_gmatch(s, pat) do for next in iter do
__table_insert(r, m) __table_insert(r, next)
end
return r
end
M.iter_to_tableN = function(iter)
local r = {}
local next = {iter()}
while #next > 0 do
__table_insert(r, next)
next = {iter()}
end end
return r return r
end end
@ -262,6 +279,10 @@ M.maybe = function(def, f, x)
end end
end end
M.fmap_maybe = function(f, x)
return M.maybe(nil, f, x)
end
-- round to whole numbers since I don't need more granularity and extra values -- round to whole numbers since I don't need more granularity and extra values
-- will lead to cache misses -- will lead to cache misses
M.round_percent = __math_floor M.round_percent = __math_floor

View File

@ -16,6 +16,14 @@ local read_micro = function(path)
return i_o.read_file(path, nil, '*n') * 0.000001 return i_o.read_file(path, nil, '*n') * 0.000001
end end
local gmatch_to_table1 = function(pat, s)
return pure.iter_to_table1(__string_gmatch(s, pat))
end
local gmatch_to_tableN = function(pat, s)
return pure.iter_to_tableN(__string_gmatch(s, pat))
end
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- memory -- memory
@ -155,9 +163,8 @@ local NET_DIR = '/sys/class/net'
local get_interfaces = function() local get_interfaces = function()
local cmd = string.format('realpath %s/* | grep -v virtual', NET_DIR) local cmd = string.format('realpath %s/* | grep -v virtual', NET_DIR)
local s = i_o.execute_cmd(cmd) local f = pure.partial(gmatch_to_table1, '/([^/\n]+)\n')
local f = pure.partial(pure.gmatch_table, '/([^/\n]+)\n') return pure.maybe({}, f, i_o.execute_cmd(cmd))
return pure.maybe({}, f, s)
end end
M.get_net_interface_paths = function() M.get_net_interface_paths = function()
@ -187,62 +194,74 @@ end
local get_coretemp_dir = function() local get_coretemp_dir = function()
i_o.assert_exe_exists('grep') i_o.assert_exe_exists('grep')
local s = i_o.execute_cmd('grep -l \'^coretemp$\' /sys/class/hwmon/*/name') local s = i_o.execute_cmd('grep -l \'^coretemp$\' /sys/class/hwmon/*/name')
if s == nil then return else return dirname(s) end return pure.fmap_maybe(dirname, s)
end end
-- map cores to integer values starting at 1; this is necessary since some cpus -- map cores to integer values starting at 1; this is necessary since some cpus
-- don't report their core id's as a sequence of integers starting at 0 -- don't report their core id's as a sequence of integers starting at 0
local get_core_id_mapper = function() local get_core_id_indexer = function()
local s = i_o.execute_cmd('lscpu -p=CORE | tail -n+5 | sort | uniq') local make_indexer = pure.compose(
local m = {} pure.array_to_map,
local i = 1 pure.partial(pure.imap, function(i, c) return {tonumber(c), i} end),
for core_id in string.gmatch(s, '(%d+)') do pure.partial(gmatch_to_table1, '(%d+)')
m[tonumber(core_id)] = i )
i = i + 1 return pure.fmap_maybe(
end make_indexer,
return m i_o.execute_cmd('lscpu -p=CORE | tail -n+5 | sort | uniq')
)
end end
local get_core_mappings = function() local get_core_mappings = function()
local ncpus = M.get_cpu_number() local ncpus = M.get_cpu_number()
local ncores = M.get_core_number() local ncores = M.get_core_number()
local nthreads = ncpus / ncores local nthreads = ncpus / ncores
local core_id_mapper = get_core_id_mapper() local map_ids = function(indexer)
local conky_thread_ids = pure.rep(ncores, nthreads) local f = function(acc, next)
local core_mappings = {} local cpu_id = tonumber(next[1]) + 1
local s = i_o.execute_cmd('lscpu -p=cpu,CORE | tail -n+5') local core_id = next[2]
for cpu_id, core_id in string.gmatch(s, '(%d+),(%d+)') do local conky_core_idx = indexer[tonumber(core_id)]
local conky_core_id = core_id_mapper[tonumber(core_id)] acc.mappings[cpu_id] = {
local conky_cpu_id = tonumber(cpu_id) + 1 conky_core_idx = conky_core_idx,
core_mappings[conky_cpu_id] = { conky_thread_id = acc.thread_ids[conky_core_idx],
conky_core_id = conky_core_id, }
conky_thread_id = conky_thread_ids[conky_core_id], acc.thread_ids[conky_core_idx] = acc.thread_ids[conky_core_idx] - 1
} return acc
conky_thread_ids[conky_core_id] = conky_thread_ids[conky_core_id] - 1 end
local cpu_to_core_map = pure.maybe(
{},
pure.partial(gmatch_to_tableN, '(%d+),(%d+)'),
i_o.execute_cmd('lscpu -p=cpu,CORE | tail -n+5')
)
local init = {mappings = {}, thread_ids = pure.rep(ncores, nthreads)}
return pure.reduce(f, init, cpu_to_core_map).mappings
end end
return core_mappings return pure.fmap_maybe(map_ids, get_core_id_indexer())
end end
M.get_coretemp_paths = function() M.get_coretemp_paths = function()
local d = get_coretemp_dir() local get_paths = function(indexer)
if d == nil then return end local d = get_coretemp_dir()
i_o.assert_exe_exists('grep') local get_labels = function(dir)
local s = i_o.execute_cmd(string.format('grep Core %s/temp*_label', d)) i_o.assert_exe_exists('grep')
local ps = {} return i_o.execute_cmd(string.format('grep Core %s/temp*_label', dir))
local core_id_mapper = get_core_id_mapper() end
for temp_name, core_id in string.gmatch(s, '/([^/\n]+)_label:Core (%d+)\n') do local to_tuple = function(m)
ps[core_id_mapper[tonumber(core_id)]] = string.format('%s/%s_input', d, temp_name) return {
indexer[tonumber(m[2])],
string.format('%s/%s_input', d, m[1])
}
end
local f = pure.compose(
pure.array_to_map,
pure.partial(pure.map, to_tuple),
pure.partial(gmatch_to_tableN, '/([^/\n]+)_label:Core (%d+)\n')
)
return pure.maybe({}, f, pure.fmap_maybe(get_labels, d))
end end
return ps return pure.maybe({}, get_paths, get_core_id_indexer())
end end
M.read_freq = function() local match_freq = function(c)
-- NOTE: Using the builtin conky functions for getting cpu freq seems to make
-- the entire loop jittery due to high variance latency. Querying
-- scaling_cur_freq in sysfs seems to do the same thing. It appears lscpu
-- (which queries /proc/cpuinfo) is much faster and doesn't have this jittery
-- problem.
local c = i_o.execute_cmd('lscpu -p=MHZ')
local f = 0 local f = 0
local n = 0 local n = 0
for s in __string_gmatch(c, '(%d+%.%d+)') do for s in __string_gmatch(c, '(%d+%.%d+)') do
@ -252,7 +271,17 @@ M.read_freq = function()
return __string_format('%.0f Mhz', f / n) return __string_format('%.0f Mhz', f / n)
end end
M.read_freq = function()
-- NOTE: Using the builtin conky functions for getting cpu freq seems to make
-- the entire loop jittery due to high variance latency. Querying
-- scaling_cur_freq in sysfs seems to do the same thing. It appears lscpu
-- (which queries /proc/cpuinfo) is much faster and doesn't have this jittery
-- problem.
return pure.maybe('N/A', match_freq, i_o.execute_cmd('lscpu -p=MHZ'))
end
M.get_hwp_paths = function() M.get_hwp_paths = function()
-- ASSUME this will never fail
return pure.map_n( return pure.map_n(
function(i) function(i)
return '/sys/devices/system/cpu/cpu' return '/sys/devices/system/cpu/cpu'
@ -301,7 +330,7 @@ M.init_cpu_loads = function()
active_prev = 0, active_prev = 0,
total_prev = 0, total_prev = 0,
percent_active = 0, percent_active = 0,
conky_core_id = core.conky_core_id, conky_core_idx = core.conky_core_idx,
conky_thread_id = core.conky_thread_id, conky_thread_id = core.conky_thread_id,
} }
end end