FIX freq and cpu calculation errors
This commit is contained in:
parent
e7d5b63c38
commit
da9a6b0c46
|
@ -6,6 +6,7 @@ local cpu = require 'sys'
|
|||
local pure = require 'pure'
|
||||
|
||||
local __math_floor = math.floor
|
||||
local __string_format = string.format
|
||||
|
||||
return function(update_freq, main_state, config, common, width, point)
|
||||
local dial_inner_radius = 30
|
||||
|
@ -89,6 +90,27 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
}
|
||||
end
|
||||
|
||||
local read_load = function(core_topology, phy_core_id, thread_id)
|
||||
local i = core_topology[phy_core_id].cpus[thread_id].lgl_cpu_id
|
||||
return mod_state[i].percent_active * 100
|
||||
end
|
||||
|
||||
local get_load_functions = function(cores, nthreads, core_topology)
|
||||
if nthreads == 1 then
|
||||
local update = function(c)
|
||||
dial.set(cores[c].loads, read_load(core_topology, c, 1))
|
||||
end
|
||||
return update, dial.draw_static, dial.draw_dynamic
|
||||
else
|
||||
local update = function(c)
|
||||
for t = 1, nthreads do
|
||||
compound_dial.set(cores[c].loads, t, read_load(core_topology, c, t))
|
||||
end
|
||||
end
|
||||
return update, compound_dial.draw_static, compound_dial.draw_dynamic
|
||||
end
|
||||
end
|
||||
|
||||
local mk_core_group = function(group_config, y)
|
||||
local nthreads = group_config.threads
|
||||
local core_topology = topology[nthreads]
|
||||
|
@ -98,32 +120,8 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
create_core, core_cols, y, nthreads, group_config.padding
|
||||
)
|
||||
local cores = pure.map_n(_create_core, ncores)
|
||||
local group_loads = mod_state[nthreads]
|
||||
local update_loads
|
||||
local draw_static_loads
|
||||
local draw_dynamic_loads
|
||||
if nthreads == 1 then
|
||||
update_loads = function(c)
|
||||
dial.set(
|
||||
cores[c].loads,
|
||||
group_loads[c][1].percent_active * 100
|
||||
)
|
||||
end
|
||||
draw_static_loads = dial.draw_static
|
||||
draw_dynamic_loads = dial.draw_dynamic
|
||||
else
|
||||
update_loads = function(c)
|
||||
for t = 1, nthreads do
|
||||
compound_dial.set(
|
||||
cores[c].loads,
|
||||
t,
|
||||
group_loads[c][t].percent_active * 100
|
||||
)
|
||||
end
|
||||
end
|
||||
draw_static_loads = compound_dial.draw_static
|
||||
draw_dynamic_loads = compound_dial.draw_dynamic
|
||||
end
|
||||
local update_loads, draw_static_loads, draw_dynamic_loads =
|
||||
get_load_functions(cores, nthreads, core_topology)
|
||||
local update = function()
|
||||
for c = 1, ncores do
|
||||
local temp = __math_floor(
|
||||
|
@ -159,13 +157,23 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
-- HWP status
|
||||
|
||||
local mk_hwp_freq = function(y)
|
||||
local hwp_paths = cpu.get_hwp_paths()
|
||||
local hwp_paths = cpu.get_hwp_paths(topology)
|
||||
local freq_labels
|
||||
local cpu_group_map = cpu.topology_to_cpu_map(topology)
|
||||
local format_label = function(group_id)
|
||||
return __string_format('Ave Freq (%i)', group_id)
|
||||
end
|
||||
if #topology == 1 then
|
||||
freq_labels = {'Ave Freq'}
|
||||
else
|
||||
freq_labels = pure.map_n(format_label, #topology)
|
||||
end
|
||||
local cpu_status = common.make_text_rows(
|
||||
point.x,
|
||||
y,
|
||||
width,
|
||||
text_spacing,
|
||||
{'HWP Preference', 'Ave Freq'}
|
||||
pure.concat({'HWP Preference'}, freq_labels)
|
||||
)
|
||||
local update = function()
|
||||
-- For some reason this call is slow (querying anything with pstate in
|
||||
|
@ -174,13 +182,18 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
if main_state.trigger10 == 0 then
|
||||
common.text_rows_set(cpu_status, 1, cpu.read_hwp(hwp_paths))
|
||||
end
|
||||
common.text_rows_set(cpu_status, 2, cpu.read_freq())
|
||||
local ave_freqs = cpu.read_ave_freqs(topology, cpu_group_map)
|
||||
local i = 2
|
||||
for group_id, _ in pairs(topology) do
|
||||
common.text_rows_set(cpu_status, i, ave_freqs[group_id])
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
local static = pure.partial(common.text_rows_draw_static, cpu_status)
|
||||
local dynamic = pure.partial(common.text_rows_draw_dynamic, cpu_status)
|
||||
return common.mk_acc(
|
||||
width,
|
||||
text_spacing,
|
||||
text_spacing * #topology,
|
||||
update,
|
||||
static,
|
||||
dynamic
|
||||
|
@ -203,12 +216,8 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
)
|
||||
local update = function()
|
||||
local s = 0
|
||||
for g = 1, #mod_state do
|
||||
for c = 1, #mod_state[g] do
|
||||
for t = 1, #mod_state[g][c] do
|
||||
s = s + mod_state[g][c][t].percent_active
|
||||
end
|
||||
end
|
||||
for i = 1, ncpus do
|
||||
s = s + mod_state[i].percent_active
|
||||
end
|
||||
common.tagged_percent_timeseries_set(total_load, s / ncpus * 100)
|
||||
end
|
||||
|
@ -269,10 +278,10 @@ return function(update_freq, main_state, config, common, width, point)
|
|||
point = point,
|
||||
width = width,
|
||||
set_state = update_state,
|
||||
top = {
|
||||
table.unpack(pure.map(core_group_section, config.core_groups)),
|
||||
-- {mk_hwp_freq, config.show_stats, sep_spacing},
|
||||
},
|
||||
top = pure.concat(
|
||||
pure.map(core_group_section, config.core_groups),
|
||||
{{mk_hwp_freq, config.show_stats, sep_spacing}}
|
||||
),
|
||||
common.mk_section(
|
||||
sep_spacing,
|
||||
{mk_load_plot, config.show_plot, geo.table.sec_break},
|
||||
|
|
173
src/sys.lua
173
src/sys.lua
|
@ -172,7 +172,7 @@ end
|
|||
--------------------------------------------------------------------------------
|
||||
-- cpu
|
||||
|
||||
-- ASSUME nproc and lscpu will always be available
|
||||
-- ASSUME lscpu will always be available
|
||||
|
||||
M.get_core_number = function()
|
||||
return __tonumber(i_o.read_file('/proc/cpuinfo', 'cpu cores%s+:%s(%d+)'))
|
||||
|
@ -180,13 +180,10 @@ end
|
|||
|
||||
M.get_cpu_number = function(topology)
|
||||
local n = 0
|
||||
for g = 1, #topology do
|
||||
for c = 1, #topology[g] do
|
||||
n = n + #topology[g][c].cpus
|
||||
end
|
||||
for g, c in pairs(topology) do
|
||||
n = n + g * #c
|
||||
end
|
||||
return n
|
||||
-- return __tonumber(i_o.execute_cmd('nproc', nil, '*n'))
|
||||
end
|
||||
|
||||
local get_coretemp_dir = function()
|
||||
|
@ -208,25 +205,6 @@ M.get_core_threads = function()
|
|||
return pure.fmap_maybe(make_indexer, i_o.execute_cmd(cmd))
|
||||
end
|
||||
|
||||
|
||||
-- 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
|
||||
-- local get_core_id_indexer = function()
|
||||
-- local make_indexer = pure.compose(
|
||||
-- pure.array_to_map,
|
||||
-- pure.partial(pure.imap, function(i, c) return {__tonumber(c), i} end),
|
||||
-- pure.partial(gmatch_to_table1, '(%d+)')
|
||||
-- )
|
||||
-- return pure.fmap_maybe(
|
||||
-- make_indexer,
|
||||
-- i_o.execute_cmd('lscpu -p=CORE | tail -n+5 | sort -k1,1n')
|
||||
-- )
|
||||
-- end
|
||||
|
||||
-- conky_core_idx: the ID of the dial to be drawn for this core
|
||||
-- conky_thread_idx: the ID of the individual indicator within one dial
|
||||
-- corresponding to one thread in a core (starting at 1 for each core)
|
||||
|
||||
local get_coretemp_mapper = function()
|
||||
local d = get_coretemp_dir()
|
||||
i_o.assert_exe_exists('grep')
|
||||
|
@ -289,91 +267,54 @@ M.get_core_topology = function()
|
|||
return pure.fmap_maybe(f, out)
|
||||
end
|
||||
|
||||
-- for t, k in pairs(get_core_topology()) do
|
||||
-- print(t)
|
||||
-- for x, y in pairs(k) do
|
||||
-- print(x, y.phy_core_id, y.coretemp_path, #y.cpus)
|
||||
-- -- for _, z in pairs(y.cpus) do
|
||||
-- -- print(x,z.cpu,z.conky_cpu)
|
||||
-- -- end
|
||||
-- end
|
||||
-- end
|
||||
|
||||
local get_core_mappings = function()
|
||||
local core_threads = M.get_core_threads()
|
||||
local assign_cpus = function(x)
|
||||
return {
|
||||
cpu_id = __tonumber(x[1]),
|
||||
core_id = __tonumber(x[2])
|
||||
}
|
||||
M.topology_to_cpu_map = function(topology)
|
||||
local r = {}
|
||||
for group_id, group in pairs(topology) do
|
||||
for _, core in pairs(group) do
|
||||
for _, cpu in pairs(core.cpus) do
|
||||
r[cpu.lgl_cpu_id] = group_id
|
||||
end
|
||||
local map_ids = function(indexer)
|
||||
local f = function(acc, next)
|
||||
local cpu_id = __tonumber(next[1]) + 1
|
||||
local core_id = __tonumber(next[2])
|
||||
local conky_core_idx = indexer[core_id]
|
||||
acc.mappings[cpu_id] = {
|
||||
conky_core_idx = conky_core_idx,
|
||||
conky_thread_id = acc.thread_ids[conky_core_idx],
|
||||
}
|
||||
acc.thread_ids[conky_core_idx] = acc.thread_ids[conky_core_idx] + 1
|
||||
return acc
|
||||
end
|
||||
local cpu_to_core_map = pure.maybe(
|
||||
{},
|
||||
pure.partial(gmatch_to_tableN, '(%d+),(%d+)'),
|
||||
i_o.execute_cmd('lscpu -y -p=cpu,core | grep -v \'^#\' | sort -k1,1n')
|
||||
)
|
||||
local init = {mappings = {}, _conky_core_index = 0, _thread_ids = {}}
|
||||
return pure.reduce(f, init, cpu_to_core_map).mappings
|
||||
end
|
||||
-- return pure.fmap_maybe(map_ids, )
|
||||
return r
|
||||
end
|
||||
|
||||
M.get_coretemp_paths = function()
|
||||
local get_paths = function(indexer)
|
||||
local d = get_coretemp_dir()
|
||||
i_o.assert_exe_exists('grep')
|
||||
local get_labels = pure.compose(
|
||||
i_o.execute_cmd,
|
||||
pure.partial(__string_format, 'grep Core %s/temp*_label', true)
|
||||
)
|
||||
local to_tuple = function(m)
|
||||
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
|
||||
return pure.maybe({}, get_paths, get_core_id_indexer())
|
||||
end
|
||||
|
||||
local match_freq = function(c)
|
||||
local f = 0
|
||||
local n = 0
|
||||
for s in __string_gmatch(c, '(%d+%.%d+)') do
|
||||
f = f + __tonumber(s)
|
||||
n = n + 1
|
||||
end
|
||||
return __string_format('%.0f Mhz', f / n)
|
||||
end
|
||||
|
||||
M.read_freq = function()
|
||||
M.read_ave_freqs = function(topology, cpu_group_map)
|
||||
-- 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'))
|
||||
local out = i_o.execute_cmd('lscpu -p=MHZ')
|
||||
local init_freqs = function(v)
|
||||
local r = {}
|
||||
for group_id, _ in pairs(topology) do
|
||||
r[group_id] = v
|
||||
end
|
||||
return r
|
||||
end
|
||||
if out == nil then
|
||||
return init_freqs('N/A')
|
||||
else
|
||||
local ave_freqs = init_freqs(0)
|
||||
local cpu_id = 1
|
||||
for s in __string_gmatch(out, '(%d+%.%d+)') do
|
||||
local group_id = cpu_group_map[cpu_id]
|
||||
ave_freqs[group_id] = ave_freqs[group_id] + __tonumber(s)
|
||||
cpu_id = cpu_id + 1
|
||||
end
|
||||
for group_id, _ in pairs(ave_freqs) do
|
||||
ave_freqs[group_id] =
|
||||
__string_format(
|
||||
'%.0f Mhz',
|
||||
ave_freqs[group_id] / (group_id * #topology[group_id])
|
||||
)
|
||||
end
|
||||
return ave_freqs
|
||||
end
|
||||
end
|
||||
|
||||
M.get_hwp_paths = function()
|
||||
M.get_hwp_paths = function(topology)
|
||||
-- ASSUME this will never fail
|
||||
return pure.map_n(
|
||||
function(i)
|
||||
|
@ -381,7 +322,7 @@ M.get_hwp_paths = function()
|
|||
.. (i - 1)
|
||||
.. '/cpufreq/energy_performance_preference'
|
||||
end,
|
||||
M.get_cpu_number()
|
||||
M.get_cpu_number(topology)
|
||||
)
|
||||
end
|
||||
|
||||
|
@ -410,48 +351,32 @@ M.read_hwp = function(hwp_paths)
|
|||
end
|
||||
|
||||
M.init_cpu_loads = function(topo)
|
||||
-- -- local m = get_core_mappings()
|
||||
-- local topo = get_core_topology()
|
||||
local ncpus = M.get_cpu_number(topo)
|
||||
local cpu_loads = {}
|
||||
for core_group_id, core_group in pairs(topo) do
|
||||
cpu_loads[core_group_id] = {}
|
||||
for lgl_core_id, core in pairs(core_group) do
|
||||
cpu_loads[core_group_id][lgl_core_id] = {}
|
||||
for thread_id = 1, #core.cpus do
|
||||
cpu_loads[core_group_id][lgl_core_id][thread_id] = {
|
||||
for lgl_cpu_id = 1, ncpus do
|
||||
cpu_loads[lgl_cpu_id] = {
|
||||
active_prev = 0,
|
||||
total_prev = 0,
|
||||
percent_active = 0,
|
||||
-- core_id = lgl_core_id,
|
||||
-- thread_id = thread_id,
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
return cpu_loads
|
||||
end
|
||||
|
||||
M.read_cpu_loads = function(cpu_loads)
|
||||
local iter = io.lines('/proc/stat')
|
||||
iter() -- ignore first line
|
||||
for group_id = 1, #cpu_loads do
|
||||
local group = cpu_loads[group_id]
|
||||
for lgl_core_id = 1, #group do
|
||||
local core = group[lgl_core_id]
|
||||
for thread_id = 1, #core do
|
||||
for lgl_cpu_id = 1, #cpu_loads do
|
||||
local ln = iter()
|
||||
local user, system, idle =
|
||||
__string_match(ln, '%d+ (%d+) %d+ (%d+) (%d+)', 4)
|
||||
local active = user + system
|
||||
local total = active + idle
|
||||
local thread = core[thread_id]
|
||||
if total > thread.total_prev then -- guard against 1/0 errors
|
||||
thread.percent_active =
|
||||
(active - thread.active_prev) / (total - thread.total_prev)
|
||||
thread.active_prev = active
|
||||
thread.total_prev = total
|
||||
end
|
||||
end
|
||||
local cpu = cpu_loads[lgl_cpu_id]
|
||||
if total > cpu.total_prev then -- guard against 1/0 errors
|
||||
cpu.percent_active = (active - cpu.active_prev) / (total - cpu.total_prev)
|
||||
cpu.active_prev = active
|
||||
cpu.total_prev = total
|
||||
end
|
||||
end
|
||||
return cpu_loads
|
||||
|
|
Loading…
Reference in New Issue