nohang/psi-monitor
2019-09-21 00:54:22 +09:00

264 lines
5.9 KiB
Python
Executable File

#!/usr/bin/env python3
import os
from time import sleep
from ctypes import CDLL
from argparse import ArgumentParser
###############################################################################
def cgroup2_root():
"""
"""
with open(mounts) as f:
for line in f:
if cgroup2_separator in line:
return line.partition(cgroup2_separator)[0].partition(' ')[2]
def mlockall():
"""
"""
MCL_CURRENT = 1
MCL_FUTURE = 2
MCL_ONFAULT = 4
libc = CDLL('libc.so.6', use_errno=True)
result = libc.mlockall(
MCL_CURRENT | MCL_FUTURE | MCL_ONFAULT
)
if result != 0:
result = libc.mlockall(
MCL_CURRENT | MCL_FUTURE
)
if result != 0:
pass
else:
pass
else:
pass
def psi_file_mem_to_metrics(psi_path):
"""
"""
with open(psi_path) as f:
psi_list = f.readlines()
# print(psi_list)
some_list, full_list = psi_list[0].split(' '), psi_list[1].split(' ')
# print(some_list, full_list)
some_avg10 = some_list[1].split('=')[1]
some_avg60 = some_list[2].split('=')[1]
some_avg300 = some_list[3].split('=')[1]
full_avg10 = full_list[1].split('=')[1]
full_avg60 = full_list[2].split('=')[1]
full_avg300 = full_list[3].split('=')[1]
return (some_avg10, some_avg60, some_avg300,
full_avg10, full_avg60, full_avg300)
def psi_file_cpu_to_metrics(psi_path):
"""
"""
with open(psi_path) as f:
psi_list = f.readlines()
# print(psi_list)
some_list = psi_list[0].split(' ')
# print(some_list, full_list)
some_avg10 = some_list[1].split('=')[1]
some_avg60 = some_list[2].split('=')[1]
some_avg300 = some_list[3].split('=')[1]
return (some_avg10, some_avg60, some_avg300)
def log(*msg):
"""
"""
print(*msg)
if separate_log:
logging.info(*msg)
###############################################################################
parser = ArgumentParser()
parser.add_argument(
'-t',
'--target',
help="""target (cgroup2 or SYTSTEM_WIDE)""",
default='SYSTEM_WIDE',
type=str
)
parser.add_argument(
'-p',
'--period',
help="""period in sec""",
default=2,
type=float
)
parser.add_argument(
'-l',
'--log',
help="""path to log file""",
default=None,
type=str
)
args = parser.parse_args()
target = args.target
period = args.period
log_file = args.log
if log_file is None:
separate_log = False
else:
separate_log = True
import logging
def sleeeep():
try:
sleep(period)
except KeyboardInterrupt:
log('Exit')
exit()
###############################################################################
if separate_log:
logging.basicConfig(
filename=log_file,
level=logging.INFO,
format="%(asctime)s: %(message)s")
###############################################################################
log('target: {}'.format(target))
log('period: {}'.format(period))
if log_file is not None:
log('log file: {}'.format(log_file))
if not os.path.exists('/proc/pressure'):
log('ERROR: /proc/pressure does not exist, PSI is not supported, exit')
exit()
if target == 'SYSTEM_WIDE':
cpu_file = "/proc/pressure/cpu"
memory_file = "/proc/pressure/memory"
io_file = "/proc/pressure/io"
else:
mounts = '/proc/mounts'
cgroup2_separator = ' cgroup2 rw,'
cgroup2_mountpoint = cgroup2_root()
if cgroup2_mountpoint is None:
log('ERROR: unified cgroup hierarchy is not mounted, exit')
exit()
else:
log('cgroup2 mountpoint: {}'.format(cgroup2_mountpoint))
cpu_file = cgroup2_mountpoint + target + "/cpu.pressure"
memory_file = cgroup2_mountpoint + target + "/memory.pressure"
io_file = cgroup2_mountpoint + target + "/io.pressure"
mlockall()
log('Starting psi-monitor, target: {}, period: {}'.format(target, period))
log('----------------------------------------------------------------------'
'--------------------------------------------')
log(' some cpu pressure || some memory pressure | full memory pressure ||'
' some io pressure | full io pressure')
log('---------------------||----------------------|----------------------||'
'----------------------|---------------------')
log(' avg10 avg60 avg300 || avg10 avg60 avg300 | avg10 avg60 avg300 ||'
' avg10 avg60 avg300 | avg10 avg60 avg300')
log('------ ------ ------ || ------ ------ ------ | ------ ------ ------ ||'
' ------ ------ ------ | ------ ------ ------')
while True:
if not os.path.exists(cpu_file):
log('ERROR: cpu pressure file does not exist: {}'.format(cpu_file))
sleeeep()
continue
if not os.path.exists(memory_file):
log('ERROR: memory pressure file does not exist: {}'.format(
memory_file))
sleeeep()
continue
if not os.path.exists(io_file):
log('ERROR: io pressure file does not exist: {}'.format(cpu_file))
sleeeep()
continue
(c_some_avg10, c_some_avg60, c_some_avg300
) = psi_file_cpu_to_metrics(cpu_file)
(m_some_avg10, m_some_avg60, m_some_avg300,
m_full_avg10, m_full_avg60, m_full_avg300
) = psi_file_mem_to_metrics(memory_file)
(i_some_avg10, i_some_avg60, i_some_avg300,
i_full_avg10, i_full_avg60, i_full_avg300
) = psi_file_mem_to_metrics(io_file)
log('{} {} {} || {} {} {} | {} {} {} || {} {} {} | {} {} {}'.format(
c_some_avg10.rjust(6),
c_some_avg60.rjust(6),
c_some_avg300.rjust(6),
m_some_avg10.rjust(6),
m_some_avg60.rjust(6),
m_some_avg300.rjust(6),
m_full_avg10.rjust(6),
m_full_avg60.rjust(6),
m_full_avg300.rjust(6),
i_some_avg10.rjust(6),
i_some_avg60.rjust(6),
i_some_avg300.rjust(6),
i_full_avg10.rjust(6),
i_full_avg60.rjust(6),
i_full_avg300.rjust(6)
))
sleeeep()