linux查询进程的启动时间

server/2024/12/3 7:34:42/

说到查询进程的启动时间,你的第一反应肯定是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/server/146959.html

相关文章

Jmeter 接口测试常见场景

csv 中读取账号密码登录 压测登录接口&#xff0c;通常需要循环读取账号密码&#xff0c;使用 jmeter 处理该需求一般会采用 csv 文件设置来读取账号密码&#xff0c;信息文件&#xff08;user_info.txt&#xff09;示例如下&#xff1a; 信息文件中使用英文逗号分割账号、密码…

【LC】35. 搜索插入位置

题目描述&#xff1a; 给定一个排序数组和一个目标值&#xff0c;在数组中找到目标值&#xff0c;并返回其索引。如果目标值不存在于数组中&#xff0c;返回它将会被按顺序插入的位置。 请必须使用时间复杂度为 O(log n) 的算法。 示例 1: 输入: nums [1,3,5,6], target …

Flink常见面试题

1、Flink 的四大特征&#xff08;基石&#xff09; 2、Flink 中都有哪些 Source&#xff0c;哪些 Sink&#xff0c;哪些算子&#xff08;方法&#xff09; 预定义Source 基于本地集合的source&#xff08;Collection-based-source&#xff09; 基于文件的source&#xff08;…

【Leetcode 每日一题】LCR 190. 加密运算

LCR 190. 加密运算 计算机安全专家正在开发一款高度安全的加密通信软件&#xff0c;需要在进行数据传输时对数据进行加密和解密操作。假定 dataA 和 dataB 分别为随机抽样的两次通信的数据量&#xff1a; 正数为发送量负数为接受量0 为数据遗失 请不使用四则运算符的情况下实…

分布式资源调度——yarn 概述(资源调度基本架构和高可用的实现)

此文章是学习笔记&#xff0c;图片均来源于B站&#xff1a;哈喽鹏程 yarn详细介绍 1、yarn 简介1.1 yarn的简介1.2 yarn 的基本架构1.3. yarn 的高可用 2、yarn 调度策略、运维、监控2.1 yarn 的调度策略2.1.1 FIFO scheduler(先进先出)2.1.2 容量调度2.1.3 公平调度 2.2 yarn…

计算机网络——数据链路层Mac帧详解

目录 前言 一、以太网 二、Mac帧 三、MTU——最大传输单元 四、Mac帧的传输过程 1.ARP协议 2.RARP协议 前言 在之前&#xff0c;我们学习过网络层的IP协议&#xff0c;了解到IP协议解决了从哪里来&#xff0c;到哪里去的问题&#xff0c;也就是提供了将数据从A到B的能力…

本地Docker部署个人在线音乐平台Melody结合内网穿透远程访问听音乐

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…

高职本科大数据实训平台及使用场景

大数据实验实训平台是在云计算、大数据、人工智能等基础上&#xff0c;以智能化容器集群技术搭建的“一站式”大数据、人工智能等相关专业的实验、实训、实战平台&#xff0c;支撑“教—学—练—赛—研”等全闭环的专业建设、人才培养、实验室建设等整体解决方案。 大数据…