Beispiel #1
0
 def __init__(self):
     name = dbus.service.BusName('org.iomonitor', dbus.SystemBus(
                                                  mainloop=DBusGMainLoop()))
     super(IoMonitor, self).__init__(name, '/org/iomonitor')
     self.pid = os.getpid()
     self.tasks = Taskstats(self.pid)
     self.is_pid = lambda file_name: file_name.isdigit()
     self.procs = lambda: map(int, filter(self.is_pid, os.listdir('/proc')))
Beispiel #2
0
 def __init__(self, pid):
     self.pid = pid
     self.__taskstats = Taskstats(self.pid)
     self.__rst_state = self.rBytes()
     self.__wst_state = self.wBytes()
     self._last_r = self.__rst_state
     self._last_w = self.__wst_state
     self.__st_switches = self.__pid_status_attrs.get(
                              'voluntary_ctxt_switches')
     if self.__st_switches is None:
         self.__st_switches = 0
Beispiel #3
0
class Profile(object):
    '''
    Profile object: builds a <Profile> object from the "pid" provided on
    initialization.
    '''

    STAT_FIELDS = ['pid', 'tcomm', 'state', 'ppid', 'pgrp', 'sid', 'tty_nr', 
                   'tty_pgrp', 'flags', 'min_flt', 'cmin_flt', 'maj_flt',
                   'cmaj_flt', 'utime', 'stime', 'cutime', 'cstime',
                   'priority', 'nice', 'num_threads', 'it_real_value', 
                   'start_time', 'vsize', 'rss', 'rsslim', 'start_code', 
                   'end_code', 'start_stack', 'esp', 'eip', 'pending', 
                   'blocked', 'sigign', 'sigcatch', 'wchan', 'NONE', 'NONE', 
                   'exit_signal', 'task_cpu', 'rt_priority', 'policy', 
                   'blkio_ticks', 'gtime', 'cgtime', 'start_data', 'end_data', 
                   'arg_start', 'arg_end', 'env_start', 'env_end', 'exit_code'
                  ]

    PROC_STATES = {'R':'running', 'S':'interruptible_sleep', 
                   'D':'uninterruptible_disk_sleep', 'Z':'zombie', 
                   'T':'traced', 'W':'paging'
                  }

    def __init__(self, pid):
        self.pid = pid
        self.__taskstats = Taskstats(self.pid)
        self.__rst_state = self.rBytes()
        self.__wst_state = self.wBytes()
        self._last_r = self.__rst_state
        self._last_w = self.__wst_state
        self.__st_switches = self.__pid_status_attrs.get(
                                 'voluntary_ctxt_switches')
        if self.__st_switches is None:
            self.__st_switches = 0
        
    @property
    def is_alive(self):
        '''
        Class property.getter: returns <type 'bool'> response of processes 
        state.
        '''
        all_processes = filter(lambda i: i.isdigit(), os.listdir('/proc'))
        return self.pid in map(int, all_processes)

    @is_alive.setter
    def is_alive(self, state):
        '''
        Class property.setter: returns <type 'NoneType'> sets the is_alive 
        property to False if ending the process is needed.
        '''
        if not isinstance(state, bool):
            raise TypeError
        if not self.tgid:
            raise BadProcess(self.pid)
        tkill(self.tgid, self.pid, SIGKILL)
        
    @property
    def ppid(self):
        '''
        Class property: returns <type 'int'> of the profiled pid's parent.
        '''
        pid_stats = self.file_reader('/proc/%s/stat' % self.pid)
        return int(pid_stats.split()[3])

    @property
    def name(self):
        '''
        Class property: returns <type 'str'> of profiled pid's name.
        '''
        pid_name = self.file_reader('/proc/%s/comm' % self.pid)
        return pid_name.strip('\n')

    @property
    def fds(self):
        '''
        Class property: returns <type 'int'> of open file-descriptors of 
        profiled pid.
        '''
        try:
            fds = os.listdir('/proc/%s/fd' % self.pid)
        except OSError:
            raise BadProcess(self.pid)
        return len(fds)

    @property
    def gid(self):
        '''
        Class property: returns <type 'str'> or <type 'NoneType'> of profiled 
        pids group id.
        '''
        gid = self.__pid_status_attrs.get('gid')
        if gid:
            return gid[0]
        return

    @property
    def tgid(self):
        '''
        Class property: returns <type 'int'> of profiled pids thread group id.
        '''
        tgid = self.__pid_status_attrs.get('tgid')
        if tgid:
            return int(tgid[0])
        return 

    def get_tids(self):
        '''
        Class method: returns <type 'list'> of profiled pids thread ids.
        '''
        threads_path = '/proc/%d/task/' % self.pid
        threads = os.listdir(threads_path)
        return threads

    @property
    def threads(self):
        '''
        Class property: returns <type 'int'> or <type 'NoneType'> of profiled 
        pids thread count.
        '''
        threads = self.__pid_status_attrs.get('threads')
        if threads:
            return int(threads[0])
        return

    @property
    def state(self):
        '''
        Class property: returns <type 'str'> or <type 'NoneType'> of profiled
        pids current state.
        '''
        state = self.__pid_stat_attrs.get('state')
        if state:
            return self.PROC_STATES[state]
        return 'Unknown'

    def load_aux_attrs(self):
        '''
        Class method: returns <type 'NoneType'>, this method creates additional
        auxillary instance attributes.
        '''
        aux_attrs = self.__pid_status_attrs
        for attr in aux_attrs:
            if not aux_attrs[attr]: continue
            attr_value = ' '.join(aux_attrs[attr])
            if not hasattr(self, attr):
                setattr(self, 'aux_' + attr, attr_value)            

    def update_aux_attrs(self):
        '''
        Class method: returns <type 'NoneType'>, this method updates the
        auxillary attributes (if load_aux_attrs methods has already been)
        called.
        '''
        aux_attrs = self.__pid_status_attrs
        for attr in aux_attrs:
            if hasattr(self, 'aux_' + attr):
                aux_attr = 'self.aux_' + attr
                update_value = ' '.join(aux_attrs[attr])
                exec("%s = '%s'" % (aux_attr, update_value))
     
    def nice(self):
        '''
        Class method: returns <type 'int'> of profiled pids niceness.
        '''
        return nice(self.pid)

    def setnice(self, level):
        '''
        Class method: sets the niceness of profiled pid, returns
        <type 'NoneType'>.

        @type 'level': <type 'int'>
        @param 'level': the new nice to set profiled pid to.
        '''
        setnice(self.pid, level)
        return 

    def ioprio(self):
        '''
        Class method: returns <type 'tuple'> of profiled pids IO_Priority
        class and ioprio_nice. 
        '''
        return ioprio(self.pid)
        
    def switches(self):
        '''
        Class method: returns <type 'int'> for the number of context switches
        of profiled pid.
        '''
        switches = self.__pid_status_attrs.get('voluntary_ctxt_switches')
        if switches:
            return int(switches[0])
        return

    def has_switched(self):
        '''
        Class method: returns <type 'bool'> to signal if there have voluntary
        context switches since initialization or last call of this method.
        '''
        current_switches = self.__pid_status_attrs.get(
                                'voluntary_ctxt_switches')
        if current_switches > self.__st_switches:
            self.__st_switches = current_switches
            return True
        return False

    def rBytes(self):
        '''
        Class method: returns <type 'int'> of pids total read bytes since 
        startup.
        '''
        try:
            bytes_read = self.__taskstats.read()
        except InsufficientRights:
            bytes_read = self.procfs_read()
        return bytes_read

    def wBytes(self):
        '''
        Class method: returns <type 'int'> of the pids total write bytes since 
        startup.
        '''
        try:
            bytes_written = self.__taskstats.write()
        except InsufficientRights:
            bytes_written = self.procfs_write()
        return bytes_written

    def procfs_read(self):
        read = self.file_reader('/proc/%s/io' % self.pid)
        return int(read.split()[1])
 
    def procfs_write(self):
        write = self.file_reader('/proc/%s/io' % self.pid)
        return int(write.split()[3])
 
    def has_read(self):
        '''
        Class method: returns <type 'bool'> for pid's reads since 
        initialization or the last call of this method.
        '''
        current_r = self.rBytes()
        if current_r > self._last_r:
            self._last_r = current_r
            return True
        return False

    def has_write(self):
        '''
        Class method: returns <type 'bool'> for the pids writes since 
        initialization or last call of this method.
        '''
        current_w = self.wBytes()
        if current_w > self._last_w:
            self._last_w = current_w
            return True
        return False

    def allread(self):
        '''
        Class method: returns <type 'int'> for pids total reads since object
         creation.
        '''
        current_r = self.rBytes()
        return current_r - self.__rst_state

    def allwrite(self):
        '''
        Class method: returns <type 'int'> for the pids total writes since
        object creation.
        '''
        current_w = self.wBytes()
        return current_w - self.__wst_state

    def smap(self):        
        '''
        Class method: returns <type 'dict'> of namedtuples for the profiled
        pids mapping memory consumption.
        '''
        smap_tuple = namedtuple('smap', ['Size', 'Rss', 'Pss', 'Shared_Clean', 
                                         'Shared_Dirty', 'Private_Clean', 
                                         'Private_Dirty', 'Referenced', 
                                         'Anonymous', 'AnonHugePages', 'Swap', 
                                         'KernelPageSize', 'MMUPageSize',
                                         'Locked', 'VmFlags']
                               )
        proc_smap = self.file_reader('/proc/%s/smaps' % self.pid).split('\n')
        proc_smaps = [proc_smap[i:i + 16] for i in 
                      xrange(0, len(proc_smap), 16)]
        smappings = dict()
        rm_newline = lambda ln: ln.strip('\n')
        for smap in proc_smaps:
            if not smap[0]: continue
            path_name = smap[0].split()[-1]
            _smap = [''.join(i.split()[1:]) for i in smap[1:]]
            _smap = map(rm_newline, _smap)
            smappings[path_name] = smap_tuple(*_smap)
        return smappings

    def pmap(self):
        '''
        Class method: returns <type 'tuple'> of the profiled pids memory map.
        '''
        return tuple(self.smap().keys())

    def wchan(self):
        '''
        Class method: returns <type 'str'> of a kernel symbol where the profiled 
        pid currently sleeping(if at all).
        '''
        wchan = self.file_reader('/proc/%s/wchan' % self.pid)
        return wchan

    def fdstat(self):
        '''
        Class method: returns <type 'dict'> for all file-descriptors as the keys
        and tuple for the files stats.
        '''
        path = '/proc/%s/fd/' % self.pid
        path_constructor = partial(lambda drt, fn: os.path.join(drt, fn), path)
        try:
            fds = map(path_constructor, os.listdir(path))
            fdstat = dict(zip(map(os.readlink, fds), map(os.stat, fds)))
        except IOError:
            raise BadProcess(self.pid)
        return fdstat

    def fdperms(self):
        '''
        Class method: returns <type 'dict'> for all file-descriptors real path
        as keys and their file permissions as octal values.
        '''
        fdstats = self.fdstat()
        permission_mask = lambda mask: oct(mask & 0777)
        modes = [fdstats[i].st_mode for i in fdstats]
        permissions = dict(zip(fdstats.keys(), map(permission_mask, modes)))
        return permissions

    def curlimit(self, resource):
        '''
        Class method: returns <type 'int'> for the current soft-limit of
        process.
        '''
        return curlimit(self.pid, resource)

    def maxlimit(self, resource):
        '''
        Class method: returns <type 'int'> for the current hard-limit of
        process.
        '''
        return maxlimit(self.pid, resource)

    def iso(self):
        '''
        Class method: returns <type 'NoneType'> :: sets the profiled process
        to run on one core and all others run on other cores.
        '''
        iso(self.pid)
        return

    def release_iso(self):
        '''
        Class method: returns <type 'NoneType'> :: releases a process that has
        been isolated.
        '''
        release_iso(self.pid)
        return

    def affinity(self):
        '''
        Class method: returns <type 'int'> for the number of cpus currently in
        processes cpu set.
        '''
        return affinity(self.pid)

    def start_time(self):
        '''
        Class method: returns <type 'float'> of seconds since boot that the 
        process started at.
        '''
        sc_clk_tck = os.sysconf('SC_CLK_TCK')
        uptime_data = self.file_reader('/proc/uptime')
        stat_data = self.file_reader('/proc/%s/stat' % self.pid)
        uptime = float(uptime_data.split()[0])
        start_time = float(stat_data.split()[21])
        return uptime - (start_time / sc_clk_tck)

    def file_reader(self, fpath):
        '''
        Class method: returns <type 'str'> for the file contents of fpath.
        '''
        try:
            with open(fpath) as f:
                raw_file_data = f.read()
        except IOError:
            raise InvalidPath(fpath)
        return raw_file_data

    @property
    def __pid_status_attrs(self):
        '''
        Private class property: (not meant to be called directly) populates a
        <type 'dict'> with pid attributes read from "status".
        '''
        raw_attrs = self.file_reader('/proc/%s/status' % self.pid)
        pid_attrs = {i[0].strip(':').lower():i[1:] for i in 
                     map(str.split, raw_attrs.split('\n')) if i}
        return pid_attrs

    @property
    def __pid_stat_attrs(self):
        '''
        Private class property: (not meant to be called directly) populates a
        <type 'dict'> with pid attributes read from "stat".
        '''
        stats = self.file_reader('/proc/%s/stat' % self.pid)
        pid_stats = dict(zip(self.STAT_FIELDS, stats.split()))
        return pid_stats

    def tgkill(self, tid, sig):
        '''
        Class method: returns <type 'NoneType'> :: sends signal 'sig' to thread
        'tid' in thread group 'tgid'.
        '''
        tgid = self.tgid
        if not tgid:
            raise BadProcess(self.pid)
        else:
            tkill(tgid, tid, sig)
        return

    def __str__(self):
        return self.__repr__()

    def __repr__(self):
        return "<class '%s (pid: %s | name: %s)'>" % (self.__class__.__name__, 
                                                      self.pid, self.name)
Beispiel #4
0
class IoMonitor(dbus.service.Object):

    def __init__(self):
        name = dbus.service.BusName('org.iomonitor', dbus.SystemBus(
                                                     mainloop=DBusGMainLoop()))
        super(IoMonitor, self).__init__(name, '/org/iomonitor')
        self.pid = os.getpid()
        self.tasks = Taskstats(self.pid)
        self.is_pid = lambda file_name: file_name.isdigit()
        self.procs = lambda: map(int, filter(self.is_pid, os.listdir('/proc')))

    @property
    def process_list(self):
        pids = self.procs()
        return dict(zip(map(self.tasks.process_name, pids), pids))

    @dbus.service.method('org.iomonitor', out_signature='aa{sa{st}}')
    def all_proc_io(self):
        all_stats = list()
        for process in self.process_list:
            write = self.tasks.write(self.process_list[process])
            read = self.tasks.read(self.process_list[process])
            all_stats.append({process:{'read':read, 'write':write}})
        return all_stats 

    @dbus.service.method('org.iomonitor', in_signature='i', out_signature='a{ia{st}}')
    def single_proc_io(self, pid=None):
        if pid is None:
            raise dbus.DBusException('''Invalid arg of type <NoneType> ::  
                                                 must be of type <int>''')
        write = self.tasks.write(pid)
        read = self.tasks.read(pid)
        return {pid:{'read':read, 'write':write}}

    @dbus.service.method('org.iomonitor', out_signature='a{st}')
    def all_proc_swap(self):
        return {p:self.tasks.swap(pid) for p, pid in self.process_list.items()}
        
    @dbus.service.method('org.iomonitor', in_signature='i', out_signature='a{it}')
    def single_proc_swap(self, pid=None):
        if pid is None:
            raise dbus.DBusException('''Invalid arg of type <NoneType> :: 
                                                 must be of type <int>''')
        pid_swap = self.tasks.swap(pid)
        return {pid:pid_swap}

    @dbus.service.method('org.iomonitor', out_signature='a{si}')
    def memory(self):
        with open('/proc/meminfo') as f:
            memory = f.read()
        memory = memory.split()
        total, free = map(int, [memory[1], memory[4]])
        return {'total_mem':total, 'free_mem':free, 'used_mem':total - free}

    @dbus.service.method('org.iomonitor', in_signature='s', out_signature='as')
    def diskstats(self, disk=None):
        if disk is None:
            raise dbus.DBusException('''Invalid arg of type <NoneType> :: 
                                                 must be of type <str>''')
        with open('/sys/block/sda/%s/stat' % disk) as f:
            raw_diskstats= f.read()
        disk_stats = raw_diskstats.split()
        return ['read %s write %s' % (disk_stats[0], disk_stats[4])]

    @dbus.service.method('org.iomonitor', out_signature='as')
    def disklist(self):
        return os.listdir('/sys/block')

    @dbus.service.method('org.iomonitor', out_signature='as')
    def deviceinfo(self):
        with open('/proc/scsi/scsi', 'r') as f:
            devinfo = f.readlines()
        return devinfo