Skip to content

Commit

Permalink
plugin_scheduler: Adjust error logging in _set_affinity
Browse files Browse the repository at this point in the history
Do not report an error if a process is defunct even if it
is not bound to specific CPUs: failing to change its affinity
does not have any negative effects.

Refactor the helper function _affinity_changeable to
_ignore_set_affinity_error and make it return True/False
depending on whether the failed affinity change can be
ignored (i.e., not reported as an error).

Do not check for vanished processes twice, the later
check is sufficient.

Resolves: RHEL-46560
  • Loading branch information
zacikpa committed Jul 12, 2024
1 parent 5d5dbfc commit 093a2bf
Showing 1 changed file with 21 additions and 35 deletions.
56 changes: 21 additions & 35 deletions tuned/plugins/plugin_scheduler.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,45 +639,38 @@ def _set_rt(self, pid, sched, prio):
log.error("Failed to set scheduling parameters of PID %d: %s"
% (pid, e))

# process is a procfs.process object
# process_stat is a procfs.pidstat object
# Raises OSError, IOError
def _is_kthread(self, process):
return process["stat"]["flags"] & procfs.pidstat.PF_KTHREAD != 0

# Return codes:
# 0 - Affinity is fixed
# 1 - Affinity is changeable
# -1 - Task vanished
# -2 - Error
def _affinity_changeable(self, pid):
def _is_kthread(self, process_stat):
return process_stat["flags"] & procfs.pidstat.PF_KTHREAD != 0

# Returns True if we can ignore a failed affinity change of
# a process with the given PID and therefore not report it as an error.
def _ignore_set_affinity_error(self, pid):
try:
process = procfs.process(pid)
if process["stat"].is_bound_to_cpu():
if process["stat"]["state"] == "Z":
log.debug("Affinity of zombie task with PID %d cannot be changed, the task's affinity mask is fixed."
% pid)
elif self._is_kthread(process):
process_stat = procfs.pidstat(pid)
if process_stat["state"] == "Z":
log.debug("Affinity of zombie task with PID %d could not be changed."
% pid)
return True
if process_stat.is_bound_to_cpu():
if self._is_kthread(process_stat):
log.debug("Affinity of kernel thread with PID %d cannot be changed, the task's affinity mask is fixed."
% pid)
else:
log.warning("Affinity of task with PID %d cannot be changed, the task's affinity mask is fixed."
% pid)
return 0
else:
return 1
return True
except (OSError, IOError) as e:
if e.errno == errno.ENOENT or e.errno == errno.ESRCH:
log.debug("Failed to get task info for PID %d, the task vanished."
% pid)
return -1
else:
log.error("Failed to get task info for PID %d: %s"
% (pid, e))
return -2
return True
except (AttributeError, KeyError) as e:
log.error("Failed to get task info for PID %d: %s"
% (pid, e))
return -2
finally:
return False

Check warning

Code scanning / CodeQL

'break' or 'return' statement in finally Warning

'return' in a finally block will swallow any exceptions raised.

def _store_orig_process_rt(self, pid, scheduler, priority):
try:
Expand Down Expand Up @@ -1174,19 +1167,12 @@ def _set_affinity(self, pid, affinity):
log.debug("Setting CPU affinity of PID %d to '%s'." % (pid, affinity))
try:
self._scheduler_utils.set_affinity(pid, affinity)
return True
# Workaround for old python-schedutils (pre-0.4) which
# incorrectly raised SystemError instead of OSError
except (SystemError, OSError) as e:
if hasattr(e, "errno") and e.errno == errno.ESRCH:
log.debug("Failed to set affinity of PID %d, the task vanished."
% pid)
else:
res = self._affinity_changeable(pid)
if res == 1 or res == -2:
log.error("Failed to set affinity of PID %d to '%s': %s"
% (pid, affinity, e))
return False
if not self._ignore_set_affinity_error(pid):
log.error("Failed to set affinity of PID %d to '%s': %s"
% (pid, affinity, e))

# returns intersection of affinity1 with affinity2, if intersection is empty it returns affinity3
def _get_intersect_affinity(self, affinity1, affinity2, affinity3):
Expand Down

0 comments on commit 093a2bf

Please sign in to comment.