如何在 Linux 中的 python 中检索进程启动时间(或正常运行时间)?
我只知道,我可以调用“ps -p my_process_id -f”,然后解析输出。但这并不酷。
使用 psutil https://github.com/giampaolo/psutil:
>>> import psutil, os, time
>>> p = psutil.Process(os.getpid())
>>> p.create_time()
1293678383.0799999
>>> time.strftime("%Y-%m-%d %H:%M:%S", time.localtime(p.create_time()))
'2010-12-30 04:06:23'
>>>
...加上它是跨平台的,不仅仅是Linux。
注意:我是该项目的作者之一。
如果您是在要测量的 python 程序中执行此操作,则可以执行以下操作:
import time
# at the beginning of the script
startTime = time.time()
# ...
def getUptime():
"""
Returns the number of seconds since the program started.
"""
# do return startTime if you just want the process start time
return time.time() - startTime
否则,你别无选择,只能解析
ps
或进入/proc/pid
。获取经过时间的一个很好的bash
方法是:
ps -eo pid,etime | grep $YOUR_PID | awk '{print $2}'
这只会以以下格式打印经过的时间,因此应该很容易解析:
days-HH:MM:SS
(如果运行时间不到一天,那就只是
HH:MM:SS
)
开始时间如下所示:
ps -eo pid,stime | grep $YOUR_PID | awk '{print $2}'
不幸的是,如果您的流程今天没有开始,这只会为您提供开始的日期,而不是时间。
最好的方法是获取经过的时间和当前时间,然后做一些数学计算。以下是一个 python 脚本,它采用 PID 作为参数,并为您执行上述操作,打印出进程的开始日期和时间:
import sys
import datetime
import time
import subprocess
# call like this: python startTime.py $PID
pid = sys.argv[1]
proc = subprocess.Popen(['ps','-eo','pid,etime'], stdout=subprocess.PIPE)
# get data from stdout
proc.wait()
results = proc.stdout.readlines()
# parse data (should only be one)
for result in results:
try:
result.strip()
if result.split()[0] == pid:
pidInfo = result.split()[1]
# stop after the first one we find
break
except IndexError:
pass # ignore it
else:
# didn't find one
print "Process PID", pid, "doesn't seem to exist!"
sys.exit(0)
pidInfo = [result.split()[1] for result in results
if result.split()[0] == pid][0]
pidInfo = pidInfo.partition("-")
if pidInfo[1] == '-':
# there is a day
days = int(pidInfo[0])
rest = pidInfo[2].split(":")
hours = int(rest[0])
minutes = int(rest[1])
seconds = int(rest[2])
else:
days = 0
rest = pidInfo[0].split(":")
if len(rest) == 3:
hours = int(rest[0])
minutes = int(rest[1])
seconds = int(rest[2])
elif len(rest) == 2:
hours = 0
minutes = int(rest[0])
seconds = int(rest[1])
else:
hours = 0
minutes = 0
seconds = int(rest[0])
# get the start time
secondsSinceStart = days*24*3600 + hours*3600 + minutes*60 + seconds
# unix time (in seconds) of start
startTime = time.time() - secondsSinceStart
# final result
print "Process started on",
print datetime.datetime.fromtimestamp(startTime).strftime("%a %b %d at %I:%M:%S %p")
man proc
表示/proc/my_process_id/stat
中的第22项是:
starttime %lu
系统启动后进程开始的时间(以 jiffies 为单位)。
你现在的问题是,如何确定一个jiffy的长度以及如何确定系统何时启动。
后者的答案仍然来自
man proc
:它在/proc/stat
中,在它自己的一行中,如下所示:
btime 1270710844
这是自纪元以来以秒为单位的测量值。
man 7 time
说:
软件时钟、HZ 和 Jiffies
许多系统调用和时间戳的准确性受到软件时钟分辨率的限制,软件时钟是由内核维护的时钟,以 jiffies 为单位测量时间。 jiffy 的大小由内核常量
的值决定。HZ
的值因内核版本和硬件平台而异。在 x86 上,情况如下:在 2.4.x 及之前的内核上,HZ
为 100,给出的 jiffy 值为 0.01 秒;从 2.6.0 开始,HZ
提高到 1000,即 0.001 秒的 jiffy;从内核 2.6.13 开始,HZ
值是一个内核配置参数,可以是 100、250(默认)或 1000,分别产生 0.01、0.004 或 0.001 秒的 jiffies 值。HZ
我们需要找到
HZ
,但我不知道如何从 Python 中实现这一点,除了希望该值为 250(正如维基百科声称是默认值)。
ps
由此获得:
/* sysinfo.c init_libproc() */
if(linux_version_code > LINUX_VERSION(2, 4, 0)){
Hertz = find_elf_note(AT_CLKTCK);
//error handling
}
old_Hertz_hack(); //ugh
这听起来像是 Python 的一个非常小的 C 模块做得很好的工作:)
这是基于 badp 答案的代码:
import os
from time import time
HZ = os.sysconf(os.sysconf_names['SC_CLK_TCK'])
def proc_age_secs():
system_stats = open('/proc/stat').readlines()
process_stats = open('/proc/self/stat').read().split()
for line in system_stats:
if line.startswith('btime'):
boot_timestamp = int(line.split()[1])
age_from_boot_jiffies = int(process_stats[21])
age_from_boot_timestamp = age_from_boot_jiffies / HZ
age_timestamp = boot_timestamp + age_from_boot_timestamp
return time() - age_timestamp
我不确定这是否正确。我编写了一个测试程序,该程序调用 sleep(5),然后运行它,但输出是错误的,并且每次运行的输出都会在几秒钟内变化。这是在 vmware 工作站虚拟机中:
if __name__ == '__main__':
from time import sleep
sleep(5)
print proc_age_secs()
输出为:
$ time python test.py
6.19169998169
real 0m5.063s
user 0m0.020s
sys 0m0.036s
def proc_starttime(pid=os.getpid()):
# https://gist.github.com/westhood/1073585
p = re.compile(r"^btime (\d+)$", re.MULTILINE)
with open("/proc/stat") as f:
m = p.search(f.read())
btime = int(m.groups()[0])
clk_tck = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
with open("/proc/%d/stat" % pid) as f:
stime = int(f.read().split()[21]) / clk_tck
return datetime.fromtimestamp(btime + stime)
此实现基于 Dan Benamy 的回答,并通过使用以秒为单位的正常运行时间而不是自纪元以来的以秒为单位的启动时间来简化。该方法已使用 Python 2 和 3 进行了测试。
import os
import time
def processRealTimeSeconds():
uptimeSeconds = float(open("/proc/uptime").readline().split()[0])
procStartJif = float(open("/proc/self/stat").readline().split()[21])
clockTicks = os.sysconf(os.sysconf_names["SC_CLK_TCK"])
procStartSecondsBoot = procStartJif / clockTicks
return uptimeSeconds - procStartSecondsBoot
if __name__ == '__main__':
time.sleep(5)
print("Real process time: {} s".format(processRealTimeSeconds()))
输出:
$ time ./processTime.py
Real process time: 5.060000000012224 s
real 0m5.059s
user 0m0.041s
sys 0m0.013s
附录:您不能期望此代码具有毫秒精度。除了
/proc
接口提供的时间戳分辨率有限之外,执行总是有可能被任务切换中断。然而,它可能可以通过将代码拆分为首先读取原始数据,然后进行转换和计算来改进,但代价是代码不那么简洁,行数更多。
你可以解析
/proc/uptime
>>> uptime, idletime = [float(f) for f in open("/proc/uptime").read().split()]
>>> print uptime
29708.1
>>> print idletime
26484.45
对于 Windows 机器,您可能可以使用 wmi
import wmi
c = wmi.WMI()
secs_up = int([uptime.SystemUpTime for uptime in c.Win32_PerfFormattedData_PerfOS_System()][0])
hours_up = secs_up / 3600
print hours_up