Rebase to python-linux-procfs 0.7.2
Resolves: RHEL-8987 Signed-off-by: John Kacur <jkacur@redhat.com>
This commit is contained in:
parent
64fd060bac
commit
69c9d7a61e
1
.gitignore
vendored
1
.gitignore
vendored
@ -10,3 +10,4 @@ python-linux-procfs-0.4.4.tar.bz2
|
||||
/python-linux-procfs-0.6.3.tar.xz
|
||||
/python-linux-procfs-0.7.0.tar.xz
|
||||
/python-linux-procfs-0.7.1.tar.xz
|
||||
/python-linux-procfs-0.7.2.tar.xz
|
||||
|
@ -1,68 +0,0 @@
|
||||
From a752e7995bfdabb08b5bb6bcd437b9a5d2e53a7a Mon Sep 17 00:00:00 2001
|
||||
From: John Kacur <jkacur@redhat.com>
|
||||
Date: Thu, 9 Dec 2021 10:11:07 -0500
|
||||
Subject: [PATCH 2/2] python-linux-procfs: Fix UnicodeDecodeError
|
||||
|
||||
Commit 7570fc0d6082 meant to solve the UnicodeDecodeError
|
||||
|
||||
Instead it actually increased the problem by reading lines as bytes
|
||||
and decoding them.
|
||||
|
||||
The original problem is hard to trigger and doesn't trigger consistently
|
||||
with reproducers. In addition there seems to be a difference in how this
|
||||
is handled between python-3.6 to python-3.9
|
||||
|
||||
For now, we should return the code to reading as utf-8 (the default)
|
||||
since that handles more cases than the current code.
|
||||
|
||||
We can catch the UnicodeDecodeError and ignore it for now. It is not
|
||||
ideal because we are not handling some pids that trigger the error.
|
||||
|
||||
This patch also includes a fix for a FileNotFoundError which can occur if
|
||||
a pid exits and disappears before we try to read it in the /proc file
|
||||
system.
|
||||
|
||||
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||
---
|
||||
procfs/procfs.py | 18 ++++++++++++++----
|
||||
1 file changed, 14 insertions(+), 4 deletions(-)
|
||||
|
||||
diff --git a/procfs/procfs.py b/procfs/procfs.py
|
||||
index a78bac5376e3..de55dfc1aef4 100755
|
||||
--- a/procfs/procfs.py
|
||||
+++ b/procfs/procfs.py
|
||||
@@ -44,7 +44,11 @@ def process_cmdline(pid_info):
|
||||
if pid_info["cmdline"]:
|
||||
return reduce(lambda a, b: a + " %s" % b, pid_info["cmdline"]).strip()
|
||||
|
||||
- return pid_info["stat"]["comm"]
|
||||
+ try:
|
||||
+ """ If a pid disappears before we query it, return None """
|
||||
+ return pid_info["stat"]["comm"]
|
||||
+ except:
|
||||
+ return None
|
||||
|
||||
|
||||
class pidstat:
|
||||
@@ -374,9 +378,15 @@ class process:
|
||||
return hasattr(self, attr)
|
||||
|
||||
def load_cmdline(self):
|
||||
- with open("/proc/%d/cmdline" % self.pid, mode='rb') as f:
|
||||
- cmdline = f.readline().decode(encoding='unicode_escape')
|
||||
- self.cmdline = cmdline.strip().split('\0')[:-1]
|
||||
+ try:
|
||||
+ with open("/proc/%d/cmdline" % self.pid) as f:
|
||||
+ self.cmdline = f.readline().strip().split('\0')[:-1]
|
||||
+ except FileNotFoundError:
|
||||
+ """ This can happen when a pid disappears """
|
||||
+ self.cmdline = None
|
||||
+ except UnicodeDecodeError:
|
||||
+ """ TODO - this shouldn't happen, needs to be investigated """
|
||||
+ self.cmdline = None
|
||||
|
||||
def load_threads(self):
|
||||
self.threads = pidstats("/proc/%d/task/" % self.pid)
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,33 +0,0 @@
|
||||
From 7570fc0d6082cb476c32233c2904214dd57737a8 Mon Sep 17 00:00:00 2001
|
||||
From: John Kacur <jkacur@redhat.com>
|
||||
Date: Fri, 19 Nov 2021 16:03:22 -0500
|
||||
Subject: [PATCH] python-linux-procfs: Fix traceback with non-utf8 chars in the
|
||||
/proc/PID/cmdline
|
||||
|
||||
Fix traceback if there are non-utf8 characters in the /proc/PID/cmdline
|
||||
|
||||
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||
---
|
||||
procfs/procfs.py | 6 +++---
|
||||
1 file changed, 3 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/procfs/procfs.py b/procfs/procfs.py
|
||||
index 3b7474cccb01..408b2bcd0a31 100755
|
||||
--- a/procfs/procfs.py
|
||||
+++ b/procfs/procfs.py
|
||||
@@ -357,9 +357,9 @@ class process:
|
||||
return hasattr(self, attr)
|
||||
|
||||
def load_cmdline(self):
|
||||
- f = open("/proc/%d/cmdline" % self.pid)
|
||||
- self.cmdline = f.readline().strip().split('\0')[:-1]
|
||||
- f.close()
|
||||
+ with open("/proc/%d/cmdline" % self.pid, mode='rb') as f:
|
||||
+ cmdline = f.readline().decode(encoding='unicode_escape')
|
||||
+ self.cmdline = cmdline.strip().split('\0')[:-1]
|
||||
|
||||
def load_threads(self):
|
||||
self.threads = pidstats("/proc/%d/task/" % self.pid)
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,68 +0,0 @@
|
||||
From b7ea06b21456d465f2d9d11358fb803eb277357f Mon Sep 17 00:00:00 2001
|
||||
From: John Kacur <jkacur@redhat.com>
|
||||
Date: Tue, 23 Nov 2021 09:58:58 -0500
|
||||
Subject: [PATCH 1/3] python-linux-procfs: Propagate error to user if a pid is
|
||||
completed
|
||||
|
||||
If a pid is completed and disappears a FileNotFoundError will occur
|
||||
because /proc/pid/stat will disappear too.
|
||||
|
||||
It is not possible to check for the file first because it could still
|
||||
disappear between the time of the check and the time of use.
|
||||
|
||||
Propagate this error to the user.
|
||||
The user should handle this with a try, except clause and ignore it if
|
||||
an exception occurs.
|
||||
|
||||
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||
---
|
||||
procfs/procfs.py | 19 ++++++++++++++++---
|
||||
1 file changed, 16 insertions(+), 3 deletions(-)
|
||||
|
||||
diff --git a/procfs/procfs.py b/procfs/procfs.py
|
||||
index 408b2bcd0a31..a0e9977214fe 100755
|
||||
--- a/procfs/procfs.py
|
||||
+++ b/procfs/procfs.py
|
||||
@@ -130,7 +130,12 @@ class pidstat:
|
||||
|
||||
def __init__(self, pid, basedir="/proc"):
|
||||
self.pid = pid
|
||||
- self.load(basedir)
|
||||
+ try:
|
||||
+ self.load(basedir)
|
||||
+ except FileNotFoundError:
|
||||
+ # The file representing the pid has disappeared
|
||||
+ # propagate the error to the user to handle
|
||||
+ raise
|
||||
|
||||
def __getitem__(self, fieldname):
|
||||
return self.fields[fieldname]
|
||||
@@ -151,7 +156,11 @@ class pidstat:
|
||||
return fieldname in self.fields
|
||||
|
||||
def load(self, basedir="/proc"):
|
||||
- f = open("%s/%d/stat" % (basedir, self.pid))
|
||||
+ try:
|
||||
+ f = open("%s/%d/stat" % (basedir, self.pid))
|
||||
+ except FileNotFoundError:
|
||||
+ # The pid has disappeared, propagate the error
|
||||
+ raise
|
||||
fields = f.readline().strip().split(') ')
|
||||
f.close()
|
||||
fields = fields[0].split(' (') + fields[1].split()
|
||||
@@ -338,7 +347,11 @@ class process:
|
||||
else:
|
||||
sclass = pidstatus
|
||||
|
||||
- setattr(self, attr, sclass(self.pid, self.basedir))
|
||||
+ try:
|
||||
+ setattr(self, attr, sclass(self.pid, self.basedir))
|
||||
+ except FileNotFoundError:
|
||||
+ # The pid has disappeared, progate the error
|
||||
+ raise
|
||||
elif attr == "cmdline":
|
||||
self.load_cmdline()
|
||||
elif attr == "threads":
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,502 +0,0 @@
|
||||
From ce8cacdd515bf7270daef62648d5f994f111cded Mon Sep 17 00:00:00 2001
|
||||
From: John Kacur <jkacur@redhat.com>
|
||||
Date: Thu, 2 Dec 2021 16:52:10 -0500
|
||||
Subject: [PATCH 1/2] python-linux-procfs: Various clean-ups
|
||||
|
||||
- Replace f=open with 'with' (context managers), except in try-except blocks
|
||||
- Reformat lines that are too long, especially in comments
|
||||
- Use min() instead of if construct
|
||||
- Use bool instead of complicated and True or False constructs
|
||||
- Reorder imports
|
||||
|
||||
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||
---
|
||||
procfs/procfs.py | 292 +++++++++++++++++++++++------------------------
|
||||
1 file changed, 142 insertions(+), 150 deletions(-)
|
||||
|
||||
diff --git a/procfs/procfs.py b/procfs/procfs.py
|
||||
index a0e9977214fe..a78bac5376e3 100755
|
||||
--- a/procfs/procfs.py
|
||||
+++ b/procfs/procfs.py
|
||||
@@ -19,10 +19,10 @@
|
||||
#
|
||||
|
||||
import os
|
||||
-import time
|
||||
-from functools import reduce
|
||||
import platform
|
||||
import re
|
||||
+import time
|
||||
+from functools import reduce
|
||||
from six.moves import range
|
||||
from procfs.utilist import bitmasklist
|
||||
|
||||
@@ -37,8 +37,9 @@ def is_s390():
|
||||
|
||||
def process_cmdline(pid_info):
|
||||
"""
|
||||
- Returns the process command line, if available in the given `process' class, if
|
||||
- not available, falls back to using the comm (short process name) in its pidstat key.
|
||||
+ Returns the process command line, if available in the given `process' class,
|
||||
+ if not available, falls back to using the comm (short process name) in its
|
||||
+ pidstat key.
|
||||
"""
|
||||
if pid_info["cmdline"]:
|
||||
return reduce(lambda a, b: a + " %s" % b, pid_info["cmdline"]).strip()
|
||||
@@ -47,10 +48,12 @@ def process_cmdline(pid_info):
|
||||
|
||||
|
||||
class pidstat:
|
||||
- """Provides a dictionary to access the fields in the per process /proc/PID/stat
|
||||
- files.
|
||||
+ """
|
||||
+ Provides a dictionary to access the fields in the
|
||||
+ per process /proc/PID/stat files.
|
||||
|
||||
- One can obtain the available fields asking for the keys of the dictionary, e.g.:
|
||||
+ One can obtain the available fields by asking for the keys of the
|
||||
+ dictionary, e.g.:
|
||||
|
||||
>>> p = procfs.pidstat(1)
|
||||
>>> print p.keys()
|
||||
@@ -182,8 +185,7 @@ class pidstat:
|
||||
Returns true if this process has a fixed smp affinity mask,
|
||||
not allowing it to be moved to a different set of CPUs.
|
||||
"""
|
||||
- return self.fields["flags"] & self.PF_THREAD_BOUND and \
|
||||
- True or False
|
||||
+ return bool(self.fields["flags"] & self.PF_THREAD_BOUND)
|
||||
|
||||
def process_flags(self):
|
||||
"""
|
||||
@@ -193,33 +195,34 @@ class pidstat:
|
||||
|
||||
As of v4.2-rc7 these include (from include/linux/sched.h comments):
|
||||
|
||||
- PF_EXITING Getting shut down
|
||||
- PF_EXITPIDONE Pi exit done on shut down
|
||||
+ PF_EXITING Getting shut down
|
||||
+ PF_EXITPIDONE Pi exit done on shut down
|
||||
PF_VCPU I'm a virtual CPU
|
||||
- PF_WQ_WORKER I'm a workqueue worker
|
||||
- PF_FORKNOEXEC Forked but didn't exec
|
||||
- PF_MCE_PROCESS Process policy on mce errors
|
||||
- PF_SUPERPRIV Used super-user privileges
|
||||
+ PF_WQ_WORKER I'm a workqueue worker
|
||||
+ PF_FORKNOEXEC Forked but didn't exec
|
||||
+ PF_MCE_PROCESS Process policy on mce errors
|
||||
+ PF_SUPERPRIV Used super-user privileges
|
||||
PF_DUMPCORE Dumped core
|
||||
PF_SIGNALED Killed by a signal
|
||||
PF_MEMALLOC Allocating memory
|
||||
- PF_NPROC_EXCEEDED Set_user noticed that RLIMIT_NPROC was exceeded
|
||||
- PF_USED_MATH If unset the fpu must be initialized before use
|
||||
- PF_USED_ASYNC Used async_schedule*(), used by module init
|
||||
+ PF_NPROC_EXCEEDED Set_user noticed that RLIMIT_NPROC was exceeded
|
||||
+ PF_USED_MATH If unset the fpu must be initialized before use
|
||||
+ PF_USED_ASYNC Used async_schedule*(), used by module init
|
||||
PF_NOFREEZE This thread should not be frozen
|
||||
- PF_FROZEN Frozen for system suspend
|
||||
- PF_FSTRANS Inside a filesystem transaction
|
||||
- PF_KSWAPD I am kswapd
|
||||
+ PF_FROZEN Frozen for system suspend
|
||||
+ PF_FSTRANS Inside a filesystem transaction
|
||||
+ PF_KSWAPD I am kswapd
|
||||
PF_MEMALLOC_NOIO Allocating memory without IO involved
|
||||
PF_LESS_THROTTLE Throttle me less: I clean memory
|
||||
- PF_KTHREAD I am a kernel thread
|
||||
+ PF_KTHREAD I am a kernel thread
|
||||
PF_RANDOMIZE Randomize virtual address space
|
||||
PF_SWAPWRITE Allowed to write to swap
|
||||
PF_NO_SETAFFINITY Userland is not allowed to meddle with cpus_allowed
|
||||
PF_MCE_EARLY Early kill for mce process policy
|
||||
- PF_MUTEX_TESTER Thread belongs to the rt mutex tester
|
||||
- PF_FREEZER_SKIP Freezer should not count it as freezable
|
||||
- PF_SUSPEND_TASK This thread called freeze_processes and should not be frozen
|
||||
+ PF_MUTEX_TESTER Thread belongs to the rt mutex tester
|
||||
+ PF_FREEZER_SKIP Freezer should not count it as freezable
|
||||
+ PF_SUSPEND_TASK This thread called freeze_processes and
|
||||
+ should not be frozen
|
||||
|
||||
"""
|
||||
sflags = []
|
||||
@@ -236,8 +239,8 @@ class pidstat:
|
||||
def cannot_set_affinity(self, pid):
|
||||
PF_NO_SETAFFINITY = 0x04000000
|
||||
try:
|
||||
- return int(self.processes[pid]["stat"]["flags"]) & \
|
||||
- PF_NO_SETAFFINITY and True or False
|
||||
+ return bool(int(self.processes[pid]["stat"]["flags"]) &
|
||||
+ PF_NO_SETAFFINITY)
|
||||
except:
|
||||
return True
|
||||
|
||||
@@ -245,19 +248,21 @@ def cannot_set_affinity(self, pid):
|
||||
def cannot_set_thread_affinity(self, pid, tid):
|
||||
PF_NO_SETAFFINITY = 0x04000000
|
||||
try:
|
||||
- return int(self.processes[pid].threads[tid]["stat"]["flags"]) & \
|
||||
- PF_NO_SETAFFINITY and True or False
|
||||
+ return bool(int(self.processes[pid].threads[tid]["stat"]["flags"]) &
|
||||
+ PF_NO_SETAFFINITY)
|
||||
except:
|
||||
return True
|
||||
|
||||
|
||||
class pidstatus:
|
||||
"""
|
||||
- Provides a dictionary to access the fields in the per process /proc/PID/status
|
||||
- files. This provides additional information about processes and threads to what
|
||||
- can be obtained with the procfs.pidstat() class.
|
||||
+ Provides a dictionary to access the fields
|
||||
+ in the per process /proc/PID/status files.
|
||||
+ This provides additional information about processes and threads to
|
||||
+ what can be obtained with the procfs.pidstat() class.
|
||||
|
||||
- One can obtain the available fields asking for the keys of the dictionary, e.g.:
|
||||
+ One can obtain the available fields by asking for the keys of the
|
||||
+ dictionary, e.g.:
|
||||
|
||||
>>> import procfs
|
||||
>>> p = procfs.pidstatus(1)
|
||||
@@ -312,19 +317,18 @@ class pidstatus:
|
||||
return fieldname in self.fields
|
||||
|
||||
def load(self, basedir="/proc"):
|
||||
- f = open("%s/%d/status" % (basedir, self.pid))
|
||||
self.fields = {}
|
||||
- for line in f.readlines():
|
||||
- fields = line.split(":")
|
||||
- if len(fields) != 2:
|
||||
- continue
|
||||
- name = fields[0]
|
||||
- value = fields[1].strip()
|
||||
- try:
|
||||
- self.fields[name] = int(value)
|
||||
- except:
|
||||
- self.fields[name] = value
|
||||
- f.close()
|
||||
+ with open("%s/%d/status" % (basedir, self.pid)) as f:
|
||||
+ for line in f.readlines():
|
||||
+ fields = line.split(":")
|
||||
+ if len(fields) != 2:
|
||||
+ continue
|
||||
+ name = fields[0]
|
||||
+ value = fields[1].strip()
|
||||
+ try:
|
||||
+ self.fields[name] = int(value)
|
||||
+ except:
|
||||
+ self.fields[name] = value
|
||||
|
||||
|
||||
class process:
|
||||
@@ -380,14 +384,13 @@ class process:
|
||||
del self.threads[self.pid]
|
||||
|
||||
def load_cgroups(self):
|
||||
- f = open("/proc/%d/cgroup" % self.pid)
|
||||
self.cgroups = ""
|
||||
- for line in reversed(f.readlines()):
|
||||
- if len(self.cgroups) != 0:
|
||||
- self.cgroups = self.cgroups + "," + line[:-1]
|
||||
- else:
|
||||
- self.cgroups = line[:-1]
|
||||
- f.close()
|
||||
+ with open("/proc/%d/cgroup" % self.pid) as f:
|
||||
+ for line in reversed(f.readlines()):
|
||||
+ if len(self.cgroups) != 0:
|
||||
+ self.cgroups = self.cgroups + "," + line[:-1]
|
||||
+ else:
|
||||
+ self.cgroups = line[:-1]
|
||||
|
||||
def load_environ(self):
|
||||
"""
|
||||
@@ -416,12 +419,11 @@ class process:
|
||||
>>>
|
||||
"""
|
||||
self.environ = {}
|
||||
- f = open("/proc/%d/environ" % self.pid)
|
||||
- for x in f.readline().split('\0'):
|
||||
- if len(x) > 0:
|
||||
- y = x.split('=')
|
||||
- self.environ[y[0]] = y[1]
|
||||
- f.close()
|
||||
+ with open("/proc/%d/environ" % self.pid) as f:
|
||||
+ for x in f.readline().split('\0'):
|
||||
+ if len(x) > 0:
|
||||
+ y = x.split('=')
|
||||
+ self.environ[y[0]] = y[1]
|
||||
|
||||
|
||||
class pidstats:
|
||||
@@ -465,18 +467,18 @@ class pidstats:
|
||||
|
||||
def reload(self):
|
||||
"""
|
||||
- This operation will throw away the current dictionary contents, if any, and
|
||||
- read all the pid files from /proc/, instantiating a 'process' instance for
|
||||
- each of them.
|
||||
+ This operation will throw away the current dictionary contents,
|
||||
+ if any, and read all the pid files from /proc/, instantiating a
|
||||
+ 'process' instance for each of them.
|
||||
|
||||
- This is a high overhead operation, and should be avoided if the perf python
|
||||
- binding can be used to detect when new threads appear and existing ones
|
||||
- terminate.
|
||||
+ This is a high overhead operation, and should be avoided if the
|
||||
+ perf python binding can be used to detect when new threads appear
|
||||
+ and existing ones terminate.
|
||||
|
||||
In RHEL it is found in the python-perf rpm package.
|
||||
|
||||
- More information about the perf facilities can be found in the 'perf_event_open'
|
||||
- man page.
|
||||
+ More information about the perf facilities can be found in the
|
||||
+ 'perf_event_open' man page.
|
||||
"""
|
||||
del self.processes
|
||||
self.processes = {}
|
||||
@@ -643,24 +645,21 @@ class interrupts:
|
||||
def reload(self):
|
||||
del self.interrupts
|
||||
self.interrupts = {}
|
||||
- f = open("/proc/interrupts")
|
||||
-
|
||||
- for line in f.readlines():
|
||||
- line = line.strip()
|
||||
- fields = line.split()
|
||||
- if fields[0][:3] == "CPU":
|
||||
- self.nr_cpus = len(fields)
|
||||
- continue
|
||||
- irq = fields[0].strip(":")
|
||||
- self.interrupts[irq] = {}
|
||||
- self.interrupts[irq] = self.parse_entry(fields[1:], line)
|
||||
- try:
|
||||
- nirq = int(irq)
|
||||
- except:
|
||||
- continue
|
||||
- self.interrupts[irq]["affinity"] = self.parse_affinity(nirq)
|
||||
-
|
||||
- f.close()
|
||||
+ with open("/proc/interrupts") as f:
|
||||
+ for line in f.readlines():
|
||||
+ line = line.strip()
|
||||
+ fields = line.split()
|
||||
+ if fields[0][:3] == "CPU":
|
||||
+ self.nr_cpus = len(fields)
|
||||
+ continue
|
||||
+ irq = fields[0].strip(":")
|
||||
+ self.interrupts[irq] = {}
|
||||
+ self.interrupts[irq] = self.parse_entry(fields[1:], line)
|
||||
+ try:
|
||||
+ nirq = int(irq)
|
||||
+ except:
|
||||
+ continue
|
||||
+ self.interrupts[irq]["affinity"] = self.parse_affinity(nirq)
|
||||
|
||||
def parse_entry(self, fields, line):
|
||||
dict = {}
|
||||
@@ -681,9 +680,8 @@ class interrupts:
|
||||
|
||||
def parse_affinity(self, irq):
|
||||
try:
|
||||
- f = open("/proc/irq/%s/smp_affinity" % irq)
|
||||
- line = f.readline()
|
||||
- f.close()
|
||||
+ with open("/proc/irq/%s/smp_affinity" % irq) as f:
|
||||
+ line = f.readline()
|
||||
return bitmasklist(line, self.nr_cpus)
|
||||
except IOError:
|
||||
return [0, ]
|
||||
@@ -741,11 +739,11 @@ class cmdline:
|
||||
"""
|
||||
Parses the kernel command line (/proc/cmdline), turning it into a dictionary."
|
||||
|
||||
- Useful to figure out if some kernel boolean knob has been turned on, as well
|
||||
- as to find the value associated to other kernel knobs.
|
||||
+ Useful to figure out if some kernel boolean knob has been turned on,
|
||||
+ as well as to find the value associated to other kernel knobs.
|
||||
|
||||
- It can also be used to find out about parameters passed to the init process,
|
||||
- such as 'BOOT_IMAGE', etc.
|
||||
+ It can also be used to find out about parameters passed to the
|
||||
+ init process, such as 'BOOT_IMAGE', etc.
|
||||
|
||||
E.g.:
|
||||
>>> import procfs
|
||||
@@ -762,15 +760,13 @@ class cmdline:
|
||||
self.parse()
|
||||
|
||||
def parse(self):
|
||||
- f = open("/proc/cmdline")
|
||||
- for option in f.readline().strip().split():
|
||||
- fields = option.split("=")
|
||||
- if len(fields) == 1:
|
||||
- self.options[fields[0]] = True
|
||||
- else:
|
||||
- self.options[fields[0]] = fields[1]
|
||||
-
|
||||
- f.close()
|
||||
+ with open("/proc/cmdline") as f:
|
||||
+ for option in f.readline().strip().split():
|
||||
+ fields = option.split("=")
|
||||
+ if len(fields) == 1:
|
||||
+ self.options[fields[0]] = True
|
||||
+ else:
|
||||
+ self.options[fields[0]] = fields[1]
|
||||
|
||||
def __getitem__(self, key):
|
||||
return self.options[key]
|
||||
@@ -790,9 +786,9 @@ class cpuinfo:
|
||||
Dictionary with information about CPUs in the system.
|
||||
|
||||
Please refer to 'man procfs(5)' for further information about the
|
||||
- '/proc/cpuinfo' file, that is the source of the information provided by this
|
||||
- class. The 'man lscpu(1)' also has information about a program that uses
|
||||
- the '/proc/cpuinfo' file.
|
||||
+ '/proc/cpuinfo' file, that is the source of the information provided
|
||||
+ by this class. The 'man lscpu(1)' also has information about a program that
|
||||
+ uses the '/proc/cpuinfo' file.
|
||||
|
||||
Using this class one can obtain the number of CPUs in a system:
|
||||
|
||||
@@ -801,14 +797,14 @@ class cpuinfo:
|
||||
4
|
||||
|
||||
It is also possible to figure out aspects of the CPU topology, such as
|
||||
- how many CPU physical sockets exists, i.e. groups of CPUs sharing components
|
||||
- such as CPU memory caches:
|
||||
+ how many CPU physical sockets exists, i.e. groups of CPUs sharing
|
||||
+ components such as CPU memory caches:
|
||||
|
||||
>>> print len(cpus.sockets)
|
||||
1
|
||||
|
||||
- Additionally dictionary with information common to all CPUs in the system is
|
||||
- available:
|
||||
+ Additionally dictionary with information common to all CPUs in the system
|
||||
+ is available:
|
||||
|
||||
>>> print cpus["model name"]
|
||||
Intel(R) Core(TM) i7-3667U CPU @ 2.00GHz
|
||||
@@ -836,28 +832,26 @@ class cpuinfo:
|
||||
return self.tags
|
||||
|
||||
def parse(self, filename):
|
||||
- f = open(filename)
|
||||
- for line in f.readlines():
|
||||
- line = line.strip()
|
||||
- if not line:
|
||||
- continue
|
||||
- fields = line.split(":")
|
||||
- tagname = fields[0].strip().lower()
|
||||
- if tagname == "processor":
|
||||
- self.nr_cpus += 1
|
||||
- continue
|
||||
- if is_s390() and tagname == "cpu number":
|
||||
- self.nr_cpus += 1
|
||||
- continue
|
||||
- if tagname == "core id":
|
||||
- continue
|
||||
- self.tags[tagname] = fields[1].strip()
|
||||
- if tagname == "physical id":
|
||||
- socket_id = self.tags[tagname]
|
||||
- if socket_id not in self.sockets:
|
||||
- self.sockets.append(socket_id)
|
||||
-
|
||||
- f.close()
|
||||
+ with open(filename) as f:
|
||||
+ for line in f.readlines():
|
||||
+ line = line.strip()
|
||||
+ if not line:
|
||||
+ continue
|
||||
+ fields = line.split(":")
|
||||
+ tagname = fields[0].strip().lower()
|
||||
+ if tagname == "processor":
|
||||
+ self.nr_cpus += 1
|
||||
+ continue
|
||||
+ if is_s390() and tagname == "cpu number":
|
||||
+ self.nr_cpus += 1
|
||||
+ continue
|
||||
+ if tagname == "core id":
|
||||
+ continue
|
||||
+ self.tags[tagname] = fields[1].strip()
|
||||
+ if tagname == "physical id":
|
||||
+ socket_id = self.tags[tagname]
|
||||
+ if socket_id not in self.sockets:
|
||||
+ self.sockets.append(socket_id)
|
||||
self.nr_sockets = self.sockets and len(self.sockets) or \
|
||||
(self.nr_cpus /
|
||||
("siblings" in self.tags and int(self.tags["siblings"]) or 1))
|
||||
@@ -870,7 +864,8 @@ class smaps_lib:
|
||||
Representation of an mmap in place for a process. Can be used to figure
|
||||
out which processes have an library mapped, etc.
|
||||
|
||||
- The 'perm' member can be used to figure out executable mmaps, i.e. libraries.
|
||||
+ The 'perm' member can be used to figure out executable mmaps,
|
||||
+ i.e. libraries.
|
||||
|
||||
The 'vm_start' and 'vm_end' in turn can be used when trying to resolve
|
||||
processor instruction pointer addresses to a symbol name in a library.
|
||||
@@ -967,13 +962,12 @@ class smaps:
|
||||
return self.entries[index]
|
||||
|
||||
def reload(self):
|
||||
- f = open("/proc/%d/smaps" % self.pid)
|
||||
line = None
|
||||
- while True:
|
||||
- line = self.parse_entry(f, line)
|
||||
- if not line:
|
||||
- break
|
||||
- f.close()
|
||||
+ with("/proc/%d/smaps" % self.pid) as f:
|
||||
+ while True:
|
||||
+ line = self.parse_entry(f, line)
|
||||
+ if not line:
|
||||
+ break
|
||||
self.nr_entries = len(self.entries)
|
||||
|
||||
def find_by_name_fragment(self, fragment):
|
||||
@@ -1055,18 +1049,17 @@ class cpusstats:
|
||||
def reload(self):
|
||||
last_entries = self.entries
|
||||
self.entries = {}
|
||||
- f = open(self.filename)
|
||||
- for line in f.readlines():
|
||||
- fields = line.strip().split()
|
||||
- if fields[0][:3].lower() != "cpu":
|
||||
- continue
|
||||
- c = cpustat(fields)
|
||||
- if c.name == "cpu":
|
||||
- idx = 0
|
||||
- else:
|
||||
- idx = int(c.name[3:]) + 1
|
||||
- self.entries[idx] = c
|
||||
- f.close()
|
||||
+ with open(self.filename) as f:
|
||||
+ for line in f.readlines():
|
||||
+ fields = line.strip().split()
|
||||
+ if fields[0][:3].lower() != "cpu":
|
||||
+ continue
|
||||
+ c = cpustat(fields)
|
||||
+ if c.name == "cpu":
|
||||
+ idx = 0
|
||||
+ else:
|
||||
+ idx = int(c.name[3:]) + 1
|
||||
+ self.entries[idx] = c
|
||||
last_time = self.time
|
||||
self.time = time.time()
|
||||
if last_entries:
|
||||
@@ -1082,8 +1075,7 @@ class cpusstats:
|
||||
(curr.nice - prev.nice) + \
|
||||
(curr.system - prev.system)
|
||||
curr.usage = (delta / interval_hz) * 100
|
||||
- if curr.usage > 100:
|
||||
- curr.usage = 100
|
||||
+ curr.usage = min(curr.usage, 100)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,50 +0,0 @@
|
||||
From eb984b30e325bbf27844bf9c1f90767504468db5 Mon Sep 17 00:00:00 2001
|
||||
From: John Kacur <jkacur@redhat.com>
|
||||
Date: Tue, 23 Nov 2021 13:01:05 -0500
|
||||
Subject: [PATCH 2/3] python-linux-procfs: pflags: Handle pids that completed
|
||||
|
||||
Sometimes pids disappear when they are completed.
|
||||
|
||||
Programs such as pflags that use procfs must account for that.
|
||||
The solution is to simply recognize this situation, and to continue.
|
||||
|
||||
Signed-off-by: John Kacur <jkacur@redhat.com>
|
||||
---
|
||||
pflags | 15 +++++++++++++--
|
||||
1 file changed, 13 insertions(+), 2 deletions(-)
|
||||
|
||||
diff --git a/pflags b/pflags
|
||||
index 3407b6f51c96..46d396c87c2b 100755
|
||||
--- a/pflags
|
||||
+++ b/pflags
|
||||
@@ -50,14 +50,25 @@ def main(argv):
|
||||
pids = list(ps.processes.keys())
|
||||
|
||||
pids.sort()
|
||||
- len_comms = [len(ps[pid]["stat"]["comm"]) for pid in pids if pid in ps]
|
||||
+ len_comms = []
|
||||
+ for pid in pids:
|
||||
+ if pid in ps:
|
||||
+ try:
|
||||
+ len(ps[pid]["stat"]["comm"])
|
||||
+ except (TypeError, FileNotFoundError):
|
||||
+ continue
|
||||
+ len_comms.append(len(ps[pid]["stat"]["comm"]))
|
||||
+
|
||||
max_comm_len = max(len_comms, default=0)
|
||||
del len_comms
|
||||
|
||||
for pid in pids:
|
||||
if pid not in ps:
|
||||
continue
|
||||
- flags = ps[pid].stat.process_flags()
|
||||
+ try:
|
||||
+ flags = ps[pid].stat.process_flags()
|
||||
+ except AttributeError:
|
||||
+ continue
|
||||
# Remove flags that were superseeded
|
||||
if "PF_THREAD_BOUND" in flags and "PF_NO_SETAFFINITY" in flags:
|
||||
flags.remove("PF_THREAD_BOUND")
|
||||
--
|
||||
2.31.1
|
||||
|
@ -1,5 +1,5 @@
|
||||
Name: python-linux-procfs
|
||||
Version: 0.7.1
|
||||
Version: 0.7.2
|
||||
Release: 1%{?dist}
|
||||
License: GPLv2
|
||||
Summary: Linux /proc abstraction classes
|
||||
@ -45,6 +45,10 @@ rm -rf %{buildroot}
|
||||
%license COPYING
|
||||
|
||||
%changelog
|
||||
* Thu Oct 26 2023 John Kacur <jkacur@redhat.com> - 0.7.2-1
|
||||
Rebase to python-linux-procfs - 0.7.2
|
||||
Resolves: RHEL-8987
|
||||
|
||||
* Fri Nov 18 2022 John Kacur <jkacur@redhat.com> - 0.7.1-1
|
||||
- Rebase to upstream version python-linux-procfs-0.7.1
|
||||
Resolves: rhbz#2121522
|
||||
|
2
sources
2
sources
@ -1 +1 @@
|
||||
SHA512 (python-linux-procfs-0.7.1.tar.xz) = 0b9ff22bcaa5dd696c1ca0a248484171fd2643290ea6f4627afc2eaff4350adc682a1868f3a9cae31e9ba67d5dc2b9d42e184472314a1383e8dd01a73742b731
|
||||
SHA512 (python-linux-procfs-0.7.2.tar.xz) = cf84df7dd4989a1de325792ed713fb74416a906c15447405c6cc35c6ca0415e4812d02ffeb5520d499f7f45ddbd0724dc74ecb82327b49b7186747c69a6f5dcd
|
||||
|
Loading…
Reference in New Issue
Block a user