如何在 python 中检索进程启动时间(或正常运行时间)

发布于 2024-08-27 17:49:18 字数 103 浏览 8 评论 0原文

如何在 Linux 中的 python 中检索进程启动时间(或正常运行时间)?

我只知道,我可以调用“ps -p my_process_id -f”,然后解析输出。但这并不酷。

How to retrieve the process start time (or uptime) in python in Linux?

I only know, I can call "ps -p my_process_id -f" and then parse the output. But it is not cool.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

打小就很酷 2024-09-03 17:49:18

通过使用 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。

注意:我是这个项目的作者之一。

By using 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'
>>>

...plus it's cross platform, not only Linux.

NB: I am one of the authors of this project.

我不会写诗 2024-09-03 17:49:18

如果您是在要测量的 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。获取经过时间的一个很好的 bashy 方法是:

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")

If you are doing it from within the python program you're trying to measure, you could do something like this:

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

Otherwise, you have no choice but to parse ps or go into /proc/pid. A nice bashy way of getting the elapsed time is:

ps -eo pid,etime | grep $YOUR_PID | awk '{print $2}'

This will only print the elapsed time in the following format, so it should be quite easy to parse:

days-HH:MM:SS

(if it's been running for less than a day, it's just HH:MM:SS)

The start time is available like this:

ps -eo pid,stime | grep $YOUR_PID | awk '{print $2}'

Unfortunately, if your process didn't start today, this will only give you the date that it started, rather than the time.

The best way of doing this is to get the elapsed time and the current time and just do a bit of math. The following is a python script that takes a PID as an argument and does the above for you, printing out the start date and time of the process:

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")
一城柳絮吹成雪 2024-09-03 17:49:18

man proc 表示 / 中的第 22 项proc/my_process_id/stat 是:

开始时间%lu

系统启动后进程启动的时间(以 jiffies 为单位)。

您现在的问题是,如何确定 jiffy 的长度以及如何确定系统何时启动。

后者的答案仍然来自 man proc:它在 /proc/stat 中,在它自己的一行中,如下所示:

btime 1270710844

这是自纪元以来以秒为单位的测量。


前者的答案我不确定。 man 7 time 说:

软件时钟、HZ 和 Jiffies

许多系统调用和时间戳的准确性受到软件时钟分辨率的限制,软件时钟是由内核维护的时钟,以 jiffies 为单位测量时间。 jiffy 的大小由内核常量 HZ 的值决定。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,但我不知道如何从 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 模块做得很好的工作:)

man proc says that the 22nd item in /proc/my_process_id/stat is:

starttime %lu

The time in jiffies the process started after system boot.

Your problem now is, how to determine the length of a jiffy and how to determine when the system booted.

The answer for the latter comes still from man proc: it's in /proc/stat, on a line of its own like this:

btime 1270710844

That's a measurement in seconds since Epoch.


The answer for the former I'm not sure about. man 7 time says:

The Software Clock, HZ, and Jiffies

The accuracy of many system calls and timestamps is limited by the resolution of the software clock, a clock maintained by the kernel which measures time in jiffies. The size of a jiffy is determined by the value of the kernel constant HZ. The value of HZ varies across kernel versions and hardware platforms. On x86 the situation is as follows: on kernels up to and including 2.4.x, HZ was 100, giving a jiffy value of 0.01 seconds; starting with 2.6.0, HZ was raised to 1000, giving a jiffy of 0.001 seconds; since kernel 2.6.13, the HZ value is a kernel configuration parameter and can be 100, 250 (the default) or 1000, yielding a jiffies value of, respectively, 0.01, 0.004, or 0.001 seconds.

We need to find HZ, but I have no idea on how I'd go about that from Python except for hoping the value is 250 (as Wikipedia claims is the default).

ps obtains it thus:

  /* 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

This sounds like a job well done by a very small C module for Python :)

愁以何悠 2024-09-03 17:49:18

这是基于 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 工作站 vm 中:

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

Here's code based on badp's answer:

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

I'm not sure if it's right though. I wrote a test program that calls sleep(5) and then runs it and the output is wrong and varies over a couple of seconds from run to run. This is in a vmware workstation vm:

if __name__ == '__main__':
    from time import sleep
    sleep(5)
    print proc_age_secs()

The output is:

$ time python test.py
6.19169998169

real    0m5.063s
user    0m0.020s
sys     0m0.036s
不甘平庸 2024-09-03 17:49:18
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)
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)
野侃 2024-09-03 17:49:18

此实现基于 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 接口提供的时间戳分辨率有限之外,执行总是有可能被任务切换中断。然而,它可能可以通过将代码拆分为首先读取原始数据,然后进行转换和计算来改进,但代价是代码不那么简洁,行数更多。

This implementation is based on Dan Benamy's answer and simplified by using the uptime in seconds instead of the boot time in seconds since the epoch. Approach was tested with both Python 2 and 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()))

Output:

$ time ./processTime.py 
Real process time: 5.060000000012224 s

real    0m5.059s
user    0m0.041s
sys     0m0.013s

Addendum: You can't expect millisecond accuracy from this code. Apart from the limited resolution of the timestamps provided by the /proc interfaces, there's always a possibility that the execution is interrupted by task switches. However it can probably be improved by splitting the code into reading the raw data first, then doing the conversions and calculations, to the expense of less concise code with more lines.

枕梦 2024-09-03 17:49:18

你可以解析 /proc/uptime

>>> uptime, idletime = [float(f) for f in open("/proc/uptime").read().split()]
>>> print uptime
29708.1
>>> print idletime
26484.45

对于 Windows 机器,你可以使用

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

you can parse /proc/uptime

>>> uptime, idletime = [float(f) for f in open("/proc/uptime").read().split()]
>>> print uptime
29708.1
>>> print idletime
26484.45

for windows machines, you can probably use 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
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文