From 0d6e63abdc56f94977a12074e1d2c429509de880 Mon Sep 17 00:00:00 2001 From: Mete Durlu Date: Wed, 3 Dec 2025 12:48:30 +0100 Subject: [PATCH] hyptop: Calculate sample time delta for physical partition Physical machine information does not include any monotonically increasing time field like other per CPU information blocks. This Prevents the percentage calculation for the physical information fields as the divisor(time_delta) is missing; field% = (value_current - value_previous) / time_delta To circumvent that, use the current partition's per CPU online time values to calculate the time_delta. Integrate time_delta as a new field(phys_delta_us) specific to the physical systems. Explicitly CPU0 online time is used, since CPU0 is always online and cannot be deconfigured on s390x. Its online-time deltas would match those of the physical CPUs. Since a new field has to be used for physical systems a new column in the table also has to be created but instead map the physical system field to the corresponding regular system fields for a nicer table view. Reviewed-by: Vasily Gorbik Signed-off-by: Mete Durlu Signed-off-by: Steffen Eiden --- hyptop/dg_debugfs_lpar.c | 39 ++++++++++++++++++++++++++++++--- hyptop/hyptop.c | 4 +++- hyptop/sd.h | 12 ++++++++++ hyptop/sd_sys_items.c | 47 ++++++++++++++++++++++++++++++++++++++++ hyptop/table.c | 2 ++ hyptop/win_sys_list.c | 9 +++++++- 6 files changed, 108 insertions(+), 5 deletions(-) diff --git a/hyptop/dg_debugfs_lpar.c b/hyptop/dg_debugfs_lpar.c index 94baf70e..6ccdf048 100644 --- a/hyptop/dg_debugfs_lpar.c +++ b/hyptop/dg_debugfs_lpar.c @@ -26,6 +26,7 @@ #define CPU_TYPE_LEN 16 #define DEBUGFS_FILE "diag_204" +static struct sd_sys *l_cur_lpar; static u64 l_update_time_us; static long l_204_buf_size; @@ -36,7 +37,8 @@ static long l_204_buf_size; struct l_x_info_blk_hdr { u8 npar; u8 flags; - u8 reserved1[6]; + u8 reserved1[4]; + u16 this_part; u64 curtod1; u64 curtod2; u8 reserved[40]; @@ -158,6 +160,21 @@ static void *l_sd_sys_fill(struct sd_sys *lpar, struct l_x_sys_hdr *sys_hdr) return cpu_info; } +/* + * Calculate the time delta between samples using current partition's + * online time. + */ +static u64 l_sd_cur_lpar_delta_time_get(void) +{ + struct sd_cpu *cpu; + + cpu = sd_cpu_get(l_cur_lpar, "0"); + if (!cpu->d_prev || !cpu->d_cur) + return 0; + return l_sub_64(cpu->d_cur->online_time_us, + cpu->d_prev->online_time_us); +} + /* * Fill one physical CPU with data */ @@ -241,9 +258,9 @@ static void l_read_debugfs(struct l_debugfs_d204_hdr **hdr, */ static void l_sd_sys_root_fill(struct sd_sys *sys) { + struct l_x_sys_hdr *sys_hdr, *this_part; struct l_x_info_blk_hdr *time_hdr; struct l_debugfs_d204_hdr *hdr; - struct l_x_sys_hdr *sys_hdr; struct sd_sys *lpar; char lpar_id[10]; int i; @@ -262,18 +279,23 @@ static void l_sd_sys_root_fill(struct sd_sys *sys) usleep(DBFS_WAIT_TIME_US); } while (1); sys_hdr = ((void *) time_hdr) + sizeof(struct l_x_info_blk_hdr); + this_part = ((void *)time_hdr) + time_hdr->this_part; for (i = 0; i < time_hdr->npar; i++) { l_sys_hdr__sys_name(sys_hdr, lpar_id); lpar = sd_sys_get(sys, lpar_id); if (!lpar) lpar = sd_sys_new(sys, lpar_id); + if (sys_hdr == this_part) + l_cur_lpar = lpar; lpar->threads_per_core = l_thread_cnt(sys_hdr); sys_hdr = l_sd_sys_fill(lpar, sys_hdr); sd_sys_commit(lpar); } - if (time_hdr->flags & LPAR_PHYS_FLG) + if (time_hdr->flags & LPAR_PHYS_FLG) { l_sd_sys_root_cpu_phys_fill(sys, (void *) sys_hdr); + sd_phys_delta_time_us_set(sys, l_sd_cur_lpar_delta_time_get()); + } ht_free(hdr); sd_sys_commit(sys); } @@ -290,6 +312,16 @@ static void l_sd_update(void) sd_sys_update_end(root, l_update_time_us); } +/* + * Supported physical information items + */ +static struct sd_sys_item *l_phys_item_vec[] = { + &sd_sys_item_core_cnt, + &sd_sys_item_phys_mgm_diff, + &sd_sys_item_mgm, + NULL, +}; + /* * Supported system items */ @@ -364,6 +396,7 @@ static struct sd_cpu_type *l_cpu_type_vec[] = { static struct sd_dg l_sd_dg = { .update_sys = l_sd_update, .cpu_type_vec = l_cpu_type_vec, + .phys_item_vec = l_phys_item_vec, .sys_item_vec = l_sys_item_vec, .sys_item_enable_vec = l_sys_item_enable_vec, .cpu_item_vec = l_cpu_item_vec, diff --git a/hyptop/hyptop.c b/hyptop/hyptop.c index dc02a7d8..0cd7679c 100644 --- a/hyptop/hyptop.c +++ b/hyptop/hyptop.c @@ -229,8 +229,10 @@ static void l_fmt_init(void) if (!g.o.format_specified) return; - if (g.o.format == FMT_CSV) + if (g.o.format == FMT_CSV) { flags |= FMT_QUOTEALL; + flags |= FMT_KEEPINVAL; + } if (g.o.format == FMT_JSON || g.o.format == FMT_JSONSEQ) flags |= FMT_HANDLEINT; util_fmt_init(stdout, g.o.format, flags, 1); diff --git a/hyptop/sd.h b/hyptop/sd.h index 75077aa4..fdfda6a6 100644 --- a/hyptop/sd.h +++ b/hyptop/sd.h @@ -78,6 +78,7 @@ struct sd_sys { struct util_list_node list; struct sd_info i; u64 update_time_us; + u64 phys_delta_us; u32 child_cnt; u32 child_cnt_active; struct util_list child_list; @@ -135,6 +136,11 @@ static inline void sd_sys_update_time_us_set(struct sd_sys *sys, u64 value) sys->update_time_us = value; } +static inline void sd_phys_delta_time_us_set(struct sd_sys *sys, u64 value) +{ + sys->phys_delta_us = value; +} + /* * CPU type */ @@ -438,12 +444,15 @@ extern struct sd_sys_item sd_sys_item_os_name; extern struct sd_sys_item sd_sys_item_samples_total; extern struct sd_sys_item sd_sys_item_samples_cpu_using; +extern struct sd_sys_item sd_sys_item_phys_mgm_diff; + /* * Data gatherer backend */ struct sd_dg { void (*update_sys)(void); struct sd_cpu_type **cpu_type_vec; + struct sd_sys_item **phys_item_vec; struct sd_sys_item **sys_item_vec; struct sd_sys_item **sys_item_enable_vec; struct sd_cpu_item **cpu_item_vec; @@ -463,6 +472,9 @@ int sd_dg_has_core_data(void); #define sd_cpu_iterate(parent, cpu) \ util_list_iterate(&parent->cpu_list, cpu) +#define sd_phys_item_iterate(ptr, i) \ + for (i = 0; (ptr = sd.dg->phys_item_vec[i]); i++) + #define sd_sys_item_iterate(ptr, i) \ for (i = 0; (ptr = sd.dg->sys_item_vec[i]); i++) diff --git a/hyptop/sd_sys_items.c b/hyptop/sd_sys_items.c index 6102d6b3..aa90f110 100644 --- a/hyptop/sd_sys_items.c +++ b/hyptop/sd_sys_items.c @@ -220,9 +220,56 @@ static u64 l_sys_smt_util(struct sd_sys_item *item, struct sd_sys *sys) return ht_calculate_smt_util(core_us, thr_us, mgm_us, sys->threads_per_core); } +/* + * value = (value_current - value_prev) / online_time_diff + */ +static double l_phys_cpu_info_diff_u64(struct sd_sys_item *item, + struct sd_cpu *cpu, + u64 time_diff_us) +{ + double factor, diff_us; + + if (!sd_cpu_type_selected(cpu->type)) + return 0; + if (sd_cpu_state(cpu) == SD_CPU_STATE_STOPPED) + return 0; + if (time_diff_us == 0) + return 0; + diff_us = l_sub_64(l_cpu_info_u64(cpu->d_cur, item->offset), + l_cpu_info_u64(cpu->d_prev, item->offset)); + factor = ((double)time_diff_us) / 1000000; + diff_us /= factor; + return diff_us; +} + +/* + * SUM over all CPUs: value = (value_current - value_prev) / online_time_diff + */ +static u64 l_sys_phys_cpu_info_diff_u64(struct sd_sys_item *item, struct sd_sys *sys) +{ + struct sd_cpu *cpu; + u64 rc = 0; + + sd_cpu_iterate(sys, cpu) { + if (!cpu->d_prev || !cpu->d_cur) + return 0; + rc += l_phys_cpu_info_diff_u64(item, cpu, sys->phys_delta_us); + } + return rc; +} + /* * System item definitions */ +struct sd_sys_item sd_sys_item_phys_mgm_diff = { + .table_col = TABLE_COL_TIME_DIFF_SUM(table_col_unit_perc, 'm', "mgm"), + .offset = SD_CPU_INFO_OFFSET(mgm_time_us), + .type = SD_TYPE_U64, + .desc = "Management time per second", + .fn_set = l_sys_cpu_info_set, + .fn_u64 = l_sys_phys_cpu_info_diff_u64, +}; + struct sd_sys_item sd_sys_item_core_cnt = { .table_col = TABLE_COL_CNT_SUM('#', "#core"), .type = SD_TYPE_U32, diff --git a/hyptop/table.c b/hyptop/table.c index 51945e0c..b1dbd05c 100644 --- a/hyptop/table.c +++ b/hyptop/table.c @@ -992,6 +992,8 @@ static void l_row_print_formatted(struct table *t, struct table_row *row) continue; if (table_col_needs_quotes(col)) flags = FMT_QUOTE; + if (strcmp(e->str, "-") == 0 || strcmp(e->str, "") == 0) + flags |= FMT_INVAL; util_fmt_pair(flags, col->head, "%s", e->str); } } diff --git a/hyptop/win_sys_list.c b/hyptop/win_sys_list.c index 508d4da3..4d851bcf 100644 --- a/hyptop/win_sys_list.c +++ b/hyptop/win_sys_list.c @@ -170,7 +170,7 @@ static void l_row_add_physical(struct table *t, struct sd_sys *sys) row = table_row_alloc(t); table_row_entry_str_add(row, &l_col_sys, sd_sys_id(sys)); - sd_sys_item_iterate(item, i) { + sd_phys_item_iterate(item, i) { if (!sd_sys_item_set(sys, item)) continue; l_sys_item_add(row, sys, item); @@ -342,6 +342,11 @@ static void l_run(struct hyptop_win *win) } } +static void win_sys_list_set_phys_table_cols(void) +{ + sd_sys_item_phys_mgm_diff.table_col = sd_sys_item_mgm_diff.table_col; +} + /* * Initialize window */ @@ -369,6 +374,8 @@ void win_sys_list_init(void) col_vec[i] = col; col_desc_vec[i] = item->desc; } + if (sd_dg_has_phys_data()) + win_sys_list_set_phys_table_cols(); /* Enable fields */ if (win_sys_list.opts.fields.specified) l_fields_enable_cmdline();