From: Xiubo Li Date: Mon, 19 Apr 2021 11:26:09 +0000 (+0800) Subject: cephfs-top: add read/write io speed support X-Git-Url: http://git.apps.os.sepia.ceph.com/?a=commitdiff_plain;h=41aa49d857cd880671f2654b66880da0599381cf;p=ceph.git cephfs-top: add read/write io speed support Calculate the speeds in cephfs-top. Fixes: https://tracker.ceph.com/issues/49811 Signed-off-by: Xiubo Li --- diff --git a/doc/man/8/cephfs-top.rst b/doc/man/8/cephfs-top.rst index 3a01bb7cdc9e5..936e02e201a27 100644 --- a/doc/man/8/cephfs-top.rst +++ b/doc/man/8/cephfs-top.rst @@ -79,6 +79,14 @@ Descriptions of fields total size of write IOs +.. describe:: rsp + + speed of read IOs compared with the last refresh + +.. describe:: wsp + + speed of write IOs compared with the last refresh + Availability ============ diff --git a/src/tools/cephfs/top/cephfs-top b/src/tools/cephfs/top/cephfs-top index 43019af706a4f..73bb411b7bed5 100755 --- a/src/tools/cephfs/top/cephfs-top +++ b/src/tools/cephfs/top/cephfs-top @@ -6,6 +6,7 @@ import curses import errno import json import signal +import time from collections import OrderedDict from datetime import datetime @@ -82,6 +83,10 @@ CLIENT_METADATA_VALID_METRICS_KEY = "valid_metrics" GLOBAL_METRICS_KEY = "global_metrics" GLOBAL_COUNTERS_KEY = "global_counters" +last_time = time.time() +last_read_size = {} +last_write_size = {} + def calc_perc(c): if c[0] == 0 and c[1] == 0: @@ -98,6 +103,13 @@ def calc_size(c): return round(c[1] / (1024 * 1024), 2) +# in MB/s +def calc_speed(size, duration): + if duration == 0: + return 0.0 + return round(size / (duration * 1024 * 1024), 2) + + def wrap(s, sl): """return a '+' suffixed wrapped string""" if len(s) < sl: @@ -224,6 +236,22 @@ class FSTop(object): # return empty string for none type return '' + def speed_items(self, item): + if item == "READ_IO_SIZES": + return "rsp" + if item == "WRITE_IO_SIZES": + return "wsp" + else: + # return empty string for none type + return '' + + def speed_mtype(self, typ): + if typ == MetricType.METRIC_TYPE_SIZE: + return "(MB/s)" + else: + # return empty string for none type + return '' + def refresh_top_line_and_build_coord(self): if self.topl is None: return @@ -245,6 +273,16 @@ class FSTop(object): x_coord_map[item] = (xp, nlen) xp += nlen + if item == "READ_IO_SIZES" or item == "WRITE_IO_SIZES": + it = f'{self.speed_items(item)}{self.speed_mtype(typ)}' + heading.append(it) + nlen = len(it) + len(ITEMS_PAD) + if item == "READ_IO_SIZES": + x_coord_map["READ_IO_SPEED"] = (xp, nlen) + if item == "WRITE_IO_SIZES": + x_coord_map["WRITE_IO_SPEED"] = (xp, nlen) + xp += nlen + for item in MAIN_WINDOW_TOP_LINE_ITEMS_END: heading.append(item) nlen = len(item) + len(ITEMS_PAD) @@ -268,6 +306,10 @@ class FSTop(object): return True def refresh_client(self, client_id, metrics, counters, client_meta, x_coord_map, y_coord): + global last_time + cur_time = time.time() + duration = cur_time - last_time + last_time = cur_time remaining_hlen = self.width - 1 for item in MAIN_WINDOW_TOP_LINE_ITEMS_START: coord = x_coord_map[item] @@ -293,6 +335,7 @@ class FSTop(object): return cidx = 0 + client_id = x_coord_map[FS_TOP_MAIN_WINDOW_COL_CLIENT_ID] for item in counters: coord = x_coord_map[item] hlen = coord[1] - len(ITEMS_PAD) @@ -302,7 +345,8 @@ class FSTop(object): else: remaining_hlen -= coord[1] m = metrics[cidx] - typ = MAIN_WINDOW_TOP_LINE_METRICS[MGR_STATS_COUNTERS[cidx]] + key = MGR_STATS_COUNTERS[cidx] + typ = MAIN_WINDOW_TOP_LINE_METRICS[key] if item.lower() in client_meta.get(CLIENT_METADATA_VALID_METRICS_KEY, []): if typ == MetricType.METRIC_TYPE_PERCENTAGE: self.mainw.addnstr(y_coord, coord[0], f'{calc_perc(m)}', hlen) @@ -310,6 +354,31 @@ class FSTop(object): self.mainw.addnstr(y_coord, coord[0], f'{calc_lat(m)}', hlen) elif typ == MetricType.METRIC_TYPE_SIZE: self.mainw.addnstr(y_coord, coord[0], f'{calc_size(m)}', hlen) + if remaining_hlen == 0: + return + if key == "READ_IO_SIZES": + coord = x_coord_map["READ_IO_SPEED"] + elif key == "WRITE_IO_SIZES": + coord = x_coord_map["WRITE_IO_SPEED"] + hlen = coord[1] - len(ITEMS_PAD) + hlen = min(hlen, remaining_hlen) + if remaining_hlen < coord[1]: + remaining_hlen = 0 + else: + remaining_hlen -= coord[1] + if key == "READ_IO_SIZES": + global last_read_size + last_size = last_read_size.get(client_id, 0) + size = m[1] - last_size + last_read_size[client_id] = m[1] + if key == "WRITE_IO_SIZES": + global last_write_size + last_size = last_write_size.get(client_id, 0) + size = m[1] - last_size + last_write_size[client_id] = m[1] + self.mainw.addnstr(y_coord, coord[0], + f'{calc_speed(size, duration)}', + hlen) else: # display 0th element from metric tuple self.mainw.addnstr(y_coord, coord[0], f'{m[0]}', hlen)