def test_memory_maps(self): src = textwrap.dedent(""" import time with open("%s", "w") as f: time.sleep(10) """ % TESTFN) sproc = pyrun(src) self.addCleanup(reap_children) call_until(lambda: os.listdir('.'), "'%s' not in ret" % TESTFN) p = psutil.Process(sproc.pid) time.sleep(.1) maps = p.memory_maps(grouped=False) pmap = sh('pmap -x %s' % p.pid).split('\n') # get rid of header del pmap[0] del pmap[0] while maps and pmap: this = maps.pop(0) other = pmap.pop(0) addr, _, rss, dirty, mode, path = other.split(None, 5) if not path.startswith('[') and not path.endswith(']'): self.assertEqual(path, os.path.basename(this.path)) self.assertEqual(int(rss) * 1024, this.rss) # test only rwx chars, ignore 's' and 'p' self.assertEqual(mode[:3], this.perms[:3])
def test_process_create_time(self): output = sh("ps -o lstart -p %s" % self.pid) start_ps = output.replace('STARTED', '').strip() start_psutil = psutil.Process(self.pid).create_time() start_psutil = time.strftime("%a %b %e %H:%M:%S %Y", time.localtime(start_psutil)) self.assertEqual(start_ps, start_psutil)
def test_virtual_memory(self): out = sh('/usr/bin/svmon -O unit=KB') re_pattern = "memory\s*" for field in ("size inuse free pin virtual available mmode").split(): re_pattern += "(?P<%s>\S+)\s+" % (field,) matchobj = re.search(re_pattern, out) self.assertIsNotNone( matchobj, "svmon command returned unexpected output") KB = 1024 total = int(matchobj.group("size")) * KB available = int(matchobj.group("available")) * KB used = int(matchobj.group("inuse")) * KB free = int(matchobj.group("free")) * KB psutil_result = psutil.virtual_memory() # MEMORY_TOLERANCE from psutil.tests is not enough. For some reason # we're seeing differences of ~1.2 MB. 2 MB is still a good tolerance # when compared to GBs. MEMORY_TOLERANCE = 2 * KB * KB # 2 MB self.assertEqual(psutil_result.total, total) self.assertAlmostEqual( psutil_result.used, used, delta=MEMORY_TOLERANCE) self.assertAlmostEqual( psutil_result.available, available, delta=MEMORY_TOLERANCE) self.assertAlmostEqual( psutil_result.free, free, delta=MEMORY_TOLERANCE)
def test_get_kernel_version(self): if not POSIX: self.assertEqual(get_kernel_version(), tuple()) else: kernel = get_kernel_version() assert kernel, kernel self.assertIn('.'.join(map(str, kernel)), sh("uname -a"))
def test_cpu_stats(self): out = sh('/usr/bin/mpstat -a') re_pattern = "ALL\s*" for field in ("min maj mpcs mpcr dev soft dec ph cs ics bound rq " "push S3pull S3grd S0rd S1rd S2rd S3rd S4rd S5rd " "sysc").split(): re_pattern += "(?P<%s>\S+)\s+" % (field,) matchobj = re.search(re_pattern, out) self.assertIsNotNone( matchobj, "mpstat command returned unexpected output") # numbers are usually in the millions so 1000 is ok for tolerance CPU_STATS_TOLERANCE = 1000 psutil_result = psutil.cpu_stats() self.assertAlmostEqual( psutil_result.ctx_switches, int(matchobj.group("cs")), delta=CPU_STATS_TOLERANCE) self.assertAlmostEqual( psutil_result.syscalls, int(matchobj.group("sysc")), delta=CPU_STATS_TOLERANCE) self.assertAlmostEqual( psutil_result.interrupts, int(matchobj.group("dev")), delta=CPU_STATS_TOLERANCE) self.assertAlmostEqual( psutil_result.soft_interrupts, int(matchobj.group("soft")), delta=CPU_STATS_TOLERANCE)
def test_swapmem_total(self): out = sh('sysctl vm.swapusage') out = out.replace('vm.swapusage: ', '') total, used, free = re.findall('\d+.\d+\w', out) psutil_smem = psutil.swap_memory() self.assertEqual(psutil_smem.total, human2bytes(total)) self.assertEqual(psutil_smem.used, human2bytes(used)) self.assertEqual(psutil_smem.free, human2bytes(free))
def test_sensors_battery(self): out = sh("pmset -g batt") percent = re.search("(\d+)%", out).group(1) drawing_from = re.search("Now drawing from '([^']+)'", out).group(1) power_plugged = drawing_from == "AC Power" psutil_result = psutil.sensors_battery() self.assertEqual(psutil_result.power_plugged, power_plugged) self.assertEqual(psutil_result.percent, int(percent))
def df(device): out = sh("df -k %s" % device).strip() line = out.split('\n')[1] fields = line.split() total = int(fields[1]) * 1024 used = int(fields[2]) * 1024 free = int(fields[3]) * 1024 percent = float(fields[4].replace('%', '')) return (total, used, free, percent)
def test_nic_names(self): out = sh('ipconfig /all') nics = psutil.net_io_counters(pernic=True).keys() for nic in nics: if "pseudo-interface" in nic.replace(' ', '-').lower(): continue if nic not in out: self.fail( "%r nic wasn't found in 'ipconfig /all' output" % nic)
def test_users(self): out = sh("who") lines = out.split('\n') users = [x.split()[0] for x in lines] terminals = [x.split()[1] for x in lines] self.assertEqual(len(users), len(psutil.users())) for u in psutil.users(): self.assertIn(u.name, users) self.assertIn(u.terminal, terminals)
def muse(field): """Thin wrapper around 'muse' cmdline utility.""" out = sh('muse') for line in out.split('\n'): if line.startswith(field): break else: raise ValueError("line not found") return int(line.split()[1])
def free_swap(): """Parse 'free' cmd and return swap memory's s total, used and free values. """ lines = sh('free').split('\n') for line in lines: if line.startswith('Swap'): _, total, used, free = line.split() return (int(total) * 1024, int(used) * 1024, int(free) * 1024)
def vm_stat(field): """Wrapper around 'vm_stat' cmdline utility.""" out = sh('vm_stat') for line in out.split('\n'): if field in line: break else: raise ValueError("line not found") return int(re.search(r'\d+', line).group(0)) * PAGESIZE
def test_users(self): out = sh("who") lines = out.split('\n') users = [x.split()[0] for x in lines] self.assertEqual(len(users), len(psutil.users())) terminals = [x.split()[1] for x in lines] for u in psutil.users(): self.assertTrue(u.name in users, u.name) self.assertTrue(u.terminal in terminals, u.terminal)
def test_nic_names(self): output = sh("ifconfig -a") for nic in psutil.net_io_counters(pernic=True).keys(): for line in output.split(): if line.startswith(nic): break else: self.fail( "couldn't find %s nic in 'ifconfig -a' output\n%s" % ( nic, output))
def df(path): out = sh('df -P -B 1 "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total, used, free = int(total), int(used), int(free) return dev, total, used, free
def test_net_if_stats(self): for name, stats in psutil.net_if_stats().items(): try: out = sh("ifconfig %s" % name) except RuntimeError: pass else: self.assertEqual(stats.isup, 'RUNNING' in out, msg=out) self.assertEqual(stats.mtu, int(re.findall(r'mtu (\d+)', out)[0]))
def sysctl(cmdline): """Expects a sysctl command with an argument and parse the result returning only the value of interest. """ out = sh(cmdline) result = out.split()[1] try: return int(result) except ValueError: return result
def free_physmem(): """Parse 'free' cmd and return physical memory's total, used and free values. """ lines = sh('free').split('\n') for line in lines: if line.startswith('Mem'): total, used, free, shared, buffers, cached = \ [int(x) * 1024 for x in line.split()[1:]] return (total, used, free, shared, buffers, cached)
def free_swap(): """Parse 'free' cmd and return swap memory's s total, used and free values. """ lines = sh('free').split('\n') for line in lines: if line.startswith('Swap'): _, total, used, free = line.split() return (int(total) * 1024, int(used) * 1024, int(free) * 1024) raise ValueError( "can't find 'Swap' in 'free' output:\n%s" % '\n'.join(lines))
def test_users(self): out = sh("who") if not out.strip(): raise self.skipTest("no users on this system") lines = out.split('\n') users = [x.split()[0] for x in lines] terminals = [x.split()[1] for x in lines] self.assertEqual(len(users), len(psutil.users())) for u in psutil.users(): self.assertIn(u.name, users) self.assertIn(u.terminal, terminals)
def parse_swapinfo(): # the last line is always the total output = sh("swapinfo -k").splitlines()[-1] parts = re.split(r'\s+', output) if not parts: raise ValueError("Can't parse swapinfo: %s" % output) # the size is in 1k units, so multiply by 1024 total, used, free = (int(p) * 1024 for p in parts[1:4]) return total, used, free
def test_net_if_stats(self): for name, stats in psutil.net_if_stats().items(): try: out = sh("ifconfig %s" % name) except RuntimeError: pass else: self.assertEqual(stats.isup, 'RUNNING' in out, msg=out) if "mtu" in out: self.assertEqual(stats.mtu, int(re.findall(r'mtu (\d+)', out)[0]))
def vm_stat(field): """Wrapper around 'vm_stat' cmdline utility.""" from psutil._psutil_posix import getpagesize out = sh('vm_stat') for line in out.split('\n'): if field in line: break else: raise ValueError("line not found") return int(re.search(r'\d+', line).group(0)) * getpagesize()
def free_swap(): """Parse 'free' cmd and return swap memory's s total, used and free values. """ lines = sh('free').split('\n') for line in lines: if line.startswith('Swap'): _, total, used, free = line.split() return (int(total) * 1024, int(used) * 1024, int(free) * 1024) raise ValueError("can't find 'Swap' in 'free' output:\n%s" % '\n'.join(lines))
def test_proc_uids_gids(self): out = sh('procstat -s %s' % self.pid) euid, ruid, suid, egid, rgid, sgid = out.split('\n')[1].split()[2:8] p = psutil.Process(self.pid) uids = p.uids() gids = p.gids() self.assertEqual(uids.real, int(ruid)) self.assertEqual(uids.effective, int(euid)) self.assertEqual(uids.saved, int(suid)) self.assertEqual(gids.real, int(rgid)) self.assertEqual(gids.effective, int(egid)) self.assertEqual(gids.saved, int(sgid))
def test_net_if_names(self): out = sh("ip addr").strip() nics = [x for x in psutil.net_if_addrs().keys() if ':' not in x] found = 0 for line in out.split('\n'): line = line.strip() if re.search("^\d+:", line): found += 1 name = line.split(':')[1].strip() self.assertIn(name, nics) self.assertEqual(len(nics), found, msg="%s\n---\n%s" % ( pprint.pformat(nics), out))
def df(path): out = sh('df -k "%s"' % path).strip() lines = out.split('\n') lines.pop(0) line = lines.pop(0) dev, total, used, free = line.split()[:4] if dev == 'none': dev = '' total = int(total) * 1024 used = int(used) * 1024 free = int(free) * 1024 return dev, total, used, free
def ifconfig(nic): ret = {} out = sh("ifconfig %s" % name) ret['packets_recv'] = int(re.findall('RX packets:(\d+)', out)[0]) ret['packets_sent'] = int(re.findall('TX packets:(\d+)', out)[0]) ret['errin'] = int(re.findall('errors:(\d+)', out)[0]) ret['errout'] = int(re.findall('errors:(\d+)', out)[1]) ret['dropin'] = int(re.findall('dropped:(\d+)', out)[0]) ret['dropout'] = int(re.findall('dropped:(\d+)', out)[1]) ret['bytes_recv'] = int(re.findall('RX bytes:(\d+)', out)[0]) ret['bytes_sent'] = int(re.findall('TX bytes:(\d+)', out)[0]) return ret
def test_process_create_time(self): output = sh("ps -o lstart -p %s" % self.pid) start_ps = output.replace('STARTED', '').strip() hhmmss = start_ps.split(' ')[-2] year = start_ps.split(' ')[-1] start_psutil = psutil.Process(self.pid).create_time() self.assertEqual( hhmmss, time.strftime("%H:%M:%S", time.localtime(start_psutil))) self.assertEqual( year, time.strftime("%Y", time.localtime(start_psutil)))
def test_available(self): # "free" output format has changed at some point: # https://github.com/giampaolo/psutil/issues/538#issuecomment-147192098 out = sh("free -b") lines = out.split('\n') if 'available' not in lines[0]: raise unittest.SkipTest("free does not support 'available' column") else: free_value = int(lines[1].split()[-1]) psutil_value = psutil.virtual_memory().available self.assertAlmostEqual( free_value, psutil_value, delta=MEMORY_TOLERANCE, msg='%s %s \n%s' % (free_value, psutil_value, out))
def assert_stdout(self, exe, args=None): exe = '"%s"' % os.path.join(SCRIPTS_DIR, exe) if args: exe = exe + ' ' + args try: out = sh(sys.executable + ' ' + exe).strip() except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: raise assert out, out return out
def test_proc_memory_maps(self): out = sh('procstat -v %s' % self.pid) maps = psutil.Process(self.pid).memory_maps(grouped=False) lines = out.split('\n')[1:] while lines: line = lines.pop() fields = line.split() _, start, stop, perms, res = fields[:5] map = maps.pop() self.assertEqual("%s-%s" % (start, stop), map.addr) self.assertEqual(int(res), map.rss) if not map.path.startswith('['): self.assertEqual(fields[10], map.path)
def free_swap(): """Parse 'free' cmd and return swap memory's s total, used and free values. """ out = sh('free -b') lines = out.split('\n') for line in lines: if line.startswith('Swap'): _, total, used, free = line.split() nt = collections.namedtuple('free', 'total used free') return nt(int(total), int(used), int(free)) raise ValueError( "can't find 'Swap' in 'free' output:\n%s" % '\n'.join(lines))
def assert_stdout(self, exe, args=None): exe = os.path.join(SCRIPTS_DIR, exe) if args: exe = exe + ' ' + args try: out = sh(sys.executable + ' ' + exe).strip() except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: raise assert out, out return out
def assert_stdout(exe, args=None, **kwds): exe = '"%s"' % os.path.join(SCRIPTS_DIR, exe) if args: exe = exe + ' ' + args try: out = sh(PYTHON_EXE + ' ' + exe, **kwds).strip() except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: raise assert out, out return out
def sysctl(cmdline): """Expects a sysctl command with an argument and parse the result returning only the value of interest. """ result = sh("sysctl " + cmdline) if FREEBSD: result = result[result.find(": ") + 2:] elif OPENBSD or NETBSD: result = result[result.find("=") + 1:] try: return int(result) except ValueError: return result
def assert_stdout(exe, *args, **kwargs): exe = '%s' % os.path.join(SCRIPTS_DIR, exe) cmd = [PYTHON_EXE, exe] for arg in args: cmd.append(arg) try: out = sh(cmd, **kwargs).strip() except RuntimeError as err: if 'AccessDenied' in str(err): return str(err) else: raise assert out, out return out
def ps(fmt, pid=None): """ Wrapper for calling the ps command with a little bit of cross-platform support for a narrow range of features. """ cmd = ['ps'] if LINUX: cmd.append('--no-headers') if pid is not None: cmd.extend(['-p', str(pid)]) else: if SUNOS: cmd.append('-A') else: cmd.append('ax') if SUNOS: fmt_map = {'command', 'comm', 'start', 'stime'} fmt = fmt_map.get(fmt, fmt) cmd.extend(['-o', fmt]) output = sh(cmd) if LINUX: output = output.splitlines() else: output = output.splitlines()[1:] all_output = [] for line in output: line = line.strip() try: line = int(line) except ValueError: pass all_output.append(line) if pid is None: return all_output else: return all_output[0]
def ps(cmd): """Expects a ps command with a -o argument and parse the result returning only the value of interest. """ if not LINUX: cmd = cmd.replace(" --no-headers ", " ") if SUNOS: cmd = cmd.replace("-o command", "-o comm") cmd = cmd.replace("-o start", "-o stime") output = sh(cmd) if not LINUX: output = output.split('\n')[1].strip() try: return int(output) except ValueError: return output
def free_physmem(): """Parse 'free' cmd and return physical memory's total, used and free values. """ # Note: free can have 2 different formats, invalidating 'shared' # and 'cached' memory which may have different positions so we # do not return them. # https://github.com/giampaolo/psutil/issues/538#issuecomment-57059946 lines = sh('free').split('\n') for line in lines: if line.startswith('Mem'): total, used, free, shared = \ [int(x) * 1024 for x in line.split()[1:5]] return (total, used, free, shared) raise ValueError( "can't find 'Mem' in 'free' output:\n%s" % '\n'.join(lines))
def free_physmem(): """Parse 'free' cmd and return physical memory's total, used and free values. """ # Note: free can have 2 different formats, invalidating 'shared' # and 'cached' memory which may have different positions so we # do not return them. # https://github.com/giampaolo/psutil/issues/538#issuecomment-57059946 lines = sh('free').split('\n') for line in lines: if line.startswith('Mem'): total, used, free, shared = \ [int(x) * 1024 for x in line.split()[1:5]] return (total, used, free, shared) raise ValueError("can't find 'Mem' in 'free' output:\n%s" % '\n'.join(lines))
def test_swap_memory(self): out = sh('env PATH=/usr/sbin:/sbin:%s swap -l' % os.environ['PATH']) lines = out.strip().split('\n')[1:] if not lines: raise ValueError('no swap device(s) configured') total = free = 0 for line in lines: line = line.split() t, f = line[-2:] total += int(int(t) * 512) free += int(int(f) * 512) used = total - free psutil_swap = psutil.swap_memory() self.assertEqual(psutil_swap.total, total) self.assertEqual(psutil_swap.used, used) self.assertEqual(psutil_swap.free, free)
def test_sensors_battery(self): def secs2hours(secs): m, s = divmod(secs, 60) h, m = divmod(m, 60) return "%d:%02d" % (h, m) out = sh("acpiconf -i 0") fields = dict([(x.split('\t')[0], x.split('\t')[-1]) for x in out.split("\n")]) metrics = psutil.sensors_battery() percent = int(fields['Remaining capacity:'].replace('%', '')) remaining_time = fields['Remaining time:'] self.assertEqual(metrics.percent, percent) if remaining_time == 'unknown': self.assertEqual(metrics.secsleft, psutil.POWER_TIME_UNLIMITED) else: self.assertEqual(secs2hours(metrics.secsleft), remaining_time)
def test_proc_cpu_times(self): tested = [] out = sh('procstat -r %s' % self.pid) p = psutil.Process(self.pid) for line in out.split('\n'): line = line.lower().strip() if 'user time' in line: pstat_value = float('0.' + line.split()[-1].split('.')[-1]) psutil_value = p.cpu_times().user self.assertEqual(pstat_value, psutil_value) tested.append(None) elif 'system time' in line: pstat_value = float('0.' + line.split()[-1].split('.')[-1]) psutil_value = p.cpu_times().system self.assertEqual(pstat_value, psutil_value) tested.append(None) if len(tested) != 2: raise RuntimeError("couldn't find lines match in procstat out")
def test_proc_ctx_switches(self): tested = [] out = sh('procstat -r %s' % self.pid) p = psutil.Process(self.pid) for line in out.split('\n'): line = line.lower().strip() if ' voluntary context' in line: pstat_value = int(line.split()[-1]) psutil_value = p.num_ctx_switches().voluntary self.assertEqual(pstat_value, psutil_value) tested.append(None) elif ' involuntary context' in line: pstat_value = int(line.split()[-1]) psutil_value = p.num_ctx_switches().involuntary self.assertEqual(pstat_value, psutil_value) tested.append(None) if len(tested) != 2: raise RuntimeError("couldn't find lines match in procstat out")
def test_swap_memory(self): out = sh('/usr/sbin/lsps -a') # From the man page, "The size is given in megabytes" so we assume # we'll always have 'MB' in the result # TODO maybe try to use "swap -l" to check "used" too, but its units # are not guaranteed to be "MB" so parsing may not be consistent matchobj = re.search(r"(?P<space>\S+)\s+" r"(?P<vol>\S+)\s+" r"(?P<vg>\S+)\s+" r"(?P<size>\d+)MB", out) self.assertIsNotNone( matchobj, "lsps command returned unexpected output") total_mb = int(matchobj.group("size")) MB = 1024 ** 2 psutil_result = psutil.swap_memory() # we divide our result by MB instead of multiplying the lsps value by # MB because lsps may round down, so we round down too self.assertEqual(int(psutil_result.total / MB), total_mb)
def test_net_if_addrs_names(self): out = sh('/etc/ifconfig -l') ifconfig_names = set(out.split()) psutil_names = set(psutil.net_if_addrs().keys()) self.assertSetEqual(ifconfig_names, psutil_names)
def test_cpu_count(self): out = sh("/usr/sbin/psrinfo") self.assertEqual(psutil.cpu_count(), len(out.split('\n')))
def test_proc_exe(self): out = sh('procstat -b %s' % self.pid) self.assertEqual(psutil.Process(self.pid).exe(), out.split('\n')[1].split()[-1])
def test_cpu_count_logical(self): out = sh('/usr/bin/mpstat -a') mpstat_lcpu = int(re.search("lcpu=(\d+)", out).group(1)) psutil_lcpu = psutil.cpu_count(logical=True) self.assertEqual(mpstat_lcpu, psutil_lcpu)
def test_proc_cmdline(self): out = sh('procstat -c %s' % self.pid) self.assertEqual(' '.join(psutil.Process(self.pid).cmdline()), ' '.join(out.split('\n')[1].split()[2:]))