blob: bf6ad9d145adb61c59837930d5a170e331ff4d12 [file] [log] [blame]
#!/usr/bin/python3
import os, re
from collections import defaultdict
from dynticks_testing_lib import parse_cpulist, get_cmdline_param
def get_irq_nohzfull_intersect(cpulist):
smp_list = defaultdict(set)
for vec in os.listdir("/proc/irq"):
path = "/proc/irq/%s" % vec
if not os.path.isdir(path) or vec == "0":
continue
path = os.path.join(path, "smp_affinity_list")
f_list = open(path, "r")
affinity = f_list.read()
f_list.close()
# Be sure IRQ affinity isn't set for nohz CPUs
cpus = parse_cpulist(affinity)
res = set(cpulist) & set(cpus)
if len(res):
smp_list[frozenset(res)].add(vec)
return smp_list
def get_thread_siblings_list():
thread_siblings_list = {};
cpu_folders = [entry for entry in os.listdir("/sys/devices/system/cpu/") if re.match(r'^cpu\d+$', entry)]
for hw_thread_s in cpu_folders:
hw_thread = hw_thread_s.replace("cpu","")
# take only 1 result, eg:
# /sys/devices/system/cpu/cpu0/topology/thread_siblings_list:0,112
# results in 2 match: for 0 and 112
cpu_present = any(hw_thread in sublist for sublist in thread_siblings_list)
if cpu_present:
continue
path = "/sys/devices/system/cpu/cpu%s/" % hw_thread
path = os.path.join(path, "topology/thread_siblings_list")
s_list = open(path, "r")
hw_threads_list = s_list.read();
s_list.close()
hw_threads = parse_cpulist(hw_threads_list)
thread_siblings_list[hw_thread] = hw_threads
return thread_siblings_list
def is_smt_enabled():
# check whether SMT is enabled
smt_path = "/sys/devices/system/cpu/smt/active"
if not os.path.exists(smt_path):
print("Can't find %s " % smt_path)
smt = int(open(smt_path).read().strip())
if smt:
print("SMT is enabled. On nohz_full with isolated CPU it should be disabled.\n")
return smt
def check_cpu_governor():
governor_path = "/sys/devices/system/cpu/cpu0/cpufreq/scaling_governor"
if os.path.exists(governor_path):
governor = open(governor_path).read().strip()
print("CPU Governor used: %s" % governor)
else:
print("Can't find %s " % governor_path)
def check_irq_affinity(cpulist):
print("nohz_full=%s\n" % cpulist)
print("=== IRQ AFFINITY ON NOHZ_FULL CPUs ===")
smp_list = get_irq_nohzfull_intersect(cpulist)
for cpus, vectors in smp_list.items():
sorted_vectors = ', '.join(map(str, sorted(vectors)))
sorted_cpus = ', '.join(map(str, sorted(cpus)))
print("Wrong IRQ affinity on vectors:", end = " ")
print(sorted_vectors, sep=", ")
print("These CPUs are nohz_full:", end = " ")
print(sorted_cpus, sep=", ")
print()
def check_siblings_thread(cpulist):
print("=== SIBLINGS THREAD <=> NOHZ_FULL ===")
print("The non-isolated core can be a source of noise, disturbing the isolated workload.")
print("If both are isolated, they can interfere with each other.\n");
siblings_list = get_thread_siblings_list()
# none of the siblings should be in cpulist
for hw_thread in siblings_list:
siblings_nohz_intersect = set(siblings_list[hw_thread]) & set(cpulist)
if len(siblings_nohz_intersect):
print("!!!WARN!!! SMT threads should NOT be isolated:", end = " ")
print(siblings_list[hw_thread], sep=", ", end=" ")
print("found:", end=" ")
print(siblings_nohz_intersect, sep=", ")
print()
def err_nohz_isolated(nohz_full, res):
print("Not all the nohz_full CPUs are isolated:")
print("nohz_full=%s\n" % nohz_full)
print("Found:",end=" ")
print(res, sep=", ")
print()
def check_isolcpus_cpuset(cpulist):
print("=== ISOLCPUS / CPUSET AND NOHZ_FULL ===")
isolcpus = get_cmdline_param("isolcpus")
if isolcpus is not None:
print("isolcpus= found...")
isolcpus_list = parse_cpulist(isolcpus)
res = sorted(list(set(isolcpus_list) & set(cpulist)))
if cpulist != res:
err_nohz_isolated(cpulist, res)
else:
print("nohz_full is part of isolcpus. Ok!")
else:
found = False
# Walk cgroup directory tree
cgroup_root = "/sys/fs/cgroup"
for root, dirs, files in os.walk(cgroup_root):
# check if partitions are present
if "cpuset.cpus.partition" in files:
partition_file = os.path.join(root, "cpuset.cpus.partition")
try:
with open(partition_file, "r") as pf:
partition_state = pf.read().strip()
# we're only interested in isolated partition here
if partition_state.startswith("isolated") is False:
continue
# if "isolated invalid" is present, nohz_full is not
# considered valid either
is_invalid = partition_state.startswith("isolated invalid")
found = True
cpus_file = os.path.join(root, "cpuset.cpus")
if os.path.exists(cpus_file):
with open(cpus_file, 'r') as f:
cpuset_content = f.read().strip()
cgroup_cpus = parse_cpulist(cpuset_content)
else:
cgroup_cpus = []
res = sorted(list(set(cgroup_cpus) & set(cpulist)))
match = ""
if is_invalid:
match = "Invalid partition configuration, check State above"
elif cpulist != res:
match = "Mismatch, nohz_full IS NOT part of cpuset"
else:
match = "nohz_full is part of cpuset. Ok!"
print(f"Found Partition: {root}")
print(f" State : {partition_state}")
print(f" cpuset.cpus : {sorted(cgroup_cpus)}")
print(f" nohz_full : {sorted(cpulist)}")
print(f" Match : {match}")
print("-"*60)
except IOError as e:
continue;
if not found:
print(f"Error: nohz_full specified {cpulist} but no isolated partitions (isolcpus | cpusets) found!")
def check_configs(cpulist):
smt = is_smt_enabled()
check_cpu_governor()
if cpulist:
check_irq_affinity(cpulist)
if smt:
check_siblings_thread(cpulist)
check_isolcpus_cpuset(cpulist)