xref: /spdk/scripts/iostat.py (revision 17538bdc67021ec097536c683124234db1aac374)
1f1687a1bSjiaqizho#!/usr/bin/env python3
2*17538bdcSpaul luse#  SPDX-License-Identifier: BSD-3-Clause
3*17538bdcSpaul luse#  Copyright (C) 2019 Intel Corporation
4*17538bdcSpaul luse#  All rights reserved.
5*17538bdcSpaul luse#
6f1687a1bSjiaqizho
7f1687a1bSjiaqizhoimport logging
87610bc38SKonrad Sztyberimport os
9f1687a1bSjiaqizhoimport sys
10f1687a1bSjiaqizhoimport argparse
11f1687a1bSjiaqizhoimport time
127610bc38SKonrad Sztyber
137610bc38SKonrad Sztybersys.path.append(os.path.dirname(__file__) + '/../python')
147610bc38SKonrad Sztyber
157610bc38SKonrad Sztyberimport spdk.rpc as rpc  # noqa
16f1687a1bSjiaqizho
17f1687a1bSjiaqizho
18f1687a1bSjiaqizhoSPDK_CPU_STAT = "/proc/stat"
19f1687a1bSjiaqizhoSPDK_UPTIME = "/proc/uptime"
20f1687a1bSjiaqizho
21f1687a1bSjiaqizhoSPDK_CPU_STAT_HEAD = ['cpu_stat:', 'user_stat', 'nice_stat',
22f1687a1bSjiaqizho                      'system_stat', 'iowait_stat', 'steal_stat', 'idle_stat']
23f1687a1bSjiaqizhoSPDK_BDEV_KB_STAT_HEAD = ['Device', 'tps', 'KB_read/s',
24f1687a1bSjiaqizho                          'KB_wrtn/s', 'KB_dscd/s', 'KB_read', 'KB_wrtn', 'KB_dscd']
25f1687a1bSjiaqizhoSPDK_BDEV_MB_STAT_HEAD = ['Device', 'tps', 'MB_read/s',
26f1687a1bSjiaqizho                          'MB_wrtn/s', 'MB_dscd/s', 'MB_read', 'MB_wrtn', 'MB_dscd']
2781a8bc67SjiaqizhoSPDK_BDEV_EXT_STAT_HEAD = ['qu-sz', 'aqu-sz', 'wareq-sz', 'rareq-sz', 'w_await(us)', 'r_await(us)', 'util']
2881a8bc67Sjiaqizho
29f1687a1bSjiaqizho
30f1687a1bSjiaqizhoSPDK_MAX_SECTORS = 0xffffffff
31f1687a1bSjiaqizho
32f1687a1bSjiaqizho
33f1687a1bSjiaqizhoclass BdevStat:
34f1687a1bSjiaqizho
35f1687a1bSjiaqizho    def __init__(self, dictionary):
36f1687a1bSjiaqizho        if dictionary is None:
37f1687a1bSjiaqizho            return
3881a8bc67Sjiaqizho        self.qd_period = 0
39f1687a1bSjiaqizho        for k, value in dictionary.items():
40f1687a1bSjiaqizho            if k == 'name':
41f1687a1bSjiaqizho                self.bdev_name = value
42f1687a1bSjiaqizho            elif k == 'bytes_read':
43f1687a1bSjiaqizho                self.rd_sectors = value >> 9
44f1687a1bSjiaqizho            elif k == 'bytes_written':
45f1687a1bSjiaqizho                self.wr_sectors = value >> 9
46f1687a1bSjiaqizho            elif k == 'bytes_unmapped':
47f1687a1bSjiaqizho                self.dc_sectors = value >> 9
48f1687a1bSjiaqizho            elif k == 'num_read_ops':
49f1687a1bSjiaqizho                self.rd_ios = value
50f1687a1bSjiaqizho            elif k == 'num_write_ops':
51f1687a1bSjiaqizho                self.wr_ios = value
52f1687a1bSjiaqizho            elif k == 'num_unmap_ops':
53f1687a1bSjiaqizho                self.dc_ios = value
54f1687a1bSjiaqizho            elif k == 'read_latency_ticks':
55f1687a1bSjiaqizho                self.rd_ticks = value
56f1687a1bSjiaqizho            elif k == 'write_latency_ticks':
57f1687a1bSjiaqizho                self.wr_ticks = value
58f1687a1bSjiaqizho            elif k == 'unmap_latency_ticks':
59f1687a1bSjiaqizho                self.dc_ticks = value
6081a8bc67Sjiaqizho            elif k == 'queue_depth_polling_period':
6181a8bc67Sjiaqizho                self.qd_period = value
62f1687a1bSjiaqizho            elif k == 'queue_depth':
6381a8bc67Sjiaqizho                self.queue_depth = value
64f1687a1bSjiaqizho            elif k == 'io_time':
6581a8bc67Sjiaqizho                self.io_time = value
66f1687a1bSjiaqizho            elif k == 'weighted_io_time':
6781a8bc67Sjiaqizho                self.weighted_io_time = value
68f1687a1bSjiaqizho        self.upt = 0.0
69f1687a1bSjiaqizho
70f1687a1bSjiaqizho    def __getattr__(self, name):
71f1687a1bSjiaqizho        return 0
72f1687a1bSjiaqizho
73f1687a1bSjiaqizho
74f1687a1bSjiaqizhodef uptime():
75f1687a1bSjiaqizho    with open(SPDK_UPTIME, 'r') as f:
76f1687a1bSjiaqizho        return float(f.readline().split()[0])
77f1687a1bSjiaqizho
78f1687a1bSjiaqizho
79f1687a1bSjiaqizhodef _stat_format(data, header, leave_first=False):
80f1687a1bSjiaqizho    list_size = len(data)
81f1687a1bSjiaqizho    header_len = len(header)
82f1687a1bSjiaqizho
83f1687a1bSjiaqizho    if list_size == 0:
84f1687a1bSjiaqizho        raise AssertionError
85f1687a1bSjiaqizho    list_len = len(data[0])
86f1687a1bSjiaqizho
87f1687a1bSjiaqizho    for ll in data:
88f1687a1bSjiaqizho        if len(ll) != list_len:
89f1687a1bSjiaqizho            raise AssertionError
90f1687a1bSjiaqizho        for i, r in enumerate(ll):
91f1687a1bSjiaqizho            ll[i] = str(r)
92f1687a1bSjiaqizho
93f1687a1bSjiaqizho    if (leave_first and list_len + 1 != header_len) or \
94f1687a1bSjiaqizho            (not leave_first and list_len != header_len):
95f1687a1bSjiaqizho        raise AssertionError
96f1687a1bSjiaqizho
97f1687a1bSjiaqizho    item_sizes = [0 for i in range(header_len)]
98f1687a1bSjiaqizho
99f1687a1bSjiaqizho    for i in range(0, list_len):
100f1687a1bSjiaqizho        if leave_first and i == 0:
101f1687a1bSjiaqizho            item_sizes[i] = len(header[i + 1])
102f1687a1bSjiaqizho
103f1687a1bSjiaqizho        data_len = 0
104f1687a1bSjiaqizho        for x in data:
105f1687a1bSjiaqizho            data_len = max(data_len, len(x[i]))
106f1687a1bSjiaqizho        index = i + 1 if leave_first else i
107f1687a1bSjiaqizho        item_sizes[index] = max(len(header[index]), data_len)
108f1687a1bSjiaqizho
109f1687a1bSjiaqizho    _format = '  '.join('%%-%ss' % item_sizes[i] for i in range(0, header_len))
110f1687a1bSjiaqizho    print(_format % tuple(header))
111f1687a1bSjiaqizho    if leave_first:
112f1687a1bSjiaqizho        print('\n'.join(_format % ('', *tuple(ll)) for ll in data))
113f1687a1bSjiaqizho    else:
114f1687a1bSjiaqizho        print('\n'.join(_format % tuple(ll) for ll in data))
115f1687a1bSjiaqizho
116f1687a1bSjiaqizho    print()
117f1687a1bSjiaqizho    sys.stdout.flush()
118f1687a1bSjiaqizho
119f1687a1bSjiaqizho
120f1687a1bSjiaqizhodef read_cpu_stat(last_cpu_info, cpu_info):
121f1687a1bSjiaqizho    jiffies = 0
122f1687a1bSjiaqizho    for i in range(0, 7):
123f1687a1bSjiaqizho        jiffies += cpu_info[i] - \
124f1687a1bSjiaqizho            (last_cpu_info[i] if last_cpu_info else 0)
125f1687a1bSjiaqizho
126f1687a1bSjiaqizho    if last_cpu_info:
127f1687a1bSjiaqizho        info_stat = [
128f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[0] - last_cpu_info[0]) / jiffies),
129f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[1] - last_cpu_info[1]) / jiffies),
130f1687a1bSjiaqizho            "{:.2%}".format(((cpu_info[2] + cpu_info[5] + cpu_info[6]) -
131f1687a1bSjiaqizho                             (last_cpu_info[2] + last_cpu_info[5] + last_cpu_info[6])) / jiffies),
132f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[4] - last_cpu_info[4]) / jiffies),
133f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[7] - last_cpu_info[7]) / jiffies),
134f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[3] - last_cpu_info[3]) / jiffies),
135f1687a1bSjiaqizho        ]
136f1687a1bSjiaqizho    else:
137f1687a1bSjiaqizho        info_stat = [
138f1687a1bSjiaqizho            "{:.2%}".format(cpu_info[0] / jiffies),
139f1687a1bSjiaqizho            "{:.2%}".format(cpu_info[1] / jiffies),
140f1687a1bSjiaqizho            "{:.2%}".format((cpu_info[2] + cpu_info[5]
141f1687a1bSjiaqizho                             + cpu_info[6]) / jiffies),
142f1687a1bSjiaqizho            "{:.2%}".format(cpu_info[4] / jiffies),
143f1687a1bSjiaqizho            "{:.2%}".format(cpu_info[7] / jiffies),
144f1687a1bSjiaqizho            "{:.2%}".format(cpu_info[3] / jiffies),
145f1687a1bSjiaqizho        ]
146f1687a1bSjiaqizho
147f1687a1bSjiaqizho    _stat_format([info_stat], SPDK_CPU_STAT_HEAD, True)
148f1687a1bSjiaqizho
149f1687a1bSjiaqizho
150f1687a1bSjiaqizhodef check_positive(value):
151f1687a1bSjiaqizho    v = int(value)
152f1687a1bSjiaqizho    if v <= 0:
153f1687a1bSjiaqizho        raise argparse.ArgumentTypeError("%s should be positive int value" % v)
154f1687a1bSjiaqizho    return v
155f1687a1bSjiaqizho
156f1687a1bSjiaqizho
157f1687a1bSjiaqizhodef get_cpu_stat():
158f1687a1bSjiaqizho    with open(SPDK_CPU_STAT, "r") as cpu_file:
159f1687a1bSjiaqizho        cpu_dump_info = []
160f1687a1bSjiaqizho        line = cpu_file.readline()
161f1687a1bSjiaqizho        while line:
162f1687a1bSjiaqizho            line = line.strip()
163f1687a1bSjiaqizho            if "cpu " in line:
164f1687a1bSjiaqizho                cpu_dump_info = [int(data) for data in line[5:].split(' ')]
165f1687a1bSjiaqizho                break
166f1687a1bSjiaqizho
167f1687a1bSjiaqizho            line = cpu_file.readline()
168f1687a1bSjiaqizho    return cpu_dump_info
169f1687a1bSjiaqizho
170f1687a1bSjiaqizho
17181a8bc67Sjiaqizhodef read_bdev_stat(last_stat, stat, mb, use_upt, ext_info):
172f1687a1bSjiaqizho    if use_upt:
173f1687a1bSjiaqizho        upt_cur = uptime()
174f1687a1bSjiaqizho    else:
175f1687a1bSjiaqizho        upt_cur = stat['ticks']
17681a8bc67Sjiaqizho
177f1687a1bSjiaqizho    upt_rate = stat['tick_rate']
178f1687a1bSjiaqizho
179f1687a1bSjiaqizho    info_stats = []
180f1687a1bSjiaqizho    unit = 2048 if mb else 2
181f1687a1bSjiaqizho
182f1687a1bSjiaqizho    bdev_stats = []
183f1687a1bSjiaqizho    if last_stat:
184f1687a1bSjiaqizho        for bdev in stat['bdevs']:
185f1687a1bSjiaqizho            _stat = BdevStat(bdev)
186f1687a1bSjiaqizho            _stat.upt = upt_cur
187f1687a1bSjiaqizho            bdev_stats.append(_stat)
188f1687a1bSjiaqizho            _last_stat = None
189f1687a1bSjiaqizho            for last_bdev in last_stat:
190f1687a1bSjiaqizho                if (_stat.bdev_name == last_bdev.bdev_name):
191f1687a1bSjiaqizho                    _last_stat = last_bdev
192f1687a1bSjiaqizho                    break
193f1687a1bSjiaqizho
194f1687a1bSjiaqizho            # get the interval time
195f1687a1bSjiaqizho            if use_upt:
196f1687a1bSjiaqizho                upt = _stat.upt - _last_stat.upt
197f1687a1bSjiaqizho            else:
198f1687a1bSjiaqizho                upt = (_stat.upt - _last_stat.upt) / upt_rate
199f1687a1bSjiaqizho
200f1687a1bSjiaqizho            rd_sec = _stat.rd_sectors - _last_stat.rd_sectors
201f1687a1bSjiaqizho            if (_stat.rd_sectors < _last_stat.rd_sectors) and (_last_stat.rd_sectors <= SPDK_MAX_SECTORS):
202f1687a1bSjiaqizho                rd_sec &= SPDK_MAX_SECTORS
203f1687a1bSjiaqizho
204f1687a1bSjiaqizho            wr_sec = _stat.wr_sectors - _last_stat.wr_sectors
205f1687a1bSjiaqizho            if (_stat.wr_sectors < _last_stat.wr_sectors) and (_last_stat.wr_sectors <= SPDK_MAX_SECTORS):
206f1687a1bSjiaqizho                wr_sec &= SPDK_MAX_SECTORS
207f1687a1bSjiaqizho
208f1687a1bSjiaqizho            dc_sec = _stat.dc_sectors - _last_stat.dc_sectors
209f1687a1bSjiaqizho            if (_stat.dc_sectors < _last_stat.dc_sectors) and (_last_stat.dc_sectors <= SPDK_MAX_SECTORS):
210f1687a1bSjiaqizho                dc_sec &= SPDK_MAX_SECTORS
211f1687a1bSjiaqizho
212f1687a1bSjiaqizho            tps = ((_stat.rd_ios + _stat.dc_ios + _stat.wr_ios) -
213f1687a1bSjiaqizho                   (_last_stat.rd_ios + _last_stat.dc_ios + _last_stat.wr_ios)) / upt
214f1687a1bSjiaqizho
215f1687a1bSjiaqizho            info_stat = [
216f1687a1bSjiaqizho                _stat.bdev_name,
217f1687a1bSjiaqizho                "{:.2f}".format(tps),
218f1687a1bSjiaqizho                "{:.2f}".format(
219f1687a1bSjiaqizho                    (_stat.rd_sectors - _last_stat.rd_sectors) / upt / unit),
220f1687a1bSjiaqizho                "{:.2f}".format(
221f1687a1bSjiaqizho                    (_stat.wr_sectors - _last_stat.wr_sectors) / upt / unit),
222f1687a1bSjiaqizho                "{:.2f}".format(
223f1687a1bSjiaqizho                    (_stat.dc_sectors - _last_stat.dc_sectors) / upt / unit),
224f1687a1bSjiaqizho                "{:.2f}".format(rd_sec / unit),
225f1687a1bSjiaqizho                "{:.2f}".format(wr_sec / unit),
226f1687a1bSjiaqizho                "{:.2f}".format(dc_sec / unit),
227f1687a1bSjiaqizho            ]
22881a8bc67Sjiaqizho            if ext_info:
22981a8bc67Sjiaqizho                if _stat.qd_period > 0:
23081a8bc67Sjiaqizho                    tot_sampling_time = upt * 1000000 / _stat.qd_period
23181a8bc67Sjiaqizho                    busy_times = (_stat.io_time - _last_stat.io_time) / _stat.qd_period
23281a8bc67Sjiaqizho
23381a8bc67Sjiaqizho                    wr_ios = _stat.wr_ios - _last_stat.wr_ios
23481a8bc67Sjiaqizho                    rd_ios = _stat.rd_ios - _last_stat.rd_ios
23581a8bc67Sjiaqizho                    if busy_times != 0:
23681a8bc67Sjiaqizho                        aqu_sz = (_stat.weighted_io_time - _last_stat.weighted_io_time) / _stat.qd_period / busy_times
23781a8bc67Sjiaqizho                    else:
23881a8bc67Sjiaqizho                        aqu_sz = 0
23981a8bc67Sjiaqizho
24081a8bc67Sjiaqizho                    if wr_ios != 0:
24181a8bc67Sjiaqizho                        wareq_sz = wr_sec / wr_ios
24281a8bc67Sjiaqizho                        w_await = (_stat.wr_ticks * 1000000 / upt_rate -
24381a8bc67Sjiaqizho                                   _last_stat.wr_ticks * 1000000 / upt_rate) / wr_ios
24481a8bc67Sjiaqizho                    else:
24581a8bc67Sjiaqizho                        wareq_sz = 0
24681a8bc67Sjiaqizho                        w_await = 0
24781a8bc67Sjiaqizho
24881a8bc67Sjiaqizho                    if rd_ios != 0:
24981a8bc67Sjiaqizho                        rareq_sz = rd_sec / rd_ios
25081a8bc67Sjiaqizho                        r_await = (_stat.rd_ticks * 1000000 / upt_rate -
25181a8bc67Sjiaqizho                                   _last_stat.rd_ticks * 1000000 / upt_rate) / rd_ios
25281a8bc67Sjiaqizho                    else:
25381a8bc67Sjiaqizho                        rareq_sz = 0
25481a8bc67Sjiaqizho                        r_await = 0
25581a8bc67Sjiaqizho
25681a8bc67Sjiaqizho                    util = busy_times / tot_sampling_time
25781a8bc67Sjiaqizho
25881a8bc67Sjiaqizho                    info_stat += [
25981a8bc67Sjiaqizho                        "{:.2f}".format(_stat.queue_depth),
26081a8bc67Sjiaqizho                        "{:.2f}".format(aqu_sz),
26181a8bc67Sjiaqizho                        "{:.2f}".format(wareq_sz),
26281a8bc67Sjiaqizho                        "{:.2f}".format(rareq_sz),
26381a8bc67Sjiaqizho                        "{:.2f}".format(w_await),
26481a8bc67Sjiaqizho                        "{:.2f}".format(r_await),
26581a8bc67Sjiaqizho                        "{:.2f}".format(util),
26681a8bc67Sjiaqizho                    ]
26781a8bc67Sjiaqizho                else:
26881a8bc67Sjiaqizho                    info_stat += ["N/A"] * len(SPDK_BDEV_EXT_STAT_HEAD)
26981a8bc67Sjiaqizho
270f1687a1bSjiaqizho            info_stats.append(info_stat)
271f1687a1bSjiaqizho    else:
272f1687a1bSjiaqizho        for bdev in stat['bdevs']:
273f1687a1bSjiaqizho            _stat = BdevStat(bdev)
274f1687a1bSjiaqizho            _stat.upt = upt_cur
275f1687a1bSjiaqizho            bdev_stats.append(_stat)
276f1687a1bSjiaqizho
277f1687a1bSjiaqizho            if use_upt:
278f1687a1bSjiaqizho                upt = _stat.upt
279f1687a1bSjiaqizho            else:
280f1687a1bSjiaqizho                upt = _stat.upt / upt_rate
281f1687a1bSjiaqizho
282f1687a1bSjiaqizho            tps = (_stat.rd_ios + _stat.dc_ios + _stat.wr_ios) / upt
283f1687a1bSjiaqizho            info_stat = [
284f1687a1bSjiaqizho                _stat.bdev_name,
285f1687a1bSjiaqizho                "{:.2f}".format(tps),
286f1687a1bSjiaqizho                "{:.2f}".format(_stat.rd_sectors / upt / unit),
287f1687a1bSjiaqizho                "{:.2f}".format(_stat.wr_sectors / upt / unit),
288f1687a1bSjiaqizho                "{:.2f}".format(_stat.dc_sectors / upt / unit),
289f1687a1bSjiaqizho                "{:.2f}".format(_stat.rd_sectors / unit),
290f1687a1bSjiaqizho                "{:.2f}".format(_stat.wr_sectors / unit),
291f1687a1bSjiaqizho                "{:.2f}".format(_stat.dc_sectors / unit),
292f1687a1bSjiaqizho            ]
29381a8bc67Sjiaqizho
29481a8bc67Sjiaqizho            # add extended statistics
29581a8bc67Sjiaqizho            if ext_info:
29681a8bc67Sjiaqizho                if _stat.qd_period > 0:
29781a8bc67Sjiaqizho                    tot_sampling_time = upt * 1000000 / _stat.qd_period
29881a8bc67Sjiaqizho                    busy_times = _stat.io_time / _stat.qd_period
29981a8bc67Sjiaqizho                    if busy_times != 0:
30081a8bc67Sjiaqizho                        aqu_sz = _stat.weighted_io_time / _stat.qd_period / busy_times
30181a8bc67Sjiaqizho                    else:
30281a8bc67Sjiaqizho                        aqu_sz = 0
30381a8bc67Sjiaqizho
30481a8bc67Sjiaqizho                    if _stat.wr_ios != 0:
30581a8bc67Sjiaqizho                        wareq_sz = _stat.wr_sectors / _stat.wr_ios
30681a8bc67Sjiaqizho                        w_await = _stat.wr_ticks * 1000000 / upt_rate / _stat.wr_ios
30781a8bc67Sjiaqizho                    else:
30881a8bc67Sjiaqizho                        wareq_sz = 0
30981a8bc67Sjiaqizho                        w_await = 0
31081a8bc67Sjiaqizho
31181a8bc67Sjiaqizho                    if _stat.rd_ios != 0:
31281a8bc67Sjiaqizho                        rareq_sz = _stat.rd_sectors / _stat.rd_ios
31381a8bc67Sjiaqizho                        r_await = _stat.rd_ticks * 1000000 / upt_rate / _stat.rd_ios
31481a8bc67Sjiaqizho                    else:
31581a8bc67Sjiaqizho                        rareq_sz = 0
31681a8bc67Sjiaqizho                        r_await = 0
31781a8bc67Sjiaqizho
31881a8bc67Sjiaqizho                    util = busy_times / tot_sampling_time
31981a8bc67Sjiaqizho
32081a8bc67Sjiaqizho                    info_stat += [
32181a8bc67Sjiaqizho                        "{:.2f}".format(_stat.queue_depth),
32281a8bc67Sjiaqizho                        "{:.2f}".format(aqu_sz),
32381a8bc67Sjiaqizho                        "{:.2f}".format(wareq_sz),
32481a8bc67Sjiaqizho                        "{:.2f}".format(rareq_sz),
32581a8bc67Sjiaqizho                        "{:.2f}".format(w_await),
32681a8bc67Sjiaqizho                        "{:.2f}".format(r_await),
32781a8bc67Sjiaqizho                        "{:.2f}".format(util),
32881a8bc67Sjiaqizho                    ]
32981a8bc67Sjiaqizho                else:
33081a8bc67Sjiaqizho                    info_stat += ["N/A"] * len(SPDK_BDEV_EXT_STAT_HEAD)
33181a8bc67Sjiaqizho
332f1687a1bSjiaqizho            info_stats.append(info_stat)
333f1687a1bSjiaqizho
33481a8bc67Sjiaqizho    head = []
33581a8bc67Sjiaqizho    head += SPDK_BDEV_MB_STAT_HEAD if mb else SPDK_BDEV_KB_STAT_HEAD
33681a8bc67Sjiaqizho    if ext_info:
33781a8bc67Sjiaqizho        head += SPDK_BDEV_EXT_STAT_HEAD
33881a8bc67Sjiaqizho
33981a8bc67Sjiaqizho    _stat_format(info_stats, head)
340f1687a1bSjiaqizho    return bdev_stats
341f1687a1bSjiaqizho
342f1687a1bSjiaqizho
343f1687a1bSjiaqizhodef get_bdev_stat(client, name):
344f1687a1bSjiaqizho    return rpc.bdev.bdev_get_iostat(client, name=name)
345f1687a1bSjiaqizho
346f1687a1bSjiaqizho
347f1687a1bSjiaqizhodef io_stat_display(args, cpu_info, stat):
348f1687a1bSjiaqizho    if args.cpu_stat and not args.bdev_stat:
349f1687a1bSjiaqizho        _cpu_info = get_cpu_stat()
350f1687a1bSjiaqizho        read_cpu_stat(cpu_info, _cpu_info)
351f1687a1bSjiaqizho        return _cpu_info, None
352f1687a1bSjiaqizho
353f1687a1bSjiaqizho    if args.bdev_stat and not args.cpu_stat:
354f1687a1bSjiaqizho        _stat = get_bdev_stat(args.client, args.name)
355f1687a1bSjiaqizho        bdev_stats = read_bdev_stat(
35681a8bc67Sjiaqizho            stat, _stat, args.mb_display, args.use_uptime, args.extended_display)
357f1687a1bSjiaqizho        return None, bdev_stats
358f1687a1bSjiaqizho
359f1687a1bSjiaqizho    _cpu_info = get_cpu_stat()
360f1687a1bSjiaqizho    read_cpu_stat(cpu_info, _cpu_info)
361f1687a1bSjiaqizho
362f1687a1bSjiaqizho    _stat = get_bdev_stat(args.client, args.name)
36381a8bc67Sjiaqizho    bdev_stats = read_bdev_stat(stat, _stat, args.mb_display, args.use_uptime, args.extended_display)
364f1687a1bSjiaqizho    return _cpu_info, bdev_stats
365f1687a1bSjiaqizho
366f1687a1bSjiaqizho
367f1687a1bSjiaqizhodef io_stat_display_loop(args):
368f1687a1bSjiaqizho    interval = args.interval
369f1687a1bSjiaqizho    time_in_second = args.time_in_second
370f1687a1bSjiaqizho    args.client = rpc.client.JSONRPCClient(
371f1687a1bSjiaqizho        args.server_addr, args.port, args.timeout, log_level=getattr(logging, args.verbose.upper()))
372f1687a1bSjiaqizho
373f1687a1bSjiaqizho    last_cpu_stat = None
374f1687a1bSjiaqizho    bdev_stats = None
375f1687a1bSjiaqizho
376f1687a1bSjiaqizho    cur = 0
377f1687a1bSjiaqizho    while True:
378f1687a1bSjiaqizho        last_cpu_stat, bdev_stats = io_stat_display(
379f1687a1bSjiaqizho            args, last_cpu_stat, bdev_stats)
380f1687a1bSjiaqizho
381f1687a1bSjiaqizho        time.sleep(interval)
382f1687a1bSjiaqizho        cur += interval
383f1687a1bSjiaqizho        if cur >= time_in_second:
384f1687a1bSjiaqizho            break
385f1687a1bSjiaqizho
386f1687a1bSjiaqizho
387f1687a1bSjiaqizhoif __name__ == "__main__":
388f1687a1bSjiaqizho    parser = argparse.ArgumentParser(
389f1687a1bSjiaqizho        description='SPDK iostats command line interface')
390f1687a1bSjiaqizho
391f1687a1bSjiaqizho    parser.add_argument('-c', '--cpu-status', dest='cpu_stat',
392f1687a1bSjiaqizho                        action='store_true', help="Only display cpu status",
393f1687a1bSjiaqizho                        required=False, default=False)
394f1687a1bSjiaqizho
395f1687a1bSjiaqizho    parser.add_argument('-d', '--bdev-status', dest='bdev_stat',
396f1687a1bSjiaqizho                        action='store_true', help="Only display Blockdev io stats",
397f1687a1bSjiaqizho                        required=False, default=False)
398f1687a1bSjiaqizho
399f1687a1bSjiaqizho    parser.add_argument('-k', '--kb-display', dest='kb_display',
400f1687a1bSjiaqizho                        action='store_true', help="Display drive stats in KiB",
401f1687a1bSjiaqizho                        required=False, default=False)
402f1687a1bSjiaqizho
403f1687a1bSjiaqizho    parser.add_argument('-m', '--mb-display', dest='mb_display',
404f1687a1bSjiaqizho                        action='store_true', help="Display drive stats in MiB",
405f1687a1bSjiaqizho                        required=False, default=False)
406f1687a1bSjiaqizho
407f1687a1bSjiaqizho    parser.add_argument('-u', '--use-uptime', dest='use_uptime',
408f1687a1bSjiaqizho                        action='store_true', help='Use uptime or spdk ticks(default) as \
409f1687a1bSjiaqizho                        the interval variable to calculate iostat changes.',
410f1687a1bSjiaqizho                        required=False, default=False)
411f1687a1bSjiaqizho
412f1687a1bSjiaqizho    parser.add_argument('-i', '--interval', dest='interval',
413f1687a1bSjiaqizho                        type=check_positive, help='Time interval (in seconds) on which \
414f1687a1bSjiaqizho                        to poll I/O stats. Used in conjunction with -t',
415f1687a1bSjiaqizho                        required=False, default=0)
416f1687a1bSjiaqizho
417f1687a1bSjiaqizho    parser.add_argument('-t', '--time', dest='time_in_second',
418f1687a1bSjiaqizho                        type=check_positive, help='The number of second to display stats \
419f1687a1bSjiaqizho                        before returning. Used in conjunction with -i',
420f1687a1bSjiaqizho                        required=False, default=0)
421f1687a1bSjiaqizho
422f1687a1bSjiaqizho    parser.add_argument('-s', "--server", dest='server_addr',
423f1687a1bSjiaqizho                        help='RPC domain socket path or IP address',
424f1687a1bSjiaqizho                        default='/var/tmp/spdk.sock')
425f1687a1bSjiaqizho
426f1687a1bSjiaqizho    parser.add_argument('-p', "--port", dest='port',
427f1687a1bSjiaqizho                        help='RPC port number (if server_addr is IP address)',
428f1687a1bSjiaqizho                        default=4420, type=int)
429f1687a1bSjiaqizho
430f1687a1bSjiaqizho    parser.add_argument('-b', '--name', dest='name',
431f1687a1bSjiaqizho                        help="Name of the Blockdev. Example: Nvme0n1", required=False)
432f1687a1bSjiaqizho
433f1687a1bSjiaqizho    parser.add_argument('-o', '--timeout', dest='timeout',
434f1687a1bSjiaqizho                        help='Timeout as a floating point number expressed in seconds \
435f1687a1bSjiaqizho                        waiting for response. Default: 60.0',
436f1687a1bSjiaqizho                        default=60.0, type=float)
437f1687a1bSjiaqizho
438f1687a1bSjiaqizho    parser.add_argument('-v', dest='verbose', action='store_const', const="INFO",
439f1687a1bSjiaqizho                        help='Set verbose mode to INFO', default="ERROR")
440f1687a1bSjiaqizho
44181a8bc67Sjiaqizho    parser.add_argument('-x', '--extended', dest='extended_display',
44281a8bc67Sjiaqizho                        action='store_true', help="Display extended statistics.",
44381a8bc67Sjiaqizho                        required=False, default=False)
44481a8bc67Sjiaqizho
445f1687a1bSjiaqizho    args = parser.parse_args()
446f1687a1bSjiaqizho    if ((args.interval == 0 and args.time_in_second != 0) or
447f1687a1bSjiaqizho            (args.interval != 0 and args.time_in_second == 0)):
448f1687a1bSjiaqizho        raise argparse.ArgumentTypeError(
449f1687a1bSjiaqizho            "interval and time_in_second should be greater than 0 at the same time")
450f1687a1bSjiaqizho
451f1687a1bSjiaqizho    if args.kb_display and args.mb_display:
452f1687a1bSjiaqizho        parser.print_help()
453f1687a1bSjiaqizho        exit()
454f1687a1bSjiaqizho
455f1687a1bSjiaqizho    io_stat_display_loop(args)
456