Subject: [PATCH] [FEAT KRN1216] hyptop: Support for SMT (SMT base support)
From: Michael Holzheu <holzheu@linux.vnet.ibm.com>

Summary:     hyptop: Support for SMT (SMT base support)
Description: Add the following new fields to hyptop:
             Window "sys":
               * Thread time per second (per core)
               * Total thread time (per core)
             Window "sys_list":
               * Thread time per second (per LPAR)
               * Total thread time (per LPAR)
               * Number of threads (per LPAR)
             Also change the following fields for LPAR:
               * #cpu: Number of CPUs     -> #core: Number of cores
               * cpu: CPU time per second -> core: Core dispatch time per sec.
               * cpu+: Total CPU time     -> core+: Total core dispatch
Upstream-ID: -
Problem-ID:  KRN1216

Signed-off-by: Michael Holzheu <holzheu@linux.vnet.ibm.com>
---
 hyptop/dg_debugfs_lpar.c |   50 ++++++++++++++++++++++++++++++-----------
 hyptop/dg_debugfs_vm.c   |    2 -
 hyptop/hyptop.8          |   11 +++++----
 hyptop/sd.h              |   20 +++++++++++++++-
 hyptop/sd_core.c         |   14 ++++++++++-
 hyptop/sd_cpu_items.c    |   32 ++++++++++++++++++++++++++
 hyptop/sd_sys_items.c    |   56 +++++++++++++++++++++++++++++++++++++++++++++++
 hyptop/win_sys.c         |   12 ++++++++--
 8 files changed, 173 insertions(+), 24 deletions(-)

--- a/hyptop/dg_debugfs_lpar.c
+++ b/hyptop/dg_debugfs_lpar.c
@@ -16,6 +16,7 @@
 #include "helper.h"
 #include "dg_debugfs.h"
 
+#define MTID_MASK	0x1f
 #define LPAR_NAME_LEN	8
 #define TMP_SIZE	64
 #define LPAR_PHYS_FLG	0x80
@@ -44,7 +45,9 @@ struct l_x_sys_hdr {
 	u8	rcpus;
 	u8	reserved2[5];
 	char	sys_name[LPAR_NAME_LEN];
-	u8	reserved3[80];
+	u8	reserved3[33];
+	u8	mtid;
+	u8	reserved4[46];
 } __attribute__ ((packed));
 
 static inline void l_sys_hdr__sys_name(struct l_x_sys_hdr *hdr, char *name)
@@ -65,9 +68,16 @@ struct l_x_cpu_info {
 	u8	reserved3[6];
 	u8	reserved4[2];
 	u64	online_time;
-	u8	reserved5[56];
+	u8	reserved5[24];
+	u64	mt_idle_time;
+	u8	reserved6[24];
 } __attribute__ ((packed));
 
+static int l_thread_cnt(struct l_x_sys_hdr *hdr)
+{
+	return (hdr->mtid & MTID_MASK) + 1;
+}
+
 static void l_idx2name(int index, char *name)
 {
 	switch (index) {
@@ -100,9 +110,15 @@ struct l_x_phys_cpu {
 /*
  * Fill CPU with data
  */
-static void l_sd_cpu_fill(struct sd_cpu *cpu, struct l_x_cpu_info *cpu_info)
+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);
+	if (threads > 1)
+		sd_cpu_thread_time_us_set(cpu,
+			cpu_info->lp_time * threads - cpu_info->mt_idle_time);
+	else
+		sd_cpu_thread_time_us_set(cpu, cpu_info->lp_time);
 	sd_cpu_mgm_time_us_set(cpu, G0(cpu_info->acc_time - cpu_info->lp_time));
 	sd_cpu_online_time_us_set(cpu, cpu_info->online_time);
 	sd_cpu_state_set(cpu, SD_CPU_STATE_UNKNOWN);
@@ -131,7 +147,7 @@ static void *l_sd_sys_fill(struct sd_sys
 			cpu = sd_cpu_new(lpar, cpu_id, cpu_type, 1);
 		}
 
-		l_sd_cpu_fill(cpu, cpu_info);
+		l_sd_cpu_fill(cpu, cpu_info, lpar->threads_per_core);
 
 		sd_cpu_commit(cpu);
 		cpu_info++;
@@ -249,6 +265,7 @@ static void l_sd_sys_root_fill(struct sd
 		lpar = sd_sys_get(sys, lpar_id);
 		if (!lpar)
 			lpar = sd_sys_new(sys, lpar_id);
+		lpar->threads_per_core = l_thread_cnt(sys_hdr);
 		sys_hdr = l_sd_sys_fill(lpar, sys_hdr);
 		sd_sys_commit(lpar);
 	}
@@ -275,10 +292,13 @@ static void l_sd_update(void)
  * Supported system items
  */
 static struct sd_sys_item *l_sys_item_vec[] = {
-	&sd_sys_item_cpu_cnt,
-	&sd_sys_item_cpu_diff,
+	&sd_sys_item_core_cnt,
+	&sd_sys_item_thread_cnt,
+	&sd_sys_item_core_diff,
+	&sd_sys_item_thread_diff,
 	&sd_sys_item_mgm_diff,
-	&sd_sys_item_cpu,
+	&sd_sys_item_core,
+	&sd_sys_item_thread,
 	&sd_sys_item_mgm,
 	&sd_sys_item_online,
 	NULL,
@@ -288,10 +308,10 @@ static struct sd_sys_item *l_sys_item_ve
  * Default system items
  */
 static struct sd_sys_item *l_sys_item_enable_vec[] = {
-	&sd_sys_item_cpu_cnt,
-	&sd_sys_item_cpu_diff,
+	&sd_sys_item_core_cnt,
+	&sd_sys_item_core_diff,
 	&sd_sys_item_mgm_diff,
-	&sd_sys_item_cpu,
+	&sd_sys_item_core,
 	&sd_sys_item_mgm,
 	&sd_sys_item_online,
 	NULL,
@@ -302,9 +322,11 @@ static struct sd_sys_item *l_sys_item_en
  */
 static struct sd_cpu_item *l_cpu_item_vec[] = {
 	&sd_cpu_item_type,
-	&sd_cpu_item_cpu_diff,
+	&sd_cpu_item_core_diff,
+	&sd_cpu_item_thread_diff,
 	&sd_cpu_item_mgm_diff,
-	&sd_cpu_item_cpu,
+	&sd_cpu_item_core,
+	&sd_cpu_item_thread,
 	&sd_cpu_item_mgm,
 	&sd_cpu_item_online,
 	NULL,
@@ -315,7 +337,7 @@ static struct sd_cpu_item *l_cpu_item_ve
  */
 static struct sd_cpu_item *l_cpu_item_enable_vec[] = {
 	&sd_cpu_item_type,
-	&sd_cpu_item_cpu_diff,
+	&sd_cpu_item_core_diff,
 	&sd_cpu_item_mgm_diff,
 	NULL,
 };
@@ -355,6 +377,6 @@ int dg_debugfs_lpar_init(void)
 		return fh;
 	else
 		close(fh);
-	sd_dg_register(&l_sd_dg);
+	sd_dg_register(&l_sd_dg, 1);
 	return 0;
 }
--- a/hyptop/dg_debugfs_vm.c
+++ b/hyptop/dg_debugfs_vm.c
@@ -356,6 +356,6 @@ int dg_debugfs_vm_init(void)
 		close(fh);
 	l_2fc_buf_size = sizeof(struct l_debugfs_d2fc_hdr);
 	l_guest_name_init();
-	sd_dg_register(&dg_debugfs_vm_dg);
+	sd_dg_register(&dg_debugfs_vm_dg, 0);
 	return 0;
 }
--- a/hyptop/hyptop.8
+++ b/hyptop/hyptop.8
@@ -108,18 +108,21 @@ or through the "--fields" command line o
 The following fields are available under LPAR:
 
   In "sys_list" and "sys" window:
-  'c' - CPU time per second
+  'c' - Core dispatch time per second
+  'e' - Thread time per second
   'm' - Management time per second
-  'C' - Total CPU time
+  'C' - Total core dispatch time
+  'E' - Total thread time
   'M' - Total management time
   'o' - Online time
 
   In "sys_list" window:
-  '#' - Number of CPUs
+  '#' - Number of cores (sum of initial and reserved)
+  'T' - Number of threads (sum of initial and reserved)
 
   In "sys" window:
   'p' - CPU type
-  'v' - Visualization of CPU time per second
+  'v' - Visualization of core dispatch time per second
 
 The following fields are available under z/VM:
 
--- a/hyptop/sd.h
+++ b/hyptop/sd.h
@@ -21,6 +21,7 @@
  */
 struct sd_cpu_info {
 	u64	cpu_time_us;
+	u64	thread_time_us;
 	u64	mgm_time_us_set;
 	u64	mgm_time_us;
 	u64	wait_time_us;
@@ -78,6 +79,7 @@ struct sd_sys {
 	u32			cpu_cnt;
 	u32			cpu_cnt_active;
 	struct util_list	cpu_list;
+	u32			threads_per_core;
 	char			id[SD_SYS_ID_SIZE];
 	struct sd_sys_name	name;
 	struct sd_mem		mem;
@@ -232,6 +234,11 @@ static inline void sd_cpu_cpu_time_us_se
 	cpu->d_cur->cpu_time_us = value;
 }
 
+static inline void sd_cpu_thread_time_us_set(struct sd_cpu *cpu, u64 value)
+{
+	cpu->d_cur->thread_time_us = value;
+}
+
 static inline void sd_cpu_mgm_time_us_set(struct sd_cpu *cpu, u64 value)
 {
 	cpu->d_cur->mgm_time_us_set = 1;
@@ -328,10 +335,14 @@ static inline char *sd_cpu_item_str(stru
 extern struct sd_cpu_item sd_cpu_item_type;
 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_mgm_diff;
 extern struct sd_cpu_item sd_cpu_item_wait_diff;
 extern struct sd_cpu_item sd_cpu_item_steal_diff;
 extern struct sd_cpu_item sd_cpu_item_cpu;
+extern struct sd_cpu_item sd_cpu_item_core;
+extern struct sd_cpu_item sd_cpu_item_thread;
 extern struct sd_cpu_item sd_cpu_item_mgm;
 extern struct sd_cpu_item sd_cpu_item_wait;
 extern struct sd_cpu_item sd_cpu_item_steal;
@@ -387,15 +398,21 @@ static inline char *sd_sys_item_str(stru
  * Predefined System items
  */
 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_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;
 extern struct sd_sys_item sd_sys_item_cpu_diff;
+extern struct sd_sys_item sd_sys_item_core_diff;
+extern struct sd_sys_item sd_sys_item_thread_diff;
 extern struct sd_sys_item sd_sys_item_mgm_diff;
 extern struct sd_sys_item sd_sys_item_wait_diff;
 extern struct sd_sys_item sd_sys_item_steal_diff;
 
 extern struct sd_sys_item sd_sys_item_cpu;
+extern struct sd_sys_item sd_sys_item_core;
+extern struct sd_sys_item sd_sys_item_thread;
 extern struct sd_sys_item sd_sys_item_mgm;
 extern struct sd_sys_item sd_sys_item_wait;
 extern struct sd_sys_item sd_sys_item_steal;
@@ -426,7 +443,8 @@ struct sd_dg {
 	struct sd_cpu_item	**cpu_item_enable_vec;
 };
 
-void sd_dg_register(struct sd_dg *);
+void sd_dg_register(struct sd_dg *, int);
+int sd_dg_has_core_data(void);
 
 /*
  * Iterators
--- a/hyptop/sd_core.c
+++ b/hyptop/sd_core.c
@@ -23,6 +23,7 @@ static u32		l_cpu_type_selected_mask;
 static int		l_cpu_type_cnt;
 static int		l_sys_item_cnt;
 static int		l_cpu_item_cnt;
+static int		l_has_core_data;
 static struct sd_sys	*l_root_sys;
 
 /*
@@ -145,15 +146,15 @@ void sd_update(void)
 /*
  * Register a data gatherer
  */
-void sd_dg_register(struct sd_dg *dg)
+void sd_dg_register(struct sd_dg *dg, int has_core_data)
 {
 	struct timespec ts = {0, SD_DG_INIT_INTERVAL_MS * 1000000};
 	struct sd_sys_item *sys_item;
 	struct sd_cpu_item *cpu_item;
 	unsigned int i;
 
+	l_has_core_data = has_core_data;
 	sd.dg = dg;
-
 	for (i = 0; dg->cpu_type_vec[i]; i++)
 		dg->cpu_type_vec[i]->idx = (1UL << i);
 	l_cpu_type_cnt = i;
@@ -170,6 +171,14 @@ void sd_dg_register(struct sd_dg *dg)
 }
 
 /*
+ * Does backend has core data?
+ */
+int sd_dg_has_core_data(void)
+{
+	return l_has_core_data;
+}
+
+/*
  * Get CPU from sys by ID
  */
 struct sd_cpu *sd_cpu_get(struct sd_sys *sys, const char* id)
@@ -249,6 +258,7 @@ struct sd_sys *sd_sys_new(struct sd_sys
 		parent->child_cnt++;
 		util_list_add_tail(&parent->child_list, sys_new);
 	}
+	sys_new->threads_per_core = 1;
 	return sys_new;
 }
 
--- a/hyptop/sd_cpu_items.c
+++ b/hyptop/sd_cpu_items.c
@@ -113,6 +113,14 @@ struct sd_cpu_item sd_cpu_item_state = {
 	.fn_str		= l_cpu_state,
 };
 
+struct sd_cpu_item sd_cpu_item_core_diff = {
+	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'c', "core"),
+	.type	= SD_TYPE_U64,
+	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
+	.desc	= "Core dispatch time per second",
+	.fn_u64	= l_cpu_diff_u64,
+};
+
 struct sd_cpu_item sd_cpu_item_cpu_diff = {
 	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'c', "cpu"),
 	.type	= SD_TYPE_U64,
@@ -121,6 +129,14 @@ struct sd_cpu_item sd_cpu_item_cpu_diff
 	.fn_u64	= l_cpu_diff_u64,
 };
 
+struct sd_cpu_item sd_cpu_item_thread_diff = {
+	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'e', "the"),
+	.type	= SD_TYPE_U64,
+	.offset = SD_CPU_INFO_OFFSET(thread_time_us),
+	.desc	= "Thread time per second",
+	.fn_u64	= l_cpu_diff_u64,
+};
+
 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,
@@ -147,6 +163,14 @@ struct sd_cpu_item sd_cpu_item_steal_dif
 	.fn_s64	= l_cpu_diff_s64,
 };
 
+struct sd_cpu_item sd_cpu_item_core = {
+	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'C', "core+"),
+	.type	= SD_TYPE_U64,
+	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
+	.desc	= "Total core dispatch time",
+	.fn_u64	= l_cpu_item_64,
+};
+
 struct sd_cpu_item sd_cpu_item_cpu = {
 	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'C', "cpu+"),
 	.type	= SD_TYPE_U64,
@@ -155,6 +179,14 @@ struct sd_cpu_item sd_cpu_item_cpu = {
 	.fn_u64	= l_cpu_item_64,
 };
 
+struct sd_cpu_item sd_cpu_item_thread = {
+	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'E', "the+"),
+	.type	= SD_TYPE_U64,
+	.offset = SD_CPU_INFO_OFFSET(thread_time_us),
+	.desc	= "Total thread time",
+	.fn_u64	= l_cpu_item_64,
+};
+
 struct sd_cpu_item sd_cpu_item_mgm = {
 	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'M', "mgm+"),
 	.type	= SD_TYPE_U64,
--- a/hyptop/sd_sys_items.c
+++ b/hyptop/sd_sys_items.c
@@ -37,6 +37,16 @@ static u64 l_sys_cpu_cnt(struct sd_sys_i
 }
 
 /*
+ * Count all threads of system
+ */
+static u64 l_sys_thread_cnt(struct sd_sys_item *item, struct sd_sys *sys)
+{
+	(void) item;
+	return l_sys_cpu_cnt_gen(sys, SD_CPU_STATE_UNKNOWN, 1) *
+			sys->threads_per_core;
+}
+
+/*
  * Count CPUs of system with state stopped
  */
 static u64 l_sys_cpu_st_cnt(struct sd_sys_item *item, struct sd_sys *sys)
@@ -199,6 +209,13 @@ static s64 l_sys_cpu_info_diff_s64(struc
 /*
  * System item definitions
  */
+struct sd_sys_item sd_sys_item_core_cnt = {
+	.table_col = TABLE_COL_CNT_SUM('#', "#core"),
+	.type	= SD_TYPE_U32,
+	.desc	= "Number of cores",
+	.fn_u64	= l_sys_cpu_cnt,
+};
+
 struct sd_sys_item sd_sys_item_cpu_cnt = {
 	.table_col = TABLE_COL_CNT_SUM('#', "#cpu"),
 	.type	= SD_TYPE_U32,
@@ -206,6 +223,13 @@ struct sd_sys_item sd_sys_item_cpu_cnt =
 	.fn_u64	= l_sys_cpu_cnt,
 };
 
+struct sd_sys_item sd_sys_item_thread_cnt = {
+	.table_col = TABLE_COL_CNT_SUM('T', "#the"),
+	.type	= SD_TYPE_U32,
+	.desc	= "Number of threads",
+	.fn_u64	= l_sys_thread_cnt,
+};
+
 struct sd_sys_item sd_sys_item_cpu_oper_cnt = {
 	.table_col = TABLE_COL_CNT_SUM('O', "#cpuop"),
 	.type	= SD_TYPE_U32,
@@ -227,6 +251,14 @@ struct sd_sys_item sd_sys_item_cpu_decon
 	.fn_u64	= l_sys_cpu_dc_cnt,
 };
 
+struct sd_sys_item sd_sys_item_core_diff = {
+	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'c', "core"),
+	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
+	.type	= SD_TYPE_U64,
+	.desc	= "Core dispatch time per second",
+	.fn_u64	= l_sys_cpu_info_diff_u64,
+};
+
 struct sd_sys_item sd_sys_item_cpu_diff = {
 	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'c', "cpu"),
 	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
@@ -235,6 +267,14 @@ struct sd_sys_item sd_sys_item_cpu_diff
 	.fn_u64	= l_sys_cpu_info_diff_u64,
 };
 
+struct sd_sys_item sd_sys_item_thread_diff = {
+	.table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'e', "the"),
+	.offset = SD_CPU_INFO_OFFSET(thread_time_us),
+	.type	= SD_TYPE_U64,
+	.desc	= "Thread time per second",
+	.fn_u64	= l_sys_cpu_info_diff_u64,
+};
+
 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),
@@ -261,6 +301,14 @@ struct sd_sys_item sd_sys_item_steal_dif
 	.fn_s64	= l_sys_cpu_info_diff_s64,
 };
 
+struct sd_sys_item sd_sys_item_core = {
+	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'C', "core+"),
+	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
+	.type	= SD_TYPE_U64,
+	.desc	= "Total core dispatch time",
+	.fn_u64	= l_sys_cpu_info_sum_u64,
+};
+
 struct sd_sys_item sd_sys_item_cpu = {
 	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'C', "cpu+"),
 	.offset = SD_CPU_INFO_OFFSET(cpu_time_us),
@@ -269,6 +317,14 @@ struct sd_sys_item sd_sys_item_cpu = {
 	.fn_u64	= l_sys_cpu_info_sum_u64,
 };
 
+struct sd_sys_item sd_sys_item_thread = {
+	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'E', "the+"),
+	.offset = SD_CPU_INFO_OFFSET(thread_time_us),
+	.type	= SD_TYPE_U64,
+	.desc	= "Total thread time",
+	.fn_u64	= l_sys_cpu_info_sum_u64,
+};
+
 struct sd_sys_item sd_sys_item_wait = {
 	.table_col = TABLE_COL_TIME_SUM(table_col_unit_hm, 'W', "wait+"),
 	.offset = SD_CPU_INFO_OFFSET(wait_time_us),
--- a/hyptop/win_sys.c
+++ b/hyptop/win_sys.c
@@ -334,9 +334,16 @@ void win_sys_init(void)
 	struct table_col **col_vec;
 	struct sd_cpu_item *item;
 	struct table_col *col;
-	char **col_desc_vec;
+	char **col_desc_vec, *vis_str;
 	unsigned int i, item_cnt;
 
+	if (sd_dg_has_core_data()) {
+		strcpy(l_cpu_col.head, "coreid");
+		vis_str = "Visualization of core dispatch time per second";
+	} else {
+		vis_str = "Visualization of CPU time per second";
+	}
+
 	/* Alloc table and add columns */
 	l_t = table_new(1, 1, 1, 1);
 	table_col_add(l_t, &l_cpu_col);
@@ -354,7 +361,7 @@ void win_sys_init(void)
 		col_desc_vec[i] = item->desc;
 	}
 	col_vec[i] = &l_vis_col;
-	col_desc_vec[i] = "Visualization of CPU time per second";
+	col_desc_vec[i] = vis_str;
 	table_col_add(l_t, &l_vis_col);
 
 	/* Enable fields */
@@ -374,6 +381,7 @@ void win_sys_init(void)
 	/* Initialize help and fields window */
 	l_win_fields = win_fields_new(l_t, col_vec, col_desc_vec);
 	l_win_help = win_help_new(&win_sys);
+
 	l_initialized = 1;
 }
 
