def test_get_stats(self): """ Tests get_stats() with all combinations of stat_type arguments. """ # list of all combinations of args with respective return values stat_combinations = mocking.get_all_combinations([ ('command', 'test_program'), ('utime', '0.13'), ('stime', '0.14'), ('start time', '10.21'), ]) stat_path = "/proc/24062/stat" stat = '1 (test_program) 2 3 4 5 6 7 8 9 10 11 12 13.0 14.0 15 16 17 18 19 20 21.0 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43' mocking.mock(proc.get_system_start_time, mocking.return_value(10)) # tests the case where no stat_types are specified mocking.mock(proc._get_line, mocking.return_for_args({ (stat_path, '24062', 'process '): stat })) self.assertEquals((), proc.get_stats(24062)) for stats in stat_combinations: # the stats variable is... # [(arg1, resp1), (arg2, resp2)...] # # but we need... # (arg1, arg2...), (resp1, resp2...). args, response = zip(*stats) mocking.mock(proc._get_line, mocking.return_for_args({ (stat_path, '24062', 'process %s' % ', '.join(args)): stat })) self.assertEquals(response, proc.get_stats(24062, *args)) # tests the case where pid = 0 if 'start time' in args: response = 10 else: response = () for arg in args: if arg == 'command': response += ('sched',) elif arg == 'utime': response += ('0',) elif arg == 'stime': response += ('0',) mocking.mock(proc._get_line, mocking.return_for_args({ ('/proc/0/stat', '0', 'process %s' % ', '.join(args)): stat })) self.assertEquals(response, proc.get_stats(0, *args))
def test_get_stats(self): """ Checks that stem.util.proc.get_stats looks somewhat reasonable. """ if not proc.is_available(): test.runner.skip(self, "(proc unavailable)") return tor_pid = test.runner.get_runner().get_pid() command, utime, stime, start_time = proc.get_stats(tor_pid, 'command', 'utime', 'stime', 'start time') self.assertEquals('tor', command) self.assertTrue(utime > 0) self.assertTrue(stime > 0) self.assertTrue(start_time > proc.get_system_start_time())
def test_get_stats(self): """ Checks that stem.util.proc.get_stats looks somewhat reasonable. """ if not proc.is_available(): test.runner.skip(self, "(proc unavailable)") return tor_pid = test.runner.get_runner().get_pid() command, utime, stime, start_time = proc.get_stats(tor_pid, 'command', 'utime', 'stime', 'start time') self.assertEquals('tor', command) self.assertTrue(float(utime) > 0) self.assertTrue(float(stime) > 0) self.assertTrue(float(start_time) > proc.get_system_start_time())
def getProcessName(pid, default=None, cacheFailure=True): """ Provides the name associated with the given process id. This isn't available on all platforms. Arguments: pid - process id for the process being returned default - result if the process name can't be retrieved (raises an IOError on failure instead if undefined) cacheFailure - if the lookup fails and there's a default then caches the default value to prevent further lookups """ if pid in PROCESS_NAME_CACHE: return PROCESS_NAME_CACHE[pid] processName, raisedExc = "", None # fetch it from proc contents if available if proc.is_available(): try: processName = proc.get_stats(pid, proc.Stat.COMMAND)[0] except IOError, exc: raisedExc = exc
def getProcessName(pid, default = None, cacheFailure = True): """ Provides the name associated with the given process id. This isn't available on all platforms. Arguments: pid - process id for the process being returned default - result if the process name can't be retrieved (raises an IOError on failure instead if undefined) cacheFailure - if the lookup fails and there's a default then caches the default value to prevent further lookups """ if pid in PROCESS_NAME_CACHE: return PROCESS_NAME_CACHE[pid] processName, raisedExc = "", None # fetch it from proc contents if available if proc.is_available(): try: processName = proc.get_stats(pid, proc.Stat.COMMAND)[0] except IOError, exc: raisedExc = exc
def run(self): while not self._halt: timeSinceReset = time.time() - self.lastLookup if self.resolveRate == 0: self._cond.acquire() if not self._halt: self._cond.wait(0.2) self._cond.release() continue elif timeSinceReset < self.resolveRate: sleepTime = max(0.2, self.resolveRate - timeSinceReset) self._cond.acquire() if not self._halt: self._cond.wait(sleepTime) self._cond.release() continue # done waiting, try again newValues = {} try: if self._useProc: utime, stime, startTime = proc.get_stats( self.processPid, proc.Stat.CPU_UTIME, proc.Stat.CPU_STIME, proc.Stat.START_TIME) totalCpuTime = float(utime) + float(stime) cpuDelta = totalCpuTime - self._lastCpuTotal newValues["cpuSampling"] = cpuDelta / timeSinceReset newValues["cpuAvg"] = totalCpuTime / (time.time() - float(startTime)) newValues["_lastCpuTotal"] = totalCpuTime memUsage = int(proc.get_memory_usage(self.processPid)[0]) totalMemory = proc.get_physical_memory() newValues["memUsage"] = memUsage newValues["memUsagePercentage"] = float( memUsage) / totalMemory else: # the ps call formats results as: # # TIME ELAPSED RSS %MEM # 3-08:06:32 21-00:00:12 121844 23.5 # # or if Tor has only recently been started: # # TIME ELAPSED RSS %MEM # 0:04.40 37:57 18772 0.9 psCall = system.call( "ps -p %s -o cputime,etime,rss,%%mem" % self.processPid) isSuccessful = False if psCall and len(psCall) >= 2: stats = psCall[1].strip().split() if len(stats) == 4: try: totalCpuTime = str_tools.parse_short_time_label( stats[0]) uptime = str_tools.parse_short_time_label( stats[1]) cpuDelta = totalCpuTime - self._lastCpuTotal newValues[ "cpuSampling"] = cpuDelta / timeSinceReset newValues["cpuAvg"] = totalCpuTime / uptime newValues["_lastCpuTotal"] = totalCpuTime newValues["memUsage"] = int( stats[2]) * 1024 # ps size is in kb newValues["memUsagePercentage"] = float( stats[3]) / 100.0 isSuccessful = True except ValueError, exc: pass if not isSuccessful: raise IOError("unrecognized output from ps: %s" % psCall) except IOError, exc: newValues = {} self._failureCount += 1 if self._useProc: if self._failureCount >= 3: # We've failed three times resolving via proc. Warn, and fall back # to ps resolutions. log.info( "Failed three attempts to get process resource usage from proc, falling back to ps (%s)" % exc) self._useProc = False self._failureCount = 1 # prevents lastQueryFailed() from thinking that we succeeded else: # wait a bit and try again log.debug( "Unable to query process resource usage from proc (%s)" % exc) self._cond.acquire() if not self._halt: self._cond.wait(0.5) self._cond.release() else: # exponential backoff on making failed ps calls sleepTime = 0.01 * ( 2**self._failureCount) + self._failureCount log.debug( "Unable to query process resource usage from ps, waiting %0.2f seconds (%s)" % (sleepTime, exc)) self._cond.acquire() if not self._halt: self._cond.wait(sleepTime) self._cond.release() # sets the new values if newValues: # If this is the first run then the cpuSampling stat is meaningless # (there isn't a previous tick to sample from so it's zero at this # point). Setting it to the average, which is a fairer estimate. if self.lastLookup == -1: newValues["cpuSampling"] = newValues["cpuAvg"] self._valLock.acquire() self.cpuSampling = newValues["cpuSampling"] self.cpuAvg = newValues["cpuAvg"] self.memUsage = newValues["memUsage"] self.memUsagePercentage = newValues["memUsagePercentage"] self._lastCpuTotal = newValues["_lastCpuTotal"] self.lastLookup = time.time() self._runCount += 1 self._failureCount = 0 self._valLock.release()
def run(self): while not self._halt: timeSinceReset = time.time() - self.lastLookup if self.resolveRate == 0: self._cond.acquire() if not self._halt: self._cond.wait(0.2) self._cond.release() continue elif timeSinceReset < self.resolveRate: sleepTime = max(0.2, self.resolveRate - timeSinceReset) self._cond.acquire() if not self._halt: self._cond.wait(sleepTime) self._cond.release() continue # done waiting, try again newValues = {} try: if self._useProc: utime, stime, startTime = proc.get_stats(self.processPid, proc.Stat.CPU_UTIME, proc.Stat.CPU_STIME, proc.Stat.START_TIME) totalCpuTime = float(utime) + float(stime) cpuDelta = totalCpuTime - self._lastCpuTotal newValues["cpuSampling"] = cpuDelta / timeSinceReset newValues["cpuAvg"] = totalCpuTime / (time.time() - float(startTime)) newValues["_lastCpuTotal"] = totalCpuTime memUsage = int(proc.get_memory_usage(self.processPid)[0]) totalMemory = proc.get_physical_memory() newValues["memUsage"] = memUsage newValues["memUsagePercentage"] = float(memUsage) / totalMemory else: # the ps call formats results as: # # TIME ELAPSED RSS %MEM # 3-08:06:32 21-00:00:12 121844 23.5 # # or if Tor has only recently been started: # # TIME ELAPSED RSS %MEM # 0:04.40 37:57 18772 0.9 psCall = system.call("ps -p %s -o cputime,etime,rss,%%mem" % self.processPid) isSuccessful = False if psCall and len(psCall) >= 2: stats = psCall[1].strip().split() if len(stats) == 4: try: totalCpuTime = str_tools.parse_short_time_label(stats[0]) uptime = str_tools.parse_short_time_label(stats[1]) cpuDelta = totalCpuTime - self._lastCpuTotal newValues["cpuSampling"] = cpuDelta / timeSinceReset newValues["cpuAvg"] = totalCpuTime / uptime newValues["_lastCpuTotal"] = totalCpuTime newValues["memUsage"] = int(stats[2]) * 1024 # ps size is in kb newValues["memUsagePercentage"] = float(stats[3]) / 100.0 isSuccessful = True except ValueError, exc: pass if not isSuccessful: raise IOError("unrecognized output from ps: %s" % psCall) except IOError, exc: newValues = {} self._failureCount += 1 if self._useProc: if self._failureCount >= 3: # We've failed three times resolving via proc. Warn, and fall back # to ps resolutions. log.info("Failed three attempts to get process resource usage from proc, falling back to ps (%s)" % exc) self._useProc = False self._failureCount = 1 # prevents lastQueryFailed() from thinking that we succeeded else: # wait a bit and try again log.debug("Unable to query process resource usage from proc (%s)" % exc) self._cond.acquire() if not self._halt: self._cond.wait(0.5) self._cond.release() else: # exponential backoff on making failed ps calls sleepTime = 0.01 * (2 ** self._failureCount) + self._failureCount log.debug("Unable to query process resource usage from ps, waiting %0.2f seconds (%s)" % (sleepTime, exc)) self._cond.acquire() if not self._halt: self._cond.wait(sleepTime) self._cond.release() # sets the new values if newValues: # If this is the first run then the cpuSampling stat is meaningless # (there isn't a previous tick to sample from so it's zero at this # point). Setting it to the average, which is a fairer estimate. if self.lastLookup == -1: newValues["cpuSampling"] = newValues["cpuAvg"] self._valLock.acquire() self.cpuSampling = newValues["cpuSampling"] self.cpuAvg = newValues["cpuAvg"] self.memUsage = newValues["memUsage"] self.memUsagePercentage = newValues["memUsagePercentage"] self._lastCpuTotal = newValues["_lastCpuTotal"] self.lastLookup = time.time() self._runCount += 1 self._failureCount = 0 self._valLock.release()