# Copyright (c) 2009, Giampaolo Rodola'. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
"""Windows platform implementation."""
import contextlib
import errno
import functools
import os
import signal
import sys
import time
from collections import namedtuple
from . import _common
from ._common import ENCODING
from ._common import ENCODING_ERRS
from ._common import AccessDenied
from ._common import NoSuchProcess
from ._common import TimeoutExpired
from ._common import conn_tmap
from ._common import conn_to_ntuple
from ._common import debug
from ._common import isfile_strict
from ._common import memoize
from ._common import memoize_when_activated
from ._common import parse_environ_block
from ._common import usage_percent
from ._compat import PY3
from ._compat import long
from ._compat import lru_cache
from ._compat import range
from ._compat import unicode
from ._psutil_windows import ABOVE_NORMAL_PRIORITY_CLASS
from ._psutil_windows import BELOW_NORMAL_PRIORITY_CLASS
from ._psutil_windows import HIGH_PRIORITY_CLASS
from ._psutil_windows import IDLE_PRIORITY_CLASS
from ._psutil_windows import NORMAL_PRIORITY_CLASS
from ._psutil_windows import REALTIME_PRIORITY_CLASS
try:
from . import _psutil_windows as cext
except ImportError as err:
if str(err).lower().startswith("dll load failed") and \
sys.getwindowsversion()[0] < 6:
# We may get here if:
# 1) we are on an old Windows version
# 2) psutil was installed via pip + wheel
# See: https://github.com/giampaolo/psutil/issues/811
msg = "this Windows version is too old (< Windows Vista); "
msg += "psutil 3.4.2 is the latest version which supports Windows "
msg += "2000, XP and 2003 server"
raise RuntimeError(msg)
else:
raise
if sys.version_info >= (3, 4):
import enum
else:
enum = None
# process priority constants, import from __init__.py:
# http://msdn.microsoft.com/en-us/library/ms686219(v=vs.85).aspx
__extra__all__ = [
"win_service_iter", "win_service_get",
# Process priority
"ABOVE_NORMAL_PRIORITY_CLASS", "BELOW_NORMAL_PRIORITY_CLASS",
"HIGH_PRIORITY_CLASS", "IDLE_PRIORITY_CLASS", "NORMAL_PRIORITY_CLASS",
"REALTIME_PRIORITY_CLASS",
# IO priority
"IOPRIO_VERYLOW", "IOPRIO_LOW", "IOPRIO_NORMAL", "IOPRIO_HIGH",
# others
"CONN_DELETE_TCB", "AF_LINK",
]
# =====================================================================
# --- globals
# =====================================================================
CONN_DELETE_TCB = "DELETE_TCB"
ERROR_PARTIAL_COPY = 299
PYPY = '__pypy__' in sys.builtin_module_names
if enum is None:
AF_LINK = -1
else:
AddressFamily = enum.IntEnum('AddressFamily', {'AF_LINK': -1})
AF_LINK = AddressFamily.AF_LINK
TCP_STATUSES = {
cext.MIB_TCP_STATE_ESTAB: _common.CONN_ESTABLISHED,
cext.MIB_TCP_STATE_SYN_SENT: _common.CONN_SYN_SENT,
cext.MIB_TCP_STATE_SYN_RCVD: _common.CONN_SYN_RECV,
cext.MIB_TCP_STATE_FIN_WAIT1: _common.CONN_FIN_WAIT1,
cext.MIB_TCP_STATE_FIN_WAIT2: _common.CONN_FIN_WAIT2,
cext.MIB_TCP_STATE_TIME_WAIT: _common.CONN_TIME_WAIT,
cext.MIB_TCP_STATE_CLOSED: _common.CONN_CLOSE,
cext.MIB_TCP_STATE_CLOSE_WAIT: _common.CONN_CLOSE_WAIT,
cext.MIB_TCP_STATE_LAST_ACK: _common.CONN_LAST_ACK,
cext.MIB_TCP_STATE_LISTEN: _common.CONN_LISTEN,
cext.MIB_TCP_STATE_CLOSING: _common.CONN_CLOSING,
cext.MIB_TCP_STATE_DELETE_TCB: CONN_DELETE_TCB,
cext.PSUTIL_CONN_NONE: _common.CONN_NONE,
}
if enum is not None:
class Priority(enum.IntEnum):
ABOVE_NORMAL_PRIORITY_CLASS = ABOVE_NORMAL_PRIORITY_CLASS
BELOW_NORMAL_PRIORITY_CLASS = BELOW_NORMAL_PRIORITY_CLASS
HIGH_PRIORITY_CLASS = HIGH_PRIORITY_CLASS
IDLE_PRIORITY_CLASS = IDLE_PRIORITY_CLASS
NORMAL_PRIORITY_CLASS = NORMAL_PRIORITY_CLASS
REALTIME_PRIORITY_CLASS = REALTIME_PRIORITY_CLASS
globals().update(Priority.__members__)
if enum is None:
IOPRIO_VERYLOW = 0
IOPRIO_LOW = 1
IOPRIO_NORMAL = 2
IOPRIO_HIGH = 3
else:
class IOPriority(enum.IntEnum):
IOPRIO_VERYLOW = 0
IOPRIO_LOW = 1
IOPRIO_NORMAL = 2
IOPRIO_HIGH = 3
globals().update(IOPriority.__members__)
pinfo_map = dict(
num_handles=0,
ctx_switches=1,
user_time=2,
kernel_time=3,
create_time=4,
num_threads=5,
io_rcount=6,
io_wcount=7,
io_rbytes=8,
io_wbytes=9,
io_count_others=10,
io_bytes_others=11,
num_page_faults=12,
peak_wset=13,
wset=14,
peak_paged_pool=15,
paged_pool=16,
peak_non_paged_pool=17,
non_paged_pool=18,
pagefile=19,
peak_pagefile=20,
mem_private=21,
)
# =====================================================================
# --- named tuples
# =====================================================================
# psutil.cpu_times()
scputimes = namedtuple('scputimes',
['user', 'system', 'idle', 'interrupt', 'dpc'])
# psutil.virtual_memory()
svmem = namedtuple('svmem', ['total', 'available', 'percent', 'used', 'free'])
# psutil.Process.memory_info()
pmem = namedtuple(
'pmem', ['rss', 'vms',
'num_page_faults', 'peak_wset', 'wset', 'peak_paged_pool',
'paged_pool', 'peak_nonpaged_pool', 'nonpaged_pool',
'pagefile', 'peak_pagefile', 'private'])
# psutil.Process.memory_full_info()
pfullmem = namedtuple('pfullmem', pmem._fields + ('uss', ))
# psutil.Process.memory_maps(grouped=True)
pmmap_grouped = namedtuple('pmmap_grouped', ['path', 'rss'])
# psutil.Process.memory_maps(grouped=False)
pmmap_ext = namedtuple(
'pmmap_ext', 'addr perms ' + ' '.join(pmmap_grouped._fields))
# psutil.Process.io_counters()
pio = namedtuple('pio', ['read_count', 'write_count',
'read_bytes', 'write_bytes',
'other_count', 'other_bytes'])
# =====================================================================
# --- utils
# =====================================================================
@lru_cache(maxsize=512)
def convert_dos_path(s):
r"""Convert paths using native DOS format like:
"\Device\HarddiskVolume1\Windows\systemew\file.txt"
into:
"C:\Windows\systemew\file.txt"
"""
rawdrive = '\\'.join(s.split('\\')[:3])
driveletter = cext.QueryDosDevice(rawdrive)
remainder = s[len(rawdrive):]
return os.path.join(driveletter, remainder)
def py2_strencode(s):
"""Encode a unicode string to a byte string by using the default fs
encoding + "replace" error handler.
"""
if PY3:
return s
else:
if isinstance(s, str):
return s
else:
return s.encode(ENCODING, ENCODING_ERRS)
@memoize
def getpagesize():
return cext.getpagesize()
# =====================================================================
# --- memory
# =====================================================================
def virtual_memory():
"""System virtual memory as a namedtuple."""
mem = cext.virtual_mem()
totphys, availphys, totsys, availsys = mem
#
total = totphys
avail = availphys
free = availphys
used = total - avail
percent = usage_percent((total - avail), total, round_=1)
return svmem(total, avail, percent, used, free)
def swap_memory():
"""Swap system memory as a (total, used, free, sin, sout) tuple."""
mem = cext.virtual_mem()
total_phys = mem[0]
free_phys = mem[1]
total_system = mem[2]
free_system = mem[3]
# system memory (commit total/limit) is the sum of physical and swap
# thus physical memory values need to be substracted to get swap values
total = total_system - total_phys
free = min(total, free_system - free_phys)
used = total - free
percent = usage_percent(used, total, round_=1)
return _common.sswap(total, used, free, percent, 0, 0)
# =====================================================================
# --- disk
# =====================================================================
disk_io_counters = cext.disk_io_counters
def disk_usage(path):
"""Return disk usage associated with path."""
if PY3 and isinstance(path, bytes):
# XXX: do we want to use "strict"? Probably yes, in order
# to fail immediately. After all we are accepting input here...
path = path.decode(ENCODING, errors="strict")
total, free = cext.disk_usage(path)
used = total - free
percent = usage_percent(used, total, round_=1)
return _common.sdiskusage(total, used, free, percent)
def disk_partitions(all):
"""Return disk partitions."""
rawlist = cext.disk_partitions(all)
return [_common.sdiskpart(*x) for x in rawlist]
# =====================================================================
# --- CPU
# =====================================================================
def cpu_times():
"""Return system CPU times as a named tuple."""
user, system, idle = cext.cpu_times()
# Internally, GetSystemTimes() is used, and it doesn't return
# interrupt and dpc times. cext.per_cpu_times() does, so we
# rely on it to get those only.
percpu_summed = scputimes(*[sum(n) for n in zip(*cext.per_cpu_times())])
return scputimes(user, system, idle,
percpu_summed.interrupt, percpu_summed.dpc)
def per_cpu_times():
"""Return system per-CPU times as a list of named tuples."""
ret = []
for user, system, idle, interrupt, dpc in cext.per_cpu_times():
item = scputimes(user, system, idle, interrupt, dpc)
ret.append(item)
return ret
def cpu_count_logical():
"""Return the number of logical CPUs in the system."""
return cext.cpu_count_logical()
def cpu_count_cores():
"""Return the number of CPU cores in the system."""
return cext.cpu_count_cores()
def cpu_stats():
"""Return CPU statistics."""
ctx_switches, interrupts, dpcs, syscalls = cext.cpu_stats()
soft_interrupts = 0
return _common.scpustats(ctx_switches, interrupts, soft_interrupts,
syscalls)
def cpu_freq():
"""Return CPU frequency.
On Windows per-cpu frequency is not supported.
"""
curr, max_ = cext.cpu_freq()
min_ = 0.0
return [_common.scpufreq(float(curr), min_, float(max_))]
_loadavg_inititialized = False
def getloadavg():
"""Return the number of processes in the system run queue averaged
over the last 1, 5, and 15 minutes respectively as a tuple"""
global _loadavg_inititialized
Loading ...