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();