From 66deecdf1b6fefb7918389f361dbda376cb6efef Mon Sep 17 00:00:00 2001 From: hy <941973499@qq.com> Date: Mon, 1 Sep 2025 14:29:29 +0800 Subject: [PATCH] support displaying bandwidth information --- ...ort-displaying-bandwidth-information.patch | 681 ++++++++++++++++++ vmtop.spec | 6 +- 2 files changed, 686 insertions(+), 1 deletion(-) create mode 100644 support-displaying-bandwidth-information.patch diff --git a/support-displaying-bandwidth-information.patch b/support-displaying-bandwidth-information.patch new file mode 100644 index 0000000..e19fa90 --- /dev/null +++ b/support-displaying-bandwidth-information.patch @@ -0,0 +1,681 @@ +From 1f72eca9331b308b0bafbd9e095381c684f9df5a Mon Sep 17 00:00:00 2001 +From: hy <941973499@qq.com> +Date: Mon, 25 Aug 2025 21:22:55 +0800 +Subject: [PATCH] support displaying bandwidth information + +--- + src/Makefile.am | 4 +- + src/domain.c | 67 ++++++++++++++++ + src/domain.h | 3 + + src/field.c | 26 ++++++- + src/field.h | 18 +++++ + src/resctrl.c | 201 ++++++++++++++++++++++++++++++++++++++++++++++++ + src/resctrl.h | 47 +++++++++++ + src/type.h | 5 ++ + src/utils.c | 1 + + src/utils.h | 2 + + src/vmtop.c | 57 +++++++++++++- + 11 files changed, 426 insertions(+), 5 deletions(-) + create mode 100644 src/resctrl.c + create mode 100644 src/resctrl.h + +diff --git a/src/Makefile.am b/src/Makefile.am +index 24a8016..fe9bfba 100644 +--- a/src/Makefile.am ++++ b/src/Makefile.am +@@ -8,4 +8,6 @@ libdomain_a_SOURCES= \ + vcpu_stat.c \ + vcpu_stat.h \ + utils.c \ +- utils.h ++ utils.h \ ++ resctrl.c \ ++ resctrl.h +diff --git a/src/domain.c b/src/domain.c +index 977cabe..859c72d 100644 +--- a/src/domain.c ++++ b/src/domain.c +@@ -19,6 +19,7 @@ + #include "utils.h" + #include "proc.h" + #include "vcpu_stat.h" ++#include "resctrl.h" + + #define VAR_RUN_QEMU_PATH "/var/run/libvirt/qemu" + #define PID_STRING_MAX 12 +@@ -33,7 +34,12 @@ void init_domains(struct domain_list *list) + { + list->domains = NULL; + list->num = 0; ++ ++ for (int i = 0; i < MAX_NODE_NUM; i++) { ++ list->bandwidth[i] = 0; ++ } + } ++ + void clear_domains(struct domain_list *list) + { + for (int i = 0; i < list->num; i++) { +@@ -306,6 +312,67 @@ int refresh_domains(struct domain_list *now, struct domain_list *pre) + return num; + } + ++static void calculate_all_bandwidth(struct domain_list *now, ++ int *sample_times_vms, int sample_times_host) ++{ ++ unsigned int node_vms; ++ struct domain *dom; ++ int i, node; ++ ++ for (node = 0; node < now->node_num; node++) { ++ if (sample_times_host > 0) { ++ now->bandwidth[node] /= sample_times_host; ++ } ++ node_vms = 0; ++ ++ for (i = 0; i < now->num; i++) { ++ if (sample_times_vms[i] > 0) { ++ dom = &now->domains[i]; ++ dom->ctl_bandwidth[node] /= sample_times_vms[i]; ++ dom->bandwidth_updated_succ = 1; ++ ++ now->bandwidth[node] += dom->ctl_bandwidth[node]; ++ node_vms += dom->ctl_bandwidth[node]; ++ } ++ } ++ ++ /* fix if host bandwidth less tahn all VMs */ ++ if (now->bandwidth[node] < node_vms) { ++ now->bandwidth[node] = node_vms; ++ } ++ } ++} ++ ++void refresh_domains_bandwidth(struct domain_list *now, struct domain_list *pre) ++{ ++ int sample_times_vms[MAX_VM_TASKS_NUM] = {0}; ++ int r, sample_times_host = 0; ++ ++ if (get_numa_num(&now->node_num) < 0) { ++ return; ++ } ++ ++ for(r = 0; r < SAMPLE_TIMES_OUTER; r++) { ++ /* sample the ctrl_group data of VMs */ ++ for (int i = 0; i < now->num; i++) { ++ if (get_vm_ctl_bandwidth(&now->domains[i], now->node_num) < 0) { ++ continue; ++ } ++ sample_times_vms[i]++; ++ } ++ /* sample the mon_group data of root */ ++ if (get_root_mon_bandwidth(now->bandwidth, now->node_num) < 0) { ++ (void)usleep(SAMPLE_INTERVAL_US_OUTER); ++ continue; ++ } ++ sample_times_host++; ++ (void)usleep(SAMPLE_INTERVAL_US_OUTER); ++ } ++ ++ /* calculate the average value */ ++ calculate_all_bandwidth(now, sample_times_vms, sample_times_host); ++} ++ + int get_task_num(struct domain_list *list) + { + int sum = 0; +diff --git a/src/domain.h b/src/domain.h +index 1bb6116..cc3c899 100644 +--- a/src/domain.h ++++ b/src/domain.h +@@ -14,13 +14,16 @@ + #define SRC_DOMAIN_H + + #include ++#include + #include "type.h" + + int refresh_domains(struct domain_list *now, struct domain_list *pre); ++void refresh_domains_bandwidth(struct domain_list *now, struct domain_list *pre); + void init_domains(struct domain_list *list); + void clear_domains(struct domain_list *list); + struct domain *add_domains(struct domain_list *list); + int get_task_num(struct domain_list *list); + extern int monitor_id; + extern struct domain_list vcpu_list; ++extern bool resctrl_enable; + #endif +diff --git a/src/field.c b/src/field.c +index 418d642..41a36a0 100644 +--- a/src/field.c ++++ b/src/field.c +@@ -19,6 +19,11 @@ + const char *summary_text = "" + "vmtop - %s - %s\n" + "Domains: %d running\n"; ++const char *summary_total_bandwidth = "" ++ "MiB MBM: %ld hosttotal\n"; ++const char *summary_numa_bandwidth = "" ++ "Node%d: %ld mbmtotal\n"; ++ + const char *filter_help = "" + "field filter - select which field to be showed\n" + "Use up/down to navigate, use space to set whether chosen filed to be showed\n" +@@ -30,7 +35,8 @@ const char *help_text = "" + "-h :print this help message and exit\n" + "-H :displays VM thread information\n" + "-n num :set the number of refresh times before automatic quit\n" +- "-v :show VMTOP version and exit\n"; ++ "-v :show VMTOP version and exit\n" ++ "-G :display bandwidth information if resctrl mounted\n"; + const char *version_text = "" + "vmtop-%s\n"; + +@@ -94,7 +100,23 @@ FID fields[] = { + {"%ST", FIELDS_DISPLAY, 8, GDF(steal) }, + {"%GUE", FIELDS_DISPLAY, 8, GDF(gtime) }, + {"%HYP", FIELDS_DISPLAY, 8, NULL }, +- {"WAITmax", FIELDS_HIDDEN, 9, GF(st_max) } ++ {"WAITmax", FIELDS_HIDDEN, 9, GF(st_max) }, ++ {"Node0", FIELDS_HIDDEN, 10, NULL }, ++ {"Node1", FIELDS_HIDDEN, 10, NULL }, ++ {"Node2", FIELDS_HIDDEN, 10, NULL }, ++ {"Node3", FIELDS_HIDDEN, 10, NULL }, ++ {"Node4", FIELDS_HIDDEN, 10, NULL }, ++ {"Node5", FIELDS_HIDDEN, 10, NULL }, ++ {"Node6", FIELDS_HIDDEN, 10, NULL }, ++ {"Node7", FIELDS_HIDDEN, 10, NULL }, ++ {"Node8", FIELDS_HIDDEN, 10, NULL }, ++ {"Node9", FIELDS_HIDDEN, 10, NULL }, ++ {"Node10", FIELDS_HIDDEN, 10, NULL }, ++ {"Node11", FIELDS_HIDDEN, 10, NULL }, ++ {"Node12", FIELDS_HIDDEN, 10, NULL }, ++ {"Node13", FIELDS_HIDDEN, 10, NULL }, ++ {"Node14", FIELDS_HIDDEN, 10, NULL }, ++ {"Node15", FIELDS_HIDDEN, 10, NULL } + #undef GDF + #undef GF + }; +diff --git a/src/field.h b/src/field.h +index 8ce047a..b0a7157 100644 +--- a/src/field.h ++++ b/src/field.h +@@ -74,6 +74,22 @@ enum fields_type { + FD_GUE, + FD_HYP, + FD_WAITMAX, ++ FD_NODE0, ++ FD_NODE1, ++ FD_NODE2, ++ FD_NODE3, ++ FD_NODE4, ++ FD_NODE5, ++ FD_NODE6, ++ FD_NODE7, ++ FD_NODE8, ++ FD_NODE9, ++ FD_NODE10, ++ FD_NODE11, ++ FD_NODE12, ++ FD_NODE13, ++ FD_NODE14, ++ FD_NODE15, + FD_END + }; + +@@ -89,6 +105,8 @@ extern const char *summary_text; + extern const char *filter_help; + extern const char *help_text; + extern const char *version_text; ++extern const char *summary_total_bandwidth; ++extern const char *summary_numa_bandwidth; + + int get_show_field_num(void); + #endif +diff --git a/src/resctrl.c b/src/resctrl.c +new file mode 100644 +index 0000000..401320e +--- /dev/null ++++ b/src/resctrl.c +@@ -0,0 +1,201 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. ++ * vmtop licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Description: get domain's data ++ ********************************************************************************/ ++ ++#include ++#include ++#include ++#include ++#include ++#include ++#include ++ ++#include "utils.h" ++#include "resctrl.h" ++ ++bool enable_resctrl(void) ++{ ++ int ret = -1; ++ ret = access(RESCTRL_MON_GROUPS_DIR, F_OK); ++ if (ret != 0) { ++ return false; ++ } ++ return true; ++} ++ ++int get_numa_num(int *node_num) ++{ ++ DIR *dirptr = NULL; ++ struct dirent *dirt = NULL; ++ int cur_node = -1; ++ int max_node = -1; ++ char path[VMTOP_GROUP_NAME_MAX] = {0}; ++ int ret = -1; ++ ++ ret = snprintf(path, VMTOP_GROUP_NAME_MAX, "%s/%s", ++ RESCTRL_FILESYSTEM_DIR, MON_DATA_DIR); ++ if (ret <= 0) { ++ return ret; ++ } ++ ++ if ((dirptr = opendir(path)) == NULL) { ++ return -1; ++ } ++ ++ while ((dirt = readdir(dirptr)) != NULL) { ++ if (strncmp(dirt->d_name, MON_DATA_PREFIX, strlen(MON_DATA_PREFIX)) == 0) { ++ cur_node = atoi(dirt->d_name + strlen(MON_DATA_PREFIX)); ++ if (cur_node < 0 || cur_node >= MAX_NODE_NUM) { ++ continue; ++ } ++ max_node = cur_node > max_node ? cur_node : max_node; ++ } ++ } ++ closedir(dirptr); ++ *node_num = max_node + 1; ++ return max_node; ++} ++ ++static long get_mon_MB_once(FILE *fp) { ++ char bandwidth_str[MAX_BANDWIDTH_LENGTH] = {0}; ++ ++ (void)fflush(fp); ++ (void)fseek(fp, SAMPLE_START, SEEK_SET); ++ if (fgets(bandwidth_str, MAX_BANDWIDTH_LENGTH, fp) != NULL) { ++ return atol(bandwidth_str); ++ } ++ return -1; ++} ++ ++static int get_mon_MB(long int *bandwidth, char *path, int node_num) { ++ FILE *fps[MAX_NODE_NUM] = {0}; ++ int sample_times[MAX_NODE_NUM] = {0}; ++ long bandwidth_sum[MAX_NODE_NUM] = {0}; ++ char mon_data_path[VMTOP_GROUP_NAME_MAX] = {0}; ++ long bandwidth_tmp; ++ int i, node; ++ int ret = -1; ++ ++ for (node = 0; node < node_num; node++) { ++ if (snprintf(mon_data_path, VMTOP_GROUP_NAME_MAX, ++ "%s/%s%02d/%s", path, MON_DATA_PREFIX, node, MON_DATA_FILE) < 0) { ++ goto out; ++ } ++ fps[node] = fopen(mon_data_path, "r"); ++ if (fps[node] == NULL) { ++ goto out; ++ } ++ } ++ for (i = 0; i < SAMPLE_TIMES_INNER; i++) { ++ for (node = 0; node < node_num; node++) { ++ bandwidth_tmp = get_mon_MB_once(fps[node]); ++ if (bandwidth_tmp != -1 && i > 0) { ++ bandwidth_sum[node] += bandwidth_tmp; ++ sample_times[node]++; ++ } ++ } ++ (void)usleep(SAMPLE_INTERVAL_US_INNER); ++ } ++ for (i = 0; i < node_num; i++) { ++ if (!sample_times[i]) { ++ goto out; ++ } ++ bandwidth[i] += (bandwidth_sum[i] / sample_times[i]); ++ } ++ ret = 0; ++out: ++ for (node = 0; node < node_num; node++) { ++ if (fps[node] != NULL) { ++ fclose(fps[node]); ++ } ++ } ++ return ret; ++} ++ ++/* ++ * collect root monitor group bandwidth from ++ * /sys/fs/resctrl/mon_data ++ */ ++int get_root_mon_bandwidth(long int *bandwidth, int node_num) ++{ ++ char path[VMTOP_GROUP_NAME_MAX] = {0}; ++ int ret = -1; ++ ++ ret = snprintf(path, VMTOP_GROUP_NAME_MAX, "%s/%s", RESCTRL_FILESYSTEM_DIR, MON_DATA_DIR); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ ret = get_mon_MB(bandwidth, path, node_num); ++ if (ret < 0) { ++ return ret; ++ } ++ ++ return 0; ++} ++ ++static int get_vm_ctl_path(int domain_id, char *vmname, char *path) ++{ ++ DIR *dir; ++ struct dirent *ent; ++ char vm_ctl_prefix[VMTOP_GROUP_NAME_MAX] = {0}; ++ int found = 0; ++ int ret = -1; ++ ++ if ((dir = opendir(RESCTRL_FILESYSTEM_DIR)) == NULL) { ++ return -1; ++ } ++ ++ ret = snprintf(vm_ctl_prefix, VMTOP_GROUP_NAME_MAX, "%s%d", ++ CTL_GROUP_PREFIX, domain_id); ++ if (ret < 0) { ++ goto out; ++ } ++ while ((ent = readdir(dir)) != NULL) { ++ if (strncmp(ent->d_name, vm_ctl_prefix, strlen(vm_ctl_prefix)) == 0) { ++ ret = snprintf(path, VMTOP_GROUP_NAME_MAX, "%s/%s/%s", ++ RESCTRL_FILESYSTEM_DIR, ent->d_name, MON_DATA_DIR); ++ if (ret < 0) { ++ goto out; ++ } ++ found = 1; ++ break; ++ } ++ } ++out: ++ closedir(dir); ++ if (found) { ++ return 0; ++ } else { ++ return -1; ++ } ++} ++ ++/* ++ * collect vm control group bandwidth from ++ * /sys/fs/resctrl/qemu-${domain_id}-${vmname}-xxx ++ */ ++int get_vm_ctl_bandwidth(struct domain *dom, int node_num) ++{ ++ char path[VMTOP_GROUP_NAME_MAX] = {0}; ++ int ret = -1; ++ ++ ret = get_vm_ctl_path(dom->domain_id, dom->vmname, path); ++ if (ret < 0) { ++ return -1; ++ } ++ ret = get_mon_MB(dom->ctl_bandwidth, path, node_num); ++ if (ret < 0) { ++ return -1; ++ } ++ return 0; ++} +\ No newline at end of file +diff --git a/src/resctrl.h b/src/resctrl.h +new file mode 100644 +index 0000000..7c94b3e +--- /dev/null ++++ b/src/resctrl.h +@@ -0,0 +1,47 @@ ++/****************************************************************************** ++ * Copyright (c) Huawei Technologies Co., Ltd. 2020-2020. All rights reserved. ++ * vmtop licensed under the Mulan PSL v2. ++ * You can use this software according to the terms and conditions of the Mulan PSL v2. ++ * You may obtain a copy of Mulan PSL v2 at: ++ * http://license.coscl.org.cn/MulanPSL2 ++ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR ++ * PURPOSE. ++ * See the Mulan PSL v2 for more details. ++ * Description: get domain's data ++ ********************************************************************************/ ++ ++#ifndef SRC_resctrl_H ++#define SRC_resctrl_H ++ ++#include ++#include "domain.h" ++ ++#define SYSINFO_PATH "/var/run/sysinfo" ++#define VMTOP_PATH "/var/run/sysinfo/vmtop" ++#define VMTOP_INFO_PATH "/var/run/sysinfo/vmtop/vmtop_info" ++#define VMTOP_INFO_BK_PATH "/var/run/sysinfo/vmtop/vmtop_info_bak" ++#define RESCTRL_FILESYSTEM_DIR "/sys/fs/resctrl" ++#define RESCTRL_MON_GROUPS_DIR "/sys/fs/resctrl/mon_groups" ++#define CTL_GROUP_PREFIX "qemu-" ++#define MON_DATA_DIR "mon_data" ++#define MON_DATA_PREFIX "mon_MB_" ++#define MON_DATA_FILE "mbm_total_bytes" ++#define VMTOP_GROUP_NAME_MAX 512 ++#define MAX_VM_TASKS_NUM 1024 ++#define MAX_VM_NUM 512 ++#define MAX_RESCTRL_VAL_LEN 32 ++#define MAX_RESCTRL_KEY_LEN 32 ++#define MAX_BANDWIDTH_LENGTH 24 ++#define SAMPLE_TIMES_INNER 2 ++#define SAMPLE_TIMES_OUTER 3 ++#define SAMPLE_INTERVAL_US_INNER 1000 ++#define SAMPLE_INTERVAL_US_OUTER 5000 ++#define SAMPLE_START 0 ++ ++bool enable_resctrl(void); ++int get_vm_ctl_bandwidth(struct domain *dom, int node_num); ++int get_root_mon_bandwidth(long int *bandwidth, int node_num); ++int write_resctrl_data_into_logfile(struct domain_list *scr_cur); ++int get_numa_num(int *node_num); ++#endif +\ No newline at end of file +diff --git a/src/type.h b/src/type.h +index 727b54b..1fc2637 100644 +--- a/src/type.h ++++ b/src/type.h +@@ -20,6 +20,7 @@ typedef unsigned long long u64; + #define DOMAIN_NAME_MAX 256 + #define BUF_SIZE 1024 + #define MAX_VCPU_NUM 1024 ++#define MAX_NODE_NUM 16 + + #define DELTA_VALUE(v) delta_ ## v + #define DFX_VALUE(v) v, DELTA_VALUE(v) +@@ -164,11 +165,15 @@ struct domain { + DFX_VALUE(gtime); + struct domain *threads; + int smp_vcpus; ++ int bandwidth_updated_succ; ++ long int ctl_bandwidth[MAX_NODE_NUM]; + }; + + struct domain_list { + struct domain *domains; + int num; ++ int node_num; ++ long int bandwidth[MAX_NODE_NUM]; + }; + + enum process_type { +diff --git a/src/utils.c b/src/utils.c +index 7bba7c2..5515bb4 100644 +--- a/src/utils.c ++++ b/src/utils.c +@@ -18,6 +18,7 @@ + #include + #include + #include ++#include + #include "utils.h" + + int read_file(char *buf, int bufsize, const char *path) +diff --git a/src/utils.h b/src/utils.h +index c8d0d01..52a5f1d 100644 +--- a/src/utils.h ++++ b/src/utils.h +@@ -13,6 +13,8 @@ + #ifndef SRC_UTILS_H + #define SRC_UTILS_H + ++#define TIME_STR_MAX 40 ++ + int read_file(char *buf, int bufsize, const char *path); + int get_time_str(char *buf, int bufsize); + int str_to_int(const char *str); +diff --git a/src/vmtop.c b/src/vmtop.c +index caa598e..0f76572 100644 +--- a/src/vmtop.c ++++ b/src/vmtop.c +@@ -15,13 +15,14 @@ + #include + #include + #include ++#include + #include "vmtop.h" + #include "field.h" + #include "domain.h" + #include "utils.h" + #include "../config.h" ++#include "resctrl.h" + +-#define TIME_STR_MAX 40 + #define TERM_MODE 0 + #define TEXT_MODE 1 + #define FLUSH_SCR() if (scr_mode == TERM_MODE) refresh(); else fflush(stdout) +@@ -38,6 +39,8 @@ int display_loop; + int scr_mode; + struct domain_list scr_cur; + struct domain_list scr_pre; ++bool resctrl_param_enable; ++bool resctrl_enable; + + static int (*print_scr)(const char *fmt, ...); + +@@ -72,7 +75,7 @@ static void init_parameter(void) + static void parse_args(int argc, char *argv[]) + { + int opt; +- char *arg_ops = "hvHd:n:bp:"; ++ char *arg_ops = "hvHd:n:bp:G"; + while ((opt = getopt(argc, argv, arg_ops)) != -1) { + switch (opt) { + case 'd': { +@@ -112,6 +115,10 @@ static void parse_args(int argc, char *argv[]) + } + break; + } ++ case 'G': { ++ resctrl_param_enable = true; ++ break; ++ } + default: + exit(1); /* exit vmtop when args are invalid */ + break; +@@ -130,6 +137,19 @@ static void summary(void) + } + + print_scr(summary_text, time_buf, PACKAGE_VERSION, scr_cur.num); ++ ++ if (resctrl_enable) { ++ long int hosttotal = 0; ++ int i; ++ ++ for (i = 0; i < scr_cur.node_num; i++) { ++ hosttotal += scr_cur.bandwidth[i]; ++ } ++ print_scr(summary_total_bandwidth, hosttotal); ++ for (i = 0; i < scr_cur.node_num; i++) { ++ print_scr(summary_numa_bandwidth, i, scr_cur.bandwidth[i]); ++ } ++ } + return; + } + +@@ -138,6 +158,11 @@ static void show_header(void) + int showd_width = 0; + int showd_field = 0; + attron(A_REVERSE); ++ ++ for (int i = FD_NODE0; i < FD_NODE0 + scr_cur.node_num; i++) { ++ fields[i].display_flag = resctrl_enable; ++ } ++ + for (int i = 0; i < FD_END; i++) { + if (fields[i].display_flag == 1 && + (i == FD_DID || i == FD_VMNAME || ++showd_field >= begin_field)) { +@@ -275,6 +300,30 @@ static void print_domain_field(struct domain *dom, int field) + print_scr("%*.3f", fields[i].align, st_max / 1000000.0f); + break; + } ++ case FD_NODE0: ++ case FD_NODE1: ++ case FD_NODE2: ++ case FD_NODE3: ++ case FD_NODE4: ++ case FD_NODE5: ++ case FD_NODE6: ++ case FD_NODE7: ++ case FD_NODE8: ++ case FD_NODE9: ++ case FD_NODE10: ++ case FD_NODE11: ++ case FD_NODE12: ++ case FD_NODE13: ++ case FD_NODE14: ++ case FD_NODE15: { ++ int index = i - FD_NODE0; ++ long int value = 0; ++ if (dom->bandwidth_updated_succ) { ++ value = dom->ctl_bandwidth[index]; ++ } ++ print_scr("%*ld", fields[i].align, value); ++ break; ++ } + default: + break; + } +@@ -504,6 +553,9 @@ int main(int argc, char *argv[]) + move(0, 0); + } + refresh_domains(&scr_cur, &scr_pre); ++ if ((resctrl_enable = enable_resctrl() && resctrl_param_enable)) { ++ refresh_domains_bandwidth(&scr_cur, &scr_pre); ++ } + + /* frame make */ + summary(); +@@ -528,5 +580,6 @@ int main(int argc, char *argv[]) + if (scr_mode == TERM_MODE) { + endwin(); /* quit from curses mode */ + } ++ + return 0; + } +-- +2.27.0 + diff --git a/vmtop.spec b/vmtop.spec index 95a2180..6f0897e 100644 --- a/vmtop.spec +++ b/vmtop.spec @@ -1,6 +1,6 @@ Name: vmtop Version: 1.1 -Release: 9 +Release: 10 Summary: A tool for collecting and analyzing data of virtual machine License: MulanPSL-2.0 Group: Application/System @@ -40,6 +40,7 @@ Patch0029: proc-del-loop-sscanf-for-proc-pid-stat-file.patch Patch0030: utils-del-realpath-from-read_file.patch Patch0031: add-README.zh.md.-update-README.md.patch Patch0032: bugfix-fixed-display-error-caused-by-missing-signal_exits.patch +Patch0033: support-displaying-bandwidth-information.patch Requires: libvirt, ncurses @@ -80,6 +81,9 @@ install -m 550 vmtop ${RPM_BUILD_ROOT}/usr/bin/%{name} %{_bindir}/vmtop %changelog +* Mon Sep 1 2025 huyu - 1.1-10 +- support displaying bandwidth information + * Thu Jun 19 2025 lutong - 1.1-9 - bugfix:fixed display error caused by missing signal_exits & revert change method of getting domain id -- Gitee