mirror of
https://github.com/ibm-s390-linux/s390-tools.git
synced 2026-08-05 02:14:52 +00:00
hyptop: Add real SMT utilization field
By using core utilization, thread utilization, and management utilization, it is possible to determine how much capacity is left or how much the real CPU SMT utilization is on lpars. Extending hyptop with this new field provides useful information. For more info about real CPU SMT utilization: https://linux.mainframe.blog/smt_utilization/ Briefly: ur = real SMT util uc = core util ut = thread util um = *management util s = **speedup factor ur = ((uc * per_core_thr_count) - ut) / s + (ut - uc) + um * management utilization: logical core time spent on hypervisor instead of logical partition. ** speedup factor: metric used to calculate the SMT utilization on that logical core. This value varies depending on the workload and the machine generation due to hardware optimization level. Signed-off-by: Mete Durlu <meted@linux.ibm.com> Reviewed-by: Steffen Eiden <seiden@linux.ibm.com> Signed-off-by: Jan Höppner <hoeppner@linux.ibm.com>
This commit is contained in:
@@ -116,6 +116,7 @@ static void l_sd_cpu_fill(struct sd_cpu *cpu, struct l_x_cpu_info *cpu_info,
|
||||
int threads)
|
||||
{
|
||||
sd_cpu_cpu_time_us_set(cpu, cpu_info->lp_time);
|
||||
sd_cpu_threads_per_core_set(cpu, threads);
|
||||
if (threads > 1)
|
||||
sd_cpu_thread_time_us_set(cpu,
|
||||
cpu_info->lp_time * threads - cpu_info->mt_idle_time);
|
||||
@@ -297,6 +298,7 @@ static struct sd_sys_item *l_sys_item_vec[] = {
|
||||
&sd_sys_item_thread_cnt,
|
||||
&sd_sys_item_core_diff,
|
||||
&sd_sys_item_thread_diff,
|
||||
&sd_sys_item_smt_diff,
|
||||
&sd_sys_item_mgm_diff,
|
||||
&sd_sys_item_core,
|
||||
&sd_sys_item_thread,
|
||||
@@ -326,6 +328,7 @@ static struct sd_cpu_item *l_cpu_item_vec[] = {
|
||||
&sd_cpu_item_type,
|
||||
&sd_cpu_item_core_diff,
|
||||
&sd_cpu_item_thread_diff,
|
||||
&sd_cpu_item_smt_diff,
|
||||
&sd_cpu_item_mgm_diff,
|
||||
&sd_cpu_item_core,
|
||||
&sd_cpu_item_thread,
|
||||
|
||||
@@ -391,3 +391,24 @@ void hyptop_helper_init(void)
|
||||
if (l_iconv_ebcdic_ascii == (iconv_t) -1)
|
||||
ERR_EXIT("Could not initialize iconv\n");
|
||||
}
|
||||
|
||||
/*
|
||||
* Calculate real SMT utilization
|
||||
* @core_us: core utilization in us
|
||||
* @thr_us: thread utilization in us
|
||||
* @mgm_us: management utilization in us
|
||||
* @thread_per_core: SMT thread count per core
|
||||
*/
|
||||
s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_core)
|
||||
{
|
||||
s64 component1, component2, smt_us;
|
||||
double smt_factor = SMT_FACTOR_DEFAULT;
|
||||
|
||||
component1 = G0(thread_per_core * core_us - thr_us);
|
||||
if (thread_per_core > 1)
|
||||
component1 /= smt_factor;
|
||||
component2 = G0(thr_us - core_us);
|
||||
smt_us = component1 + component2 + mgm_us;
|
||||
|
||||
return smt_us;
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "lib/zt_common.h"
|
||||
|
||||
#define G0(x) MAX(0, (s64) (x))
|
||||
#define SMT_FACTOR_DEFAULT 1.3
|
||||
|
||||
/*
|
||||
* Helper Prototypes
|
||||
@@ -34,6 +35,7 @@ extern void ht_ebcdic_to_ascii(char *in, char *out, size_t len);
|
||||
extern char *ht_mount_point_get(const char *fs_type);
|
||||
extern u64 ht_ext_tod_2_us(void *tod_ext);
|
||||
extern void ht_print_time(void);
|
||||
extern s64 ht_calculate_smt_util(u64 core_us, u64 thr_us, u64 mgm_us, int thread_per_core);
|
||||
|
||||
/*
|
||||
* Memory alloc functions
|
||||
|
||||
@@ -119,6 +119,7 @@ The following fields are available under LPAR:
|
||||
In "sys_list" and "sys" window:
|
||||
'c' - Core dispatch time per second
|
||||
'e' - Thread time per second
|
||||
'S' - Real CPU SMT utilization
|
||||
'm' - Management time per second
|
||||
'C' - Total core dispatch time
|
||||
'E' - Total thread time
|
||||
|
||||
@@ -200,6 +200,7 @@ struct sd_cpu {
|
||||
struct sd_cpu_info *d_cur;
|
||||
struct sd_cpu_info *d_prev;
|
||||
u16 cnt;
|
||||
int threads_per_core;
|
||||
enum sd_cpu_state state;
|
||||
};
|
||||
|
||||
@@ -232,6 +233,11 @@ static inline void sd_cpu_cpu_time_us_set(struct sd_cpu *cpu, u64 value)
|
||||
cpu->d_cur->cpu_time_us = value;
|
||||
}
|
||||
|
||||
static inline void sd_cpu_threads_per_core_set(struct sd_cpu *cpu, int value)
|
||||
{
|
||||
cpu->threads_per_core = value;
|
||||
}
|
||||
|
||||
static inline void sd_cpu_thread_time_us_set(struct sd_cpu *cpu, u64 value)
|
||||
{
|
||||
cpu->d_cur->thread_time_us = value;
|
||||
@@ -335,6 +341,7 @@ extern struct sd_cpu_item sd_cpu_item_state;
|
||||
extern struct sd_cpu_item sd_cpu_item_cpu_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_core_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_thread_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_smt_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_mgm_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_wait_diff;
|
||||
extern struct sd_cpu_item sd_cpu_item_steal_diff;
|
||||
@@ -398,6 +405,7 @@ static inline char *sd_sys_item_str(struct sd_sys *sys,
|
||||
extern struct sd_sys_item sd_sys_item_cpu_cnt;
|
||||
extern struct sd_sys_item sd_sys_item_core_cnt;
|
||||
extern struct sd_sys_item sd_sys_item_thread_cnt;
|
||||
extern struct sd_sys_item sd_sys_item_smt_diff;
|
||||
extern struct sd_sys_item sd_sys_item_cpu_oper_cnt;
|
||||
extern struct sd_sys_item sd_sys_item_cpu_deconf_cnt;
|
||||
extern struct sd_sys_item sd_sys_item_cpu_stop_cnt;
|
||||
|
||||
@@ -98,6 +98,18 @@ static u64 l_cpu_item_64(struct sd_cpu_item *item, struct sd_cpu *cpu)
|
||||
return l_cpu_info_u64(cpu->d_cur, item->offset) / cpu->cnt;
|
||||
}
|
||||
|
||||
static u64 l_cpu_smt_util(struct sd_cpu_item *item, struct sd_cpu *cpu)
|
||||
{
|
||||
u64 core_us, thr_us, mgm_us;
|
||||
(void)item;
|
||||
|
||||
core_us = sd_cpu_item_u64(&sd_cpu_item_core_diff, cpu);
|
||||
thr_us = sd_cpu_item_u64(&sd_cpu_item_thread_diff, cpu);
|
||||
mgm_us = sd_cpu_item_u64(&sd_cpu_item_mgm_diff, cpu);
|
||||
|
||||
return ht_calculate_smt_util(core_us, thr_us, mgm_us, cpu->threads_per_core);
|
||||
}
|
||||
|
||||
/*
|
||||
* CPU item definitions
|
||||
*/
|
||||
@@ -139,6 +151,13 @@ struct sd_cpu_item sd_cpu_item_thread_diff = {
|
||||
.fn_u64 = l_cpu_diff_u64,
|
||||
};
|
||||
|
||||
struct sd_cpu_item sd_cpu_item_smt_diff = {
|
||||
.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'S', "smt"),
|
||||
.type = SD_TYPE_U64,
|
||||
.desc = "Real CPU SMT utilization",
|
||||
.fn_u64 = l_cpu_smt_util,
|
||||
};
|
||||
|
||||
struct sd_cpu_item sd_cpu_item_mgm_diff = {
|
||||
.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'm', "mgm"),
|
||||
.type = SD_TYPE_U64,
|
||||
|
||||
@@ -208,6 +208,18 @@ static s64 l_sys_cpu_info_diff_s64(struct sd_sys_item *item, struct sd_sys *sys)
|
||||
return rc;
|
||||
}
|
||||
|
||||
static u64 l_sys_smt_util(struct sd_sys_item *item, struct sd_sys *sys)
|
||||
{
|
||||
u64 core_us, thr_us, mgm_us;
|
||||
(void)item;
|
||||
|
||||
core_us = sd_sys_item_u64(sys, &sd_sys_item_core_diff);
|
||||
thr_us = sd_sys_item_u64(sys, &sd_sys_item_thread_diff);
|
||||
mgm_us = sd_sys_item_u64(sys, &sd_sys_item_mgm_diff);
|
||||
|
||||
return ht_calculate_smt_util(core_us, thr_us, mgm_us, sys->threads_per_core);
|
||||
}
|
||||
|
||||
/*
|
||||
* System item definitions
|
||||
*/
|
||||
@@ -277,6 +289,13 @@ struct sd_sys_item sd_sys_item_thread_diff = {
|
||||
.fn_u64 = l_sys_cpu_info_diff_u64,
|
||||
};
|
||||
|
||||
struct sd_sys_item sd_sys_item_smt_diff = {
|
||||
.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'S', "smt"),
|
||||
.type = SD_TYPE_U64,
|
||||
.desc = "Real CPU SMT utilization",
|
||||
.fn_u64 = l_sys_smt_util,
|
||||
};
|
||||
|
||||
struct sd_sys_item sd_sys_item_mgm_diff = {
|
||||
.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'm', "mgm"),
|
||||
.offset = SD_CPU_INFO_OFFSET(mgm_time_us),
|
||||
|
||||
Reference in New Issue
Block a user