def get_system_stats(self, details=None): """ Return system statistics on this node. :param details: Call details. :type details: :class:`autobahn.wamp.types.CallDetails` :return: Current system statistics for this node. :rtype: dict """ started = time_ns() res = self._smonitor.poll() us = int(round((time_ns() - started) / 1000.)) if us > 5000: self.log.warn( "{cls}.get_system_stats()->{mcls} excessive run-time of {duration}us!", cls=self.__class__.__name__, mcls=self._smonitor.__class__.__name__, duration=us) else: self.log.debug( "{cls}.get_system_stats()->{mcls} ran in {duration}us", cls=self.__class__.__name__, mcls=self._smonitor.__class__.__name__, duration=us) return res
def _loop(self, index): prefix = self.config.extra['prefix'] last = None while self._running: rtts = [] batch_started_str = utcnow() batch_started = time() while (time() - batch_started) < self._period: ts_req = time_ns() res = yield self.call('{}.echo'.format(prefix), ts_req) ts_res = time_ns() assert res == ts_req rtt = ts_res - ts_req rtts.append(rtt) stats = self._pinfo.get_stats() if last: batch_duration = (stats['time'] - last['time']) / 10**9 ctx = round( (stats['voluntary'] - last['voluntary']) / batch_duration, 0) self.log.info('{logname}: {cpu} cpu, {mem} mem, {ctx} ctx', logname=self._logname, cpu=round(stats['cpu_percent'], 1), mem=round(stats['mem_percent'], 1), ctx=ctx) rtts = sorted(rtts) sr = WampStatsRecord() sr.key = '{}#{}.{}'.format(batch_started_str, self._logname, index) sr.count = len(rtts) sr.calls_per_sec = int(round(sr.count / batch_duration, 0)) # all times here are in microseconds: sr.avg_rtt = round(1000000. * batch_duration / float(sr.count), 1) sr.max_rtt = round(rtts[-1] / 1000, 1) sr.q50_rtt = round(rtts[int(sr.count / 2.)] / 1000, 1) sr.q99_rtt = round(rtts[int(-(sr.count / 100.))] / 1000, 1) sr.q995_rtt = round(rtts[int(-(sr.count / 995.))] / 1000, 1) with self._db.begin(write=True) as txn: self._schema.wamp_stats[txn, sr.key] = sr print( "{}: {} calls, {} calls/sec, RTT (us): q50 {}, avg {}, q99 {}, q995 {}, max {}" .format(sr.key, sr.count, sr.calls_per_sec, sr.q50_rtt, sr.avg_rtt, sr.q99_rtt, sr.q995_rtt, sr.max_rtt)) last = stats
def _loop(self, index): prefix = self.config.extra['prefix'] last = None while self._running: rtts = [] batch_started_str = utcnow() batch_started = time() while (time() - batch_started) < self._period: ts_req = time_ns() res = yield self.call('{}.echo'.format(prefix), ts_req) ts_res = time_ns() assert res == ts_req rtt = ts_res - ts_req rtts.append(rtt) stats = self._pinfo.get_stats() if last: batch_duration = (stats['time'] - last['time']) / 10 ** 9 ctx = round((stats['voluntary'] - last['voluntary']) / batch_duration, 0) self.log.info('{logname}: {cpu} cpu, {mem} mem, {ctx} ctx', logname=self._logname, cpu=round(stats['cpu_percent'], 1), mem=round(stats['mem_percent'], 1), ctx=ctx) rtts = sorted(rtts) sr = WampStatsRecord() sr.key = '{}#{}.{}'.format(batch_started_str, self._logname, index) sr.count = len(rtts) sr.calls_per_sec = int(round(sr.count / batch_duration, 0)) # all times here are in microseconds: sr.avg_rtt = round(1000000. * batch_duration / float(sr.count), 1) sr.max_rtt = round(rtts[-1] / 1000, 1) sr.q50_rtt = round(rtts[int(sr.count / 2.)] / 1000, 1) sr.q99_rtt = round(rtts[int(-(sr.count / 100.))] / 1000, 1) sr.q995_rtt = round(rtts[int(-(sr.count / 995.))] / 1000, 1) with self._db.begin(write=True) as txn: self._schema.wamp_stats[txn, sr.key] = sr print("{}: {} calls, {} calls/sec, RTT (us): q50 {}, avg {}, q99 {}, q995 {}, max {}".format(sr.key, sr.count, sr.calls_per_sec, sr.q50_rtt, sr.avg_rtt, sr.q99_rtt, sr.q995_rtt, sr.max_rtt)) last = stats
def store_event(self, session, publication_id, publish): """ Store event to event history. :param session: The publishing session. :type session: :class:`autobahn.wamp.interfaces.ISession` :param publication_id: The WAMP publication ID under which the publish happens :type publication_id: int :param publish: The WAMP publish message. :type publish: :class:`autobahn.wamp.messages.Publish` """ assert (publication_id not in self._event_store) evt = { 'time_ns': time_ns(), 'realm': session._realm, 'session_id': session._session_id, 'authid': session._authid, 'authrole': session._authrole, 'publication': publication_id, 'topic': publish.topic, 'args': publish.args, 'kwargs': publish.kwargs } self._event_store[publication_id] = evt self.log.debug("Event {publication_id} stored in {store_type}-store", store_type=self.STORE_TYPE, publication_id=publication_id)
def poll(self): """ Measure current stats value and return new stats. Override in your derived submonitor class. :returns: Current stats from monitor. :rtype: dict """ self._tick += 1 now = time_ns() if self._last_poll: self._last_period = now - self._last_poll current = { 'tick': self._tick, # the UTC timestamp when measurement was taken 'timestamp': now, # the effective last period in ns 'last_period': self._last_period, # duration in seconds the retrieval of sensor values took 'elapsed': self._elapsed, } self._last_poll = now self._last_value = current return current
async def on_rotate(key_series): key_id = key_series.key_id self._keys_map[key_id] = key_series # FIXME: expose the knobs hard-coded in below .. # offer the key to the market maker (retry 5x in specific error cases) retries = 5 while retries: try: valid_from = time_ns() - 10 * 10 ** 9 delegate = self._addr # FIXME: sign the supplied offer information using self._pkey signature = os.urandom(65) provider_id = self._provider_id offer = await self._session.call('xbr.marketmaker.place_offer', key_id, api_id, prefix, valid_from, delegate, signature, privkey=None, price=pack_uint256(price) if price is not None else None, categories=categories, expires=None, copies=None, provider_id=provider_id) self.log.info( '{tx_type} key "{key_id}" offered for {price} [api_id={api_id}, prefix="{prefix}", delegate="{delegate}"]', tx_type=hl('XBR OFFER ', color='magenta'), key_id=hl(uuid.UUID(bytes=key_id)), api_id=hl(uuid.UUID(bytes=api_id)), price=hl(str(int(price / 10 ** 18) if price is not None else 0) + ' XBR', color='magenta'), delegate=hl(binascii.b2a_hex(delegate).decode()), prefix=hl(prefix)) self.log.debug('offer={offer}', offer=offer) break except ApplicationError as e: if e.error == 'wamp.error.no_such_procedure': self.log.warn('xbr.marketmaker.offer: procedure unavailable!') else: self.log.failure() break except TransportLost: self.log.warn('TransportLost while calling xbr.marketmaker.offer!') break except: self.log.failure() retries -= 1 self.log.warn('Failed to place offer for key! Retrying {retries}/5 ..', retries=retries) await asyncio.sleep(1)
def _rotate(self): self._id = os.urandom(16) self._key = nacl.utils.random(nacl.secret.SecretBox.KEY_SIZE) self._box = nacl.secret.SecretBox(self._key) self._archive[self._id] = (zlmdb.time_ns(), self._key, self._box) self.log.info('key rotated, new key_id={key_id}', key_id=uuid.UUID(bytes=self._id))
def get_stats(self): """ Get process statistics. """ res = {} res[u'ts'] = utcnow() res[u'time'] = time_ns() res[u'pid'] = self._pid s = self._p.num_ctx_switches() c = self._p.cpu_times() c_perc = self._p.cpu_percent() m = self._p.memory_info() m_perc = self._p.memory_percent() f = self._p.io_counters() # process status res[u'status'] = self._p.status() # context switches res[u'voluntary'] = s[0] res[u'nonvoluntary'] = s[1] # cpu res[u'user'] = c.user res[u'system'] = c.system res[u'cpu_percent'] = c_perc # memory res[u'resident'] = m.rss res[u'virtual'] = m.vms res[u'mem_percent'] = m_perc # disk res[u'reads'] = f.read_count res[u'writes'] = f.write_count return res
def poll(self, verbose=False): """ Measure current stats value and return new stats. :returns: A deferred that resolves with a dict containing new process statistics. :rtype: :class:`twisted.internet.defer.Deferred` """ self._tick += 1 now = time_ns() if self._last_poll: self._last_period = now - self._last_poll if verbose: _current = { 'tick': self._tick, # the UTC timestamp when measurement was taken 'timestamp': now, # the effective last period in ns 'last_period': self._last_period, # duration in seconds the retrieval of sensor values took 'elapsed': self._elapsed, } else: _current = {} # uptime, as all durations, is in ns _current['uptime'] = int(now - psutil.boot_time() * 10**9) def _poll(current, last_value): # normalize with effective period diff = 1. if self._last_period: diff = self._last_period / 10**9 # int values: bytes_sent, bytes_recv, packets_sent, packets_recv, errin, errout, dropin, dropout current['network'] = dict(psutil.net_io_counters()._asdict()) # int values: read_count, write_count, read_bytes, write_bytes, read_time, write_time, read_merged_count, write_merged_count, busy_time current['disk'] = dict(psutil.disk_io_counters()._asdict()) if last_value: for k in ['network', 'disk']: d = current[k] for k2 in list(d.keys()): value = float(d[k2] - last_value[k][k2]) / diff d['{}_per_sec'.format(k2)] = int(value) # float values: user, nice, system, idle, iowait, irq, softirq, streal, guest, guest_nice current['cp'] = dict( psutil.cpu_times_percent(interval=None)._asdict()) cpu_freq = psutil.cpu_freq() current['cp']['freq'] = round( cpu_freq.current) if cpu_freq else None s = psutil.cpu_stats() current['cp']['ctx_switches'] = s.ctx_switches current['cp']['interrupts'] = s.interrupts current['cp']['soft_interrupts'] = s.soft_interrupts # int values: total, available, used, free, active, inactive, buffers, cached, shared, slab # float values: percent current['memory'] = dict(psutil.virtual_memory()._asdict()) # Network connections res = {} conns = psutil.net_connections(kind='all') for c in conns: if c.family not in res: res[c.family] = 0 res[c.family] += 1 res2 = {} for f, cnt in res.items(): res2[f.name] = cnt current['network']['connection'] = res2 return current new_value = yield deferToThread(_poll, _current, self._last_value) self._elapsed = time_ns() - now new_value['elapsed'] = self._elapsed self._last_poll = now self._last_value = new_value returnValue(new_value)
def poll(self, verbose=False): """ Measure current stats value and return new stats. :returns: A deferred that resolves with a dict containing new process statistics. :rtype: :class:`twisted.internet.defer.Deferred` """ self._tick += 1 now = time_ns() if self._last_poll: self._last_period = now - self._last_poll if verbose: _current = { 'tick': self._tick, # the UTC timestamp when measurement was taken 'timestamp': now, # the effective last period in ns 'last_period': self._last_period, # duration in seconds the retrieval of sensor values took 'elapsed': self._elapsed, } else: _current = {} def _poll(current, last_value): # normalize with effective period diff = 1. if self._last_period: diff = self._last_period / 10**9 # cmd_started = time.time() current['type'] = self._worker_type current['pid'] = self._p.pid current['status'] = self._p.status() if verbose: current['exe'] = self._p.exe() current['user'] = self._p.username() current['name'] = self._p.name() current['cmdline'] = ' '.join(self._p.cmdline()) created = self._p.create_time() current['created'] = utcstr( datetime.datetime.fromtimestamp(created)) current['num_fds'] = self._p.num_fds() current['num_threads'] = self._p.num_threads() current['num_fds'] = self._p.num_fds() # the following values are cumulative since process creation! # num_ctx_switches = self._p.num_ctx_switches() current['num_ctx_switches_voluntary'] = num_ctx_switches.voluntary current[ 'num_ctx_switches_involuntary'] = num_ctx_switches.involuntary if self._has_io_counters: iocounters = self._p.io_counters() current['read_ios'] = iocounters.read_count current['write_ios'] = iocounters.write_count current['read_bytes'] = iocounters.read_bytes current['write_bytes'] = iocounters.write_bytes else: current['read_ios'] = None current['write_ios'] = None current['read_bytes'] = None current['write_bytes'] = None cpu = self._p.cpu_times() current['cpu_user'] = cpu.user current['cpu_system'] = cpu.system # current['command_duration'] = time.time() - cmd_started for key in [ 'read_ios', 'write_ios', 'read_bytes', 'write_bytes', 'cpu_user', 'cpu_system', 'num_ctx_switches_voluntary', 'num_ctx_switches_involuntary' ]: if last_value and last_value[key] is not None: value = float(current[key] - last_value[key]) / diff current['{}_per_sec'.format(key)] = int(value) return current new_value = yield deferToThread(_poll, _current, self._last_value) self._last_poll = now self._last_value = new_value returnValue(new_value)
def start_link(self, link_id, link_config, caller): assert type(link_id) == str assert isinstance(link_config, RLinkConfig) assert isinstance(caller, SessionIdent) if link_id in self._links: raise ApplicationError( 'crossbar.error.already_running', 'router link {} already running'.format(link_id)) # setup local session # local_extra = { 'other': None, 'on_ready': Deferred(), 'rlink': link_id, # 'forward_events': False, 'forward_events': link_config.forward_local_events, } local_realm = self._realm.config['name'] local_authid = link_config.authid or util.generate_serial_number() local_authrole = 'trusted' local_config = ComponentConfig(local_realm, local_extra) local_session = RLinkLocalSession(local_config) # setup remote session # remote_extra = { 'rlink_manager': self, 'other': None, 'on_ready': Deferred(), 'authid': link_config.authid, 'exclude_authid': link_config.exclude_authid, 'forward_events': link_config.forward_remote_events, 'forward_invocations': link_config.forward_remote_invocations, } remote_realm = link_config.realm remote_config = ComponentConfig(remote_realm, remote_extra) remote_session = RLinkRemoteSession(remote_config) # cross-connect the two sessions # local_extra['other'] = remote_session remote_extra['other'] = local_session # the rlink # rlink = RLink(link_id, link_config) self._links[link_id] = rlink # create connecting client endpoint # connecting_endpoint = create_connecting_endpoint_from_config( link_config.transport['endpoint'], self._controller.cbdir, self._controller._reactor, self.log) try: # connect the local session # self._realm.controller.router_session_factory.add( local_session, self._realm.router, authid=local_authid, authrole=local_authrole, authextra=local_extra) yield local_extra['on_ready'] # connect the remote session # # remote connection parameters to ApplicationRunner: # # url: The WebSocket URL of the WAMP router to connect to (e.g. ws://somehost.com:8090/somepath) # realm: The WAMP realm to join the application session to. # extra: Optional extra configuration to forward to the application component. # serializers: List of :class:`autobahn.wamp.interfaces.ISerializer` (or None for default serializers). # ssl: None or :class:`twisted.internet.ssl.CertificateOptions` # proxy: Explicit proxy server to use; a dict with ``host`` and ``port`` keys # headers: Additional headers to send (only applies to WAMP-over-WebSocket). # max_retries: Maximum number of reconnection attempts. Unlimited if set to -1. # initial_retry_delay: Initial delay for reconnection attempt in seconds (Default: 1.0s). # max_retry_delay: Maximum delay for reconnection attempts in seconds (Default: 60s). # retry_delay_growth: The growth factor applied to the retry delay between reconnection attempts (Default 1.5). # retry_delay_jitter: A 0-argument callable that introduces nose into the delay. (Default random.random) # remote_runner = ApplicationRunner(url=link_config.transport['url'], realm=remote_realm, extra=remote_extra) yield remote_runner.run(remote_session, start_reactor=False, auto_reconnect=True, endpoint=connecting_endpoint, reactor=self._controller._reactor) yield remote_extra['on_ready'] except: # make sure to remove the half-initialized link from our map .. del self._links[link_id] # .. and then re-raise raise # the router link is established: store final infos rlink.started = time_ns() rlink.started_by = caller rlink.local = local_session rlink.remote = remote_session return rlink
def _sender_loop(self, loopname, enable_publish=True, enable_call=True): loop = 0 while self._running: started = time_ns() dl = [] for counter in range(self._stride): payload = os.urandom(self._size) fingerprint = hashlib.sha256(payload).digest()[:6] if enable_publish: d = self.publish(HATestClientSession.TEST_TOPIC, self._logname, self._url, loop, counter, payload, options=PublishOptions(acknowledge=True, exclude_me=False)) dl.append(d) self._published_cnt += 1 self._published_bytes += len(payload) self.log.debug( '{logprefix}: EVENT sent from session={session}, authid={authid}, authrole={authrole} -> loop={loop}, counter={counter}, len={payload_len}, fp={fp}', logprefix=hl('WAMP {}:{}'.format( self._url, self._logname), color='green', bold=True), session=hl(self._session_id, color='green', bold=True), authid=hl(self._authid, color='green', bold=True), authrole=hl(self._authrole, color='green', bold=True), loop=loop, counter=counter, topic=HATestClientSession.TEST_TOPIC, payload_len=len(payload), fp=hl(binascii.b2a_hex(fingerprint).decode(), color='green', bold=True)) if enable_call: for uri in [ 'node{}.container1.proc1'.format(i + 1) for i in range(4) ]: d = self.call(uri, self._logname, self._url, loop, counter, payload, options=CallOptions(details=True)) def check_result(result, uri): print('-' * 100, result) _fingerprint, _pid, _logname, _url = result.results[ 0] self.log.info( '{logprefix}: CALL RESULT for {uri} received from pid={pid}, logname={logname}, url={url}, callee={callee}, callee_authid={callee_authid}, callee_authrole={callee_authrole}, forward_for={forward_for}, fp={fp} => fp_equal={fp_equal}', logprefix=hl('WAMP {}:{}'.format( self._url, self._logname), color='green', bold=True), pid=hl(_pid, color='green', bold=True), logname=_logname, url=_url, fp=hl(binascii.b2a_hex(fingerprint).decode(), color='green', bold=True), fp_equal=(_fingerprint == fingerprint), uri=hl(uri, color='yellow', bold=True), callee=result.callee, callee_authid=result.callee_authid, callee_authrole=result.callee_authrole, forward_for=result.forward_for) assert _fingerprint == fingerprint def error(err): print(err) d.addCallbacks(check_result, error, (uri, )) dl.append(d) self._calls_cnt += 1 self._calls_bytes += len(payload) self.log.info( '{logprefix}: CALL issued to {uri} from pid={pid}, session={session}, authid={authid}, authrole={authrole} -> loop={loop}, counter={counter}, len={payload_len}, fp={fp}', logprefix=hl('WAMP {}:{}'.format( self._url, self._logname), color='green', bold=True), pid=hl(self._pid, color='green', bold=True), session=hl(self._session_id, color='green', bold=True), authid=hl(self._authid, color='green', bold=True), authrole=hl(self._authrole, color='green', bold=True), uri=hl(uri, color='yellow', bold=True), loop=loop, counter=counter, procedure=HATestClientSession.TEST_PROC, payload_len=len(payload), fp=hl(binascii.b2a_hex(fingerprint).decode(), color='green', bold=True)) d = gatherResults(dl) try: yield d except TransportLost: self.log.error('Transport lost!') self.leave() return duration = (time_ns() - started) / 10**9 sleep_secs = (1 / float(self._rate)) - duration if sleep_secs > 0: yield sleep(sleep_secs) loop += 1
def _loop(self, batch_id, index): prefix = self.config.extra['prefix'] while self._running: rtts = [] self.log.debug( '{logprefix} is starting new period ..', logprefix=hl(' {}.{}'.format(self._logname, index), color='magenta', bold=True), ) batch_started = time_ns() while float(time_ns() - batch_started) / 10**9 < self._period: ts_req = time_ns() res = yield self.call('{}.echo'.format(prefix), ts_req) ts_res = time_ns() assert res == ts_req rtt = ts_res - ts_req rtts.append(rtt) batch_duration = float(time_ns() - batch_started) / 10**9 rtts = sorted(rtts) sr = WampStatsRecord() sr.worker = int(self._logname.split('.')[1]) sr.loop = index sr.count = len(rtts) sr.calls_per_sec = int(round(sr.count / batch_duration, 0)) # all times here are in microseconds: sr.avg_rtt = int( round(1000000. * batch_duration / float(sr.count), 0)) sr.max_rtt = int(round(rtts[-1] / 1000, 0)) sr.q50_rtt = int(round(rtts[int(sr.count / 2.)] / 1000, 0)) sr.q99_rtt = int(round(rtts[int(-(sr.count / 100.))] / 1000, 0)) sr.q995_rtt = int(round(rtts[int(-(sr.count / 995.))] / 1000, 0)) try: with self._db.begin(write=True) as txn: self._schema.wamp_stats[txn, ( batch_id, np.datetime64(batch_started, 'ns'))] = sr except: self.log.failure() return self.leave() self.log.info( "{logprefix}: {count} calls, {calls_per_sec}, round-trip time (microseconds): q50 {q50_rtt}, avg {avg_rtt}, {q99_rtt}, q995 {q995_rtt}, max {max_rtt}" .format(logprefix=hl('WAMP {}.{}'.format(self._logname, index), color='magenta', bold=True), count=sr.count, calls_per_sec=hl('{} calls/second'.format( sr.calls_per_sec), bold=True), q50_rtt=sr.q50_rtt, avg_rtt=sr.avg_rtt, q99_rtt=hl('q99 {}'.format(sr.q99_rtt), bold=True), q995_rtt=sr.q995_rtt, max_rtt=sr.max_rtt))
def poll(self, verbose=False): """ Measure current stats value and return new stats. :returns: A deferred that resolves with a dict containing new process statistics. :rtype: :class:`twisted.internet.defer.Deferred` """ self._tick += 1 now = time_ns() if self._last_poll: self._last_period = now - self._last_poll if verbose: _current = { 'tick': self._tick, # the UTC timestamp when measurement was taken 'timestamp': now, # the effective last period in ns 'last_period': self._last_period, # duration in seconds the retrieval of sensor values took 'elapsed': self._elapsed, } else: _current = {} # uptime, as all durations, is in ns _current['uptime'] = int(now - psutil.boot_time() * 10**9) def _poll(current, last_value): # normalize with effective period diff = 1. if self._last_period: diff = self._last_period / 10**9 # int values: bytes_sent, bytes_recv, packets_sent, packets_recv, errin, errout, dropin, dropout current['network'] = dict(psutil.net_io_counters()._asdict()) # int values: read_count, write_count, read_bytes, write_bytes, read_time, write_time, read_merged_count, write_merged_count, busy_time current['disk'] = dict(psutil.disk_io_counters()._asdict()) if last_value: for k in ['network', 'disk']: d = current[k] for k2 in list(d.keys()): value = float(d[k2] - last_value[k][k2]) / diff d['{}_per_sec'.format(k2)] = int(value) # float values: user, nice, system, idle, iowait, irq, softirq, streal, guest, guest_nice current['cp'] = dict(psutil.cpu_times_percent(interval=None)._asdict()) cpu_freq = psutil.cpu_freq() current['cp']['freq'] = round(cpu_freq.current) if cpu_freq else None s = psutil.cpu_stats() current['cp']['ctx_switches'] = s.ctx_switches current['cp']['interrupts'] = s.interrupts current['cp']['soft_interrupts'] = s.soft_interrupts # int values: total, available, used, free, active, inactive, buffers, cached, shared, slab # float values: percent current['memory'] = dict(psutil.virtual_memory()._asdict()) # Network connections res = {} conns = psutil.net_connections(kind='all') for c in conns: if c.family not in res: res[c.family] = 0 res[c.family] += 1 res2 = {} for f, cnt in res.items(): res2[f.name] = cnt current['network']['connection'] = res2 return current new_value = yield deferToThread(_poll, _current, self._last_value) self._elapsed = time_ns() - now new_value['elapsed'] = self._elapsed self._last_poll = now self._last_value = new_value returnValue(new_value)
def poll(self, verbose=False): """ Measure current stats value and return new stats. :returns: A deferred that resolves with a dict containing new process statistics. :rtype: :class:`twisted.internet.defer.Deferred` """ self._tick += 1 now = time_ns() if self._last_poll: self._last_period = now - self._last_poll if verbose: _current = { 'tick': self._tick, # the UTC timestamp when measurement was taken 'timestamp': now, # the effective last period in ns 'last_period': self._last_period, # duration in seconds the retrieval of sensor values took 'elapsed': self._elapsed, } else: _current = {} def _poll(current, last_value): # normalize with effective period diff = 1. if self._last_period: diff = self._last_period / 10**9 # cmd_started = time.time() current['type'] = self._worker_type current['pid'] = self._p.pid current['status'] = self._p.status() if verbose: current['exe'] = self._p.exe() current['user'] = self._p.username() current['name'] = self._p.name() current['cmdline'] = ' '.join(self._p.cmdline()) created = self._p.create_time() current['created'] = utcstr(datetime.datetime.fromtimestamp(created)) current['num_fds'] = self._p.num_fds() current['num_threads'] = self._p.num_threads() current['num_fds'] = self._p.num_fds() # the following values are cumulative since process creation! # num_ctx_switches = self._p.num_ctx_switches() current['num_ctx_switches_voluntary'] = num_ctx_switches.voluntary current['num_ctx_switches_involuntary'] = num_ctx_switches.involuntary if self._has_io_counters: iocounters = self._p.io_counters() current['read_ios'] = iocounters.read_count current['write_ios'] = iocounters.write_count current['read_bytes'] = iocounters.read_bytes current['write_bytes'] = iocounters.write_bytes else: current['read_ios'] = None current['write_ios'] = None current['read_bytes'] = None current['write_bytes'] = None cpu = self._p.cpu_times() current['cpu_user'] = cpu.user current['cpu_system'] = cpu.system # current['command_duration'] = time.time() - cmd_started for key in [ 'read_ios', 'write_ios', 'read_bytes', 'write_bytes', 'cpu_user', 'cpu_system', 'num_ctx_switches_voluntary', 'num_ctx_switches_involuntary' ]: if last_value and last_value[key] is not None: value = float(current[key] - last_value[key]) / diff current['{}_per_sec'.format(key)] = int(value) return current new_value = yield deferToThread(_poll, _current, self._last_value) self._last_poll = now self._last_value = new_value returnValue(new_value)