linux查询进程的启动时间

embedded/2024/12/3 7:43:17/

说到查询进程的启动时间,你的第一反应肯定是ps -p $pid -o lstart,但是ps 命令通常会通过访问 proc 文件系统来收集进程的信息,它本身是一个外部命令,执行时需要进行进程管理、格式化输出等额外的操作,这会消耗更多的 CPU 和 I/O 资源。每次执行 ps 命令时,它都会启动一个新的进程来执行命令,并且在执行过程中会对多个系统资源进行访问,可能会影响系统性能,尤其是高频繁调用时。

而直接读取 /proc/$pid/stat 文件是内核级别的操作,效率高,不需要额外的进程管理或命令解析开销。通过直接访问 /proc 文件系统,可以快速获得进程信息,尤其是在需要高频率查询进程信息时,它比 ps 命令更具优势。

在 Linux 系统中,/proc/[pid]/stat 文件包含了关于进程的各种信息,其中包括进程的启动时间。你可以通过解析 stat 文件中的某些字段来计算进程的启动时间,并将其转换为 date 格式。

如何通过/proc获取进程启动时间

步骤一:从 /proc/uptime 获取进程的启动时间

uptime_seconds =awk '{print $1}' /proc/uptime获取系统的运行时间(单位:秒)(从os启动到现在有多少秒 )

1.1 获取启动时间(jiffies)

首先,读取 /proc/[pid]/stat 文件中的第 22 个字段,这个字段表示进程的启动时间(jiffies)。每个 jiffie 是系统时钟的一个单位,通常等于 1/100 秒(在某些系统上,可能是 1/250 秒,但大多数 Linux 系统使用 1/100 秒),得到进程自系统启动以来的时钟滴答(jiffies)数。

步骤二:获取系统的时钟频率

系统时钟频率(也称为 CLK_TCK)指的是每秒钟的时钟滴答数。在大多数 Linux 系统上,时钟频率为 100(即每秒 100 个 jiffies)。你可以通过 getconf CLK_TCK 来获取当前系统的时钟频率。

2.1 获取时钟频率

你可以使用 getconf CLK_TCK 命令来获取系统的时钟频率:

clk_tck=$(getconf CLK_TCK)

步骤三:计算进程启动的时间

要计算进程的启动时间,可以使用以下公式:

process_start_time_seconds = (启动的 jiffies) / (每秒的时钟滴答数)
$uptime_seconds - $process_start_time_seconds

$uptime_seconds - $process_start_time_seconds这个结果将给出从系统启动以来,进程启动的秒数。

系统启动时间和进程启动时间的参考时间点是一致的:它们都是相对于系统的启动时刻。

利用这个共同的时间点,通过两者之间的差值就可以计算出进程的启动时间。

/proc/uptime 提供的是系统的总运行时间,因此它可以作为整个系统的“基准时钟”

/proc/$pid/stat提供的是进程在该系统上的启动时刻(相对于系统启动),所以通过它们的差值来计算进程的启动时间

步骤四:转换为实际日期格式

使用 date 命令将秒数转换为人类可读的日期格式。

absolute_start_time_seconds=$(echo "$(date +%s) - $uptime_seconds + $process_start_time_seconds" | bc)

示例代码

以下是一个脚本,演示了如何通过 /proc/[pid]/stat 获取进程的启动时间,并将其转换为实际的日期和时间格式:

#!/bin/bash# 输入进程的 PID
pid=$1# 获取系统的运行时间(单位:秒)
uptime_seconds=$(awk '{print $1}' /proc/uptime)# 获取进程的启动时间(jiffies)
start_jiffies=$(awk '{print $22}' /proc/$pid/stat)# 获取系统的时钟频率(每秒的时钟滴答数)
clk_tck=$(getconf CLK_TCK)# 计算进程的启动时间(单位:秒)
process_start_time_seconds=$(echo "$start_jiffies / $clk_tck" | bc)# 计算进程的绝对启动时间
absolute_start_time_seconds=$(echo "$(date +%s) - $uptime_seconds + $process_start_time_seconds" | bc)# 转换为日期格式
start_date=$(date -d @$absolute_start_time_seconds "+%Y-%m-%d %H:%M:%S")echo "Process $pid started at: $start_date"

解释:

  1. awk '{print $22}' /proc/$pid/stat:读取进程的启动时间(jiffies)。
  2. getconf CLK_TCK:获取系统的时钟频率(即每秒的 jiffies 数量)。
  3. awk '{print $1}' /proc/uptime:读取系统的 uptime(系统启动后的总时间,单位为秒)。
  4. bc:用于浮点运算计算进程启动的秒数。
  5. absolute_start_time_seconds=$(echo "$(date +%s) - $uptime_seconds + $process_start_time_seconds" | bc):计算进程的绝对启动时间。用当前时间戳(date +%s)减去系统启动时间,再加上进程的启动时间,得到进程的绝对启动时间。
  6. start_date=$(date -d @$absolute_start_time_seconds "+%Y-%m-%d %H:%M:%S"):将绝对启动时间转换为可读的日期格式。

步骤五:运行脚本

假设你有一个进程的 PID,可以像下面这样运行脚本:

./get_process_start_time.sh 12345

这个命令会输出类似下面的内容:

Process 12345 started at: 2024-11-01 10:35:15

总结:

  • /proc/[pid]/stat 中的第 22 个字段提供了进程的启动时间(以 jiffies 为单位)。
  • 使用 getconf CLK_TCK 获取系统时钟频率,确定每秒的 jiffies 数量。
  • 使用 /proc/uptime 来获取系统的启动时间,从而计算进程的启动时间。
  • 使用 date 命令将计算出的秒数转换为标准的日期时间格式。

这种方法能够有效地查询进程的启动时间并将其转换为可读的格式。

上述讲解如果获取pid的启动时间,但是实际场景我们只知道进程的名称,如何通过进程名称拿到pid呢,你的第一反应肯定是ps -ef | grep 进程名称,nonono,我们说明不建议使用ps,那么是否有其他方式呢?

pgrep/proc/$pid/cmdline 获取进程 PID


1. pgrep 命令

简介

pgrep 是一个用来查找匹配指定条件的进程,并返回它们的 PID(进程 ID)的命令。它能够快速定位进程,并返回一个或多个 PID。

常见用法:
  • pgrep <pattern>:通过进程名称(或匹配模式)查找 PID。
  • pgrep -f <pattern>:在整个命令行中查找进程,而不仅仅是进程名称。
  • pgrep -o <pattern>:只返回最早的 PID。
  • pgrep -n <pattern>:只返回最近的 PID。
示例:
# 查找所有名为 'python' 的进程 PID
pgrep python# 查找所有包含 'python /usr/bin/cinder-volume' 命令的进程
pgrep -f "python /usr/bin/cinder-volume"# 获取名为 'cinder-api' 的进程 PID
pgrep cinder-api
解析:
  • pgrep 会返回匹配到的进程的 PID。如果没有匹配到,返回空值。
  • 默认情况下,pgrep 只会匹配进程名称(argv[0]),即进程的命令名。
  • 使用 -f 选项时,pgrep 会匹配进程的完整命令行(包括命令行参数),而不仅仅是进程名称。
  • pgrep 可以根据进程名、父进程 ID、用户、会话等信息进行过滤,支持正则表达式。
优点:
  • 简洁高效pgrep 是专门用来查询进程 PID 的工具,使用简单,能够快速找到进程。
  • 支持正则:可以用正则表达式灵活匹配进程。
  • 无需手动处理 /proc 目录pgrep 内部实现已经处理了 /proc 的细节,用户只需要关心进程名称或命令行即可。
缺点:
  • 可能有误匹配:如果进程名中有多个类似的进程,可能会返回多个 PID。例如,如果有两个进程名称相同的进程,pgrep 会返回它们的所有 PID,可能需要后续处理来精确筛选。
  • 限制性pgrep 仅通过进程名称或者命令行来匹配进程,无法像 /proc 目录那样查询其他进程信息(例如启动时间、内存占用等)。

2. /proc/$pid/cmdline 方式

简介

Linux 系统中每个进程在 /proc 目录下都有一个对应的目录,目录名即为进程的 PID。每个进程目录下都有一个 cmdline 文件,记录了启动该进程时的命令行参数。通过读取 cmdline 文件,结合进程的 PID,可以知道该进程是如何启动的。

常见用法:
  • 通过 /proc/[pid]/cmdline 来获取进程的命令行信息。
  • 通过遍历 /proc 目录来查找符合条件的进程。
示例:
# 获取进程 1234 的命令行信息
cat /proc/1234/cmdline# 查找所有进程的命令行,并筛选出包含 'python' 的进程
for pid in /proc/[0-9]*; doif [[ -f $pid/cmdline && $(cat $pid/cmdline) == *"python"* ]]; thenecho "Found PID: $(basename $pid)"fi
done
解析:
  • /proc/$pid/cmdline 文件包含该进程启动时的命令行字符串,多个参数之间用 null 字符 (\0) 分隔。
  • 读取 cmdline 文件可以了解进程的完整命令行,包括程序名称和所有传递的命令行参数。
  • 可以通过遍历 /proc 目录下的每个进程目录(/proc/[pid])来检查进程的命令行,查找符合条件的进程。
优点:
  • 详细信息cmdline 包含完整的命令行参数,可以获取进程启动时的完整命令(包括路径和参数)。
  • 精确控制:通过直接操作 /proc,可以灵活地过滤和查找进程,支持更复杂的查询条件。
  • 无需依赖外部工具:通过直接访问 /proc,可以不依赖于 pgrep 等外部命令。
缺点:
  • 性能问题:遍历 /proc 目录可能会导致较高的 I/O 开销,尤其是在系统进程较多时。
  • 需要处理 null 字符/proc/$pid/cmdline 中的命令行参数由 null 字符分隔,因此需要特别处理。例如,使用 cat 会输出 \0 字符,可能需要进一步处理。
  • 复杂性较高:与 pgrep 命令相比,通过 /proc 查找进程需要手动遍历 /proc 目录并对 cmdline 文件进行解析,代码实现稍复杂。

3. pgrep vs /proc/$pid/cmdline

性能:
  • pgrep 在实现上已经做了很多优化,直接使用命令行参数匹配,通常会比遍历 /proc 目录查找 PID 更高效。
  • /proc/$pid/cmdline 方法需要遍历系统中的所有进程,并读取每个进程的 cmdline 文件,对于大量进程的系统来说性能开销较大。
精确度:
  • pgrep 适合简单的匹配任务,如果仅仅是通过进程名查找进程 PID,pgrep 更简洁。
  • /proc/$pid/cmdline 方法则能提供更精确的控制,尤其在进程名称不唯一的情况下,或者需要检查进程的启动参数时,/proc 方式更灵活。
易用性:
  • pgrep 作为一个专门的命令,使用起来非常简便。它提供了正则表达式支持,可以快速查找进程。
  • /proc/$pid/cmdline 需要编写脚本来遍历 /proc 目录并解析 cmdline 文件,使用起来相对复杂。
使用场景:
  • pgrep:如果只是通过进程名或命令行模式查找 PID,pgrep 是最简单直接的工具,适合大部分简单任务。
  • /proc/$pid/cmdline:如果你需要深入解析进程的启动命令,或者进程名不唯一需要通过命令行参数进行更精确的筛选,/proc 方式更适用。

总结

  • pgrep 是一个简单、快速、有效的工具,适合根据进程名称或命令行模式快速查找进程 PID,适用于大多数场景。
  • /proc/$pid/cmdline 提供了更高的灵活性和精确度,适合需要访问进程命令行参数的场景,但性能开销较大,使用起来也更为复杂。

两者根据具体需求选择,通常如果只是查找进程 PID,pgrep 更加高效和简洁;而如果需要深入获取进程的命令行信息,/proc 方式更适合。

/proc/uptime

/proc/uptime 是 Linux 系统中的一个伪文件,用于提供系统启动以来的运行时间(包括空闲时间和总运行时间)。它位于 /proc 文件系统中,是一个很有用的文件,可以用来获取系统的启动时间、空闲时间等相关信息。

/proc/uptime 文件格式

/proc/uptime 文件的内容通常如下所示:

12345.67 8901.23

这里有两个值,用空格分开:

  1. 第一个值:系统的总运行时间,单位是秒。

    • 这个值表示系统自启动以来的时间(包括系统空闲时间),即从系统启动到当前时间的总时长。
  2. 第二个值:系统空闲时间,单位也是秒。

    • 这个值表示自系统启动以来,所有 CPU 的空闲时间的累计时间(包括系统空闲和用户空闲的时间)。

/proc/uptime 详细解析

  1. 第一个字段:系统的总运行时间(uptime)

    • 意义:这是系统从启动时刻开始,到当前时刻所经过的总时间(包括空闲时间和非空闲时间)。可以理解为整个系统的“活跃时间”。
    • 单位:秒。
    • 例如12345.67,表示系统从启动到当前的时间是 12345.67 秒。
  2. 第二个字段:系统空闲时间(idle time)

    • 意义:这个字段表示从系统启动到当前时刻,所有 CPU 核心空闲的累计时间。换句话说,这个时间表示系统中 CPU 在空闲状态下的总时间。
    • 单位:秒。
    • 例如8901.23,表示自系统启动以来,CPU 处于空闲状态的时间为 8901.23 秒。

如何使用 /proc/uptime 获取系统信息

  • 系统运行时间:第一个字段的值表示系统的总运行时间,可以用来计算系统的“活跃”时间。

  • 系统空闲时间:第二个字段的值表示系统的空闲时间,可以用来了解系统的负载和空闲情况。

计算系统的“活动”时间

/proc/uptime 提供的第一个字段可以直接表示系统自启动以来的运行时间。这个时间是总运行时间,包括了 CPU 在空闲时和活动时的时间。因此,如果需要查看系统的运行状态、负载、空闲情况时,uptime 是一个非常重要的参考。

示例
  1. 查看系统总运行时间和空闲时间
cat /proc/uptime

假设返回的内容为:

12345.67 8901.23
  • 系统总运行时间:12345.67 秒
  • 系统空闲时间:8901.23 秒
  1. 查看系统的活动时间

如果你想了解系统的活动时间,可以通过以下公式计算:

active_time=$(awk '{print $1 - $2}' /proc/uptime)
echo "Active time: $active_time seconds"

这里,$1 是系统总运行时间,$2 是空闲时间。通过计算这两者的差值,你就可以得到系统的“活动时间”。

计算系统启动时间

/proc/uptime 中的第一个字段还可以帮助你计算系统的启动时间。假设当前时间戳是 $(date +%s)(即从1970年1月1日到当前的秒数),系统的启动时间戳可以通过以下公式计算:

startup_time=$(echo "$(date +%s) - $(awk '{print $1}' /proc/uptime)" | bc)
startup_date=$(date -d @$startup_time)
echo "System startup time: $startup_date"

这里,我们首先使用 date +%s 获取当前时间戳,再用 /proc/uptime 中的第一个字段(系统总运行时间)减去,得到系统的启动时间戳,然后用 date -d @$startup_time 将时间戳转换为可读的日期格式。

应用场景

  1. 系统监控:你可以利用 /proc/uptime 来查看系统是否在长时间运行,尤其是当你想监控一个系统的健康状况时,了解系统是否重启或者空闲状态。

  2. 负载分析:通过对比系统的空闲时间和总运行时间,可以推测系统的负载状态。较高的空闲时间可能表明系统负载较轻,较低的空闲时间则可能表明系统负载较高。

  3. 计算系统启动时间:如上所述,/proc/uptime 提供了计算系统启动时间的关键信息,尤其是在系统管理和调试中很有用。

总结

  • /proc/uptime 是一个非常有用的文件,它提供了系统的总运行时间和空闲时间。
  • 可以使用该文件的信息来监控系统的负载、计算系统的启动时间等。
  • 理解 /proc/uptime 中的两个字段的含义有助于你更好地分析和理解系统的状态。

/proc/$pid/stat

/proc/$pid/stat 是 Linux 中一个非常重要的文件,它包含了当前进程的各种状态和资源使用情况。每个进程都有一个对应的 /proc/$pid/stat 文件,其中包含了该进程的多种信息,包括它的运行时间、内存使用情况、CPU 使用情况等。

/proc/$pid/stat 文件格式

/proc/$pid/stat 文件的内容通常包括多达 50 个字段,每个字段用空格分隔。这里简要介绍最常用的字段,重点讲解 utimestime 字段。

/proc/$pid/stat 中的字段
pid (comm) state ppid pgrp session tty_nr tpgid flags minflt cminflt majflt cmajflt utime stime cutime cstime priority nice num_threads itrealvalue starttime vsize rss rsslim startcode endcode startstack kstkesp kstkeip signal blocked sigignore sigcatch wchan nswap cnswap exit_signal processor rt_priority policy delayacct_blkio_ticks guest_time cguest_time
  1. pid: 进程的 PID(进程ID)。
  2. comm: 进程的名称(括号中的内容)。
  3. state: 进程的状态,常见的有:
    • R: 运行
    • S: 睡眠
    • D: 不可中断的睡眠
    • Z: 僵尸
    • T: 停止
    • W: 内存交换中
  4. ppid: 父进程的 PID。
  5. pgrp: 进程组 ID。
  6. session: 会话 ID。
  7. tty_nr: 进程的终端设备号。
  8. tpgid: 进程组的进程号。
  9. flags: 进程标志位,表示进程的特性。
  10. minflt: 进程自启动以来发生的最小页面错误次数。
  11. cminflt: 进程的子进程自启动以来发生的最小页面错误次数。
  12. majflt: 进程自启动以来发生的重大页面错误次数。
  13. cmajflt: 进程的子进程自启动以来发生的重大页面错误次数。
  14. utime: 进程在用户态的 CPU 时间(单位:jiffies,时钟滴答)。表示进程在用户空间执行的时间,不包括内核空间的时间。
  15. stime: 进程在内核态的 CPU 时间(单位:jiffies,时钟滴答)。表示进程在内核空间执行的时间,不包括用户空间的时间。
  16. cutime: 子进程在用户态的 CPU 时间(单位:jiffies)。
  17. cstime: 子进程在内核态的 CPU 时间(单位:jiffies)。
  18. priority: 进程的调度优先级。
  19. nice: 进程的 nice 值,影响进程的优先级。
  20. num_threads: 进程的线程数。
  21. itrealvalue: 进程的定时器过期时间。
  22. starttime: 进程启动时的时间(单位:jiffies)。
  23. vsize: 进程的虚拟内存大小(单位:字节)。
  24. rss: 进程的常驻内存集大小(单位:页面数)。
  25. rsslim: 进程的最大内存限制(单位:字节)。
  26. startcode: 进程代码段的起始地址。
  27. endcode: 进程代码段的结束地址。
  28. startstack: 进程堆栈段的起始地址。
  29. kstkesp: 进程内核栈的栈指针。
  30. kstkeip: 进程内核栈的指令指针。
  31. signal: 进程接收的信号。
  32. blocked: 进程阻塞的信号。
  33. sigignore: 进程忽略的信号。
  34. sigcatch: 进程捕获的信号。
  35. wchan: 进程阻塞时的内核函数地址。
  36. nswap: 进程交换出去的页面数量。
  37. cnswap: 子进程交换出去的页面数量。
  38. exit_signal: 进程退出时发送的信号。
  39. processor: 进程运行的 CPU 核心编号。
  40. rt_priority: 进程的实时优先级。
  41. policy: 进程的调度策略。
  42. delayacct_blkio_ticks: 进程的块 I/O 延迟时间(单位:时钟滴答)。
  43. guest_time: 进程在模拟的虚拟机中运行的时间(单位:jiffies)。
  44. cguest_time: 子进程在模拟的虚拟机中运行的时间(单位:jiffies)。

utimestime 字段的意义

  • utime:表示进程在用户空间执行的时间。它是进程执行用户代码所消耗的 CPU 时间,单位为 jiffies(时钟滴答)。每个 jiffy 的长度取决于系统的时钟频率(getconf CLK_TCK)。通常情况下,utime 可以反映进程的 CPU 使用量(除去内核部分)。

  • stime:表示进程在内核空间执行的时间。它是进程执行内核代码所消耗的 CPU 时间,单位也为 jiffies。通常,这个时间会比较短,除非进程进行大量的内核空间操作。

这两个字段分别表示用户态和内核态的 CPU 时间,它们的合计给出了进程的总 CPU 使用时间。

为什么 utimestime 不等于进程的启动时间?

utimestime 字段并不是表示进程的启动时间,而是表示进程在用户态和内核态的 CPU 时间消耗。它们指的是从进程启动以来,进程实际占用 CPU 时间的总和。

  • utime:表示进程在用户态(执行用户代码)消耗的 CPU 时间。
  • stime:表示进程在内核态(执行系统调用、内核代码)消耗的 CPU 时间。

utimestime:表示的是进程的 CPU 使用时间,累积了进程在用户态和内核态的时间。它并不能直接告诉你进程的启动时间,而是进程执行时消耗的 CPU 时间。
utimestime 的计算不考虑进程的 等待时间,比如:如果进程在等待 I/O 操作、睡眠、被暂停等,它的 CPU 时间 不会增加,但它的 实际启动时间(通过 ps -p $pid -o lstart 获取)仍然可以准确反映进程的启动时刻。


http://www.ppmy.cn/embedded/142542.html

相关文章

MATLAB 手写判断点在多边形内外的2种方法(87)

MATLAB 手写判断点在多边形内外-方法1(87) 一、算法介绍二、算法实现1.方法1(代码+测试)2.方法2(代码+测试)三、结果一、算法介绍 手动实现两种方法,判断点在多边形的内部还是外部, 具体实现和测试代码如下,使用前请自行验证。(代码复制粘贴即可使用) 二、算法实现…

设计模式- Java

工厂模式 通过将对象的创建过程封装到一个工厂类中&#xff0c;使得客户端不需要直接使用 new 去创建对象&#xff0c;而是通过调用工厂方法来获取所需的对象。这样可以降低代码耦合度&#xff0c;并方便后续的扩展和维护。 示例代码 简单工厂模式&#xff08;不配合策略模式…

三格电子—单通道串口服务器

型号&#xff1a;SG-TCP232-110 一、产品介绍 1.1 功能简介 SG-TCP232-110 是一款用来进行串口数据和网口数据转换的设备。解决普通 串口设备在 Internet 上的联网问题。 设备的串口部分提供一个 232 接口和一个 485 接口&#xff0c;两个接口内部连接&#xff0c;…

阿里邮箱发送带excel附件邮件

导包 <dependency><groupId>javax.mail</groupId><artifactId>mail</artifactId><version>1.4.7</version> </dependency> 内容 调用 EmilUtil.sendEmail("xxxx163.com",host,username,password,port,excelFile,…

axios的认识与基本使用

axios简介 Axios 是一个基于 promise 网络请求库&#xff0c;作用于node.js 和浏览器中。 它是 isomorphic 的(即同一套代码可以运行在浏览器和node.js中)。在服务端它使用原生 node.js http 模块, 而在客户端 (浏览端) 则使用 XMLHttpRequests。 主要特点 从浏览器创建 XML…

DOCKER学习总结

这里写目录标题 一、Docker安装1.1 在线安装1.2 离线安装安装配置启动服务 1.3 配置镜像1.4 Docker启动相关命令 二、Docker三大核心概念2.1 镜像2.2 容器2.3 仓库2.3.1 公有仓库2.3.2 私有仓库 二、容器与虚拟机比较 一、Docker安装 1.1 在线安装 查看是否安装dockeryum lis…

【Robocasa】Code Review

文章目录 OverviewalgoInitializationImportant Class MethodsTrain LoopTest Time ConfigsdemoConfig FactoryConfig StructureConfig Locking默认锁定状态配置修改的上下文管理器 dataset示例数据集对象参数说明 model基础模块EncoderCoreVisualCoreScanCore随机化器 (Random…

VINS_MONO视觉导航算法【二】论文讲解+GPU实现调研

文章目录 其他文章说明论文系统特点和创新点鲁棒的初始化紧耦合优化的视觉惯性里程计&#xff08;VIO&#xff09;回环检测与重定位4自由度姿态图优化 视觉和IMU测量的预处理步骤视觉测量预处理特征跟踪特征点处理关键帧选择 IMU测量预处理IMU噪声和偏差预积分偏差校正 单目紧密…