Skip to content

Commit

Permalink
Merge 4d18440 into be1a35f
Browse files Browse the repository at this point in the history
  • Loading branch information
giampaolo committed Jul 28, 2018
2 parents be1a35f + 4d18440 commit 4482266
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 58 deletions.
3 changes: 3 additions & 0 deletions HISTORY.rst
Expand Up @@ -24,6 +24,9 @@ XXXX-XX-XX
MemoryError. (patch by sylvainduchesne)
- 1309_: [Linux] Process.status() is unable to recognie "idle" and "parked"
statuses (returns '?').
- 1313_: [Linux] disk_io_counters() can report inflated IO counters due to
counting disk device and disk partition(s) twice. This was fixed and now it
mirrors "iostat" cmdline tool behavior.

5.4.6
=====
Expand Down
53 changes: 26 additions & 27 deletions psutil/_pslinux.py
Expand Up @@ -252,19 +252,38 @@ def file_flags_to_mode(flags):
return mode


def get_sector_size(partition):
"""Return the sector size of a partition.
Used by disk_io_counters().
"""
def get_sector_size(name):
"""Return the sector size of a device or partition name."""
# Some devices may have a slash in their name (e.g. cciss/c0d0...).
name = name.replace('/', '!')
try:
with open("/sys/block/%s/queue/hw_sector_size" % partition, "rt") as f:
with open("/sys/block/%s/queue/hw_sector_size" % name, "rt") as f:
return int(f.read())
except (IOError, ValueError):
# man iostat states that sectors are equivalent with blocks and
# have a size of 512 bytes since 2.4 kernels.
return SECTOR_SIZE_FALLBACK


def is_storage_device(name):
"""Return True if the given name refers to a physical (e.g. "sda",
"nvme0n1") or virtual (e.g. "loop1", "ram") storage device.
In case name refers to a device's partition (e.g. "sda1", "nvme0n1p1")
this is supposed to return False.
"""
# Readapted from iostat source code, see:
# https://github.com/sysstat/sysstat/blob/
# 97912938cd476645b267280069e83b1c8dc0e1c7/common.c#L208
# Some devices may have a slash in their name (e.g. cciss/c0d0...).
name = name.replace('/', '!')
including_virtual = True
if including_virtual:
path = "/sys/block/%s" % name
else:
path = "/sys/block/%s/device" % name
return os.access(path, os.F_OK)


@memoize
def set_scputimes_ntuple(procfs_path):
"""Set a namedtuple of variable fields depending on the CPU times
Expand Down Expand Up @@ -1032,28 +1051,7 @@ def disk_io_counters():
"""Return disk I/O statistics for every disk installed on the
system as a dict of raw tuples.
"""
# determine partitions we want to look for
def get_partitions():
partitions = []
with open_text("%s/partitions" % get_procfs_path()) as f:
lines = f.readlines()[2:]
for line in reversed(lines):
_, _, _, name = line.split()
if name[-1].isdigit():
# we're dealing with a partition (e.g. 'sda1'); 'sda' will
# also be around but we want to omit it
partitions.append(name)
else:
if not partitions or not partitions[-1].startswith(name):
# we're dealing with a disk entity for which no
# partitions have been defined (e.g. 'sda' but
# 'sda1' was not around), see:
# https://github.com/giampaolo/psutil/issues/338
partitions.append(name)
return partitions

retdict = {}
partitions = get_partitions()
with open_text("%s/diskstats" % get_procfs_path()) as f:
lines = f.readlines()
for line in lines:
Expand Down Expand Up @@ -1091,12 +1089,13 @@ def get_partitions():
else:
raise ValueError("not sure how to interpret line %r" % line)

if name in partitions:
if is_storage_device(name):
ssize = get_sector_size(name)
rbytes *= ssize
wbytes *= ssize
retdict[name] = (reads, writes, rbytes, wbytes, rtime, wtime,
reads_merged, writes_merged, busy_time)

return retdict


Expand Down
68 changes: 37 additions & 31 deletions psutil/tests/test_linux.py
Expand Up @@ -995,16 +995,18 @@ def test_disk_io_counters_kernel_2_4_mocked(self):
with mock_open_content(
'/proc/diskstats',
" 3 0 1 hda 2 3 4 5 6 7 8 9 10 11 12"):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_merged_count, 2)
self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE)
self.assertEqual(ret.read_time, 4)
self.assertEqual(ret.write_count, 5)
self.assertEqual(ret.write_merged_count, 6)
self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE)
self.assertEqual(ret.write_time, 8)
self.assertEqual(ret.busy_time, 10)
with mock.patch('psutil._pslinux.is_storage_device',
return_value=True):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_merged_count, 2)
self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE)
self.assertEqual(ret.read_time, 4)
self.assertEqual(ret.write_count, 5)
self.assertEqual(ret.write_merged_count, 6)
self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE)
self.assertEqual(ret.write_time, 8)
self.assertEqual(ret.busy_time, 10)

def test_disk_io_counters_kernel_2_6_full_mocked(self):
# Tests /proc/diskstats parsing format for 2.6 kernels,
Expand All @@ -1020,16 +1022,18 @@ def test_disk_io_counters_kernel_2_6_full_mocked(self):
with mock_open_content(
'/proc/diskstats',
" 3 0 hda 1 2 3 4 5 6 7 8 9 10 11"):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_merged_count, 2)
self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE)
self.assertEqual(ret.read_time, 4)
self.assertEqual(ret.write_count, 5)
self.assertEqual(ret.write_merged_count, 6)
self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE)
self.assertEqual(ret.write_time, 8)
self.assertEqual(ret.busy_time, 10)
with mock.patch('psutil._pslinux.is_storage_device',
return_value=True):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_merged_count, 2)
self.assertEqual(ret.read_bytes, 3 * SECTOR_SIZE)
self.assertEqual(ret.read_time, 4)
self.assertEqual(ret.write_count, 5)
self.assertEqual(ret.write_merged_count, 6)
self.assertEqual(ret.write_bytes, 7 * SECTOR_SIZE)
self.assertEqual(ret.write_time, 8)
self.assertEqual(ret.busy_time, 10)

def test_disk_io_counters_kernel_2_6_limited_mocked(self):
# Tests /proc/diskstats parsing format for 2.6 kernels,
Expand All @@ -1047,17 +1051,19 @@ def test_disk_io_counters_kernel_2_6_limited_mocked(self):
with mock_open_content(
'/proc/diskstats',
" 3 1 hda 1 2 3 4"):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_bytes, 2 * SECTOR_SIZE)
self.assertEqual(ret.write_count, 3)
self.assertEqual(ret.write_bytes, 4 * SECTOR_SIZE)

self.assertEqual(ret.read_merged_count, 0)
self.assertEqual(ret.read_time, 0)
self.assertEqual(ret.write_merged_count, 0)
self.assertEqual(ret.write_time, 0)
self.assertEqual(ret.busy_time, 0)
with mock.patch('psutil._pslinux.is_storage_device',
return_value=True):
ret = psutil.disk_io_counters(nowrap=False)
self.assertEqual(ret.read_count, 1)
self.assertEqual(ret.read_bytes, 2 * SECTOR_SIZE)
self.assertEqual(ret.write_count, 3)
self.assertEqual(ret.write_bytes, 4 * SECTOR_SIZE)

self.assertEqual(ret.read_merged_count, 0)
self.assertEqual(ret.read_time, 0)
self.assertEqual(ret.write_merged_count, 0)
self.assertEqual(ret.write_time, 0)
self.assertEqual(ret.busy_time, 0)


# =====================================================================
Expand Down

0 comments on commit 4482266

Please sign in to comment.