良好的计时器可帮助程序开发人员确定程序的性能瓶颈,或对不同算法进行性能比较。但要精确测量程序的运行时间并不容易,因为进程切换、中断、共享的多用户、网络流量、高速缓存访问及转移预测等因素都会对程序计时产生影响。

抛开这些影响因素,本文仅关注 Linux 系统中用户态程序执行时间的计算方式,即基于类 UNIX 系统的 time 命令统计一个程序或比较不同算法的时间消耗。


基本概念

1. 日历时间

  • Coordinated Universal Time(UTC)

    世界协调时间(又称世界标准时间),旧称格林威治标准时间( Greenwich Mean Time, GMT )。

  • Calendar Time

    日历时间,即从一个标准时间点到此时的时间所经过的秒数。该标准时间点因编译器而异,但对编译系统而言标准时间点不变。该编译系统中的时间对应的日历时间都通过该标准时间点衡量,故日历时间是“相对时间”。UNIX/Linux 的时间系统由 “新纪元时间( Epoch )” 开始算起,该起点指定为 1970 年 1 月 1 日凌晨 0 时 0 分 0 秒(格林威治时间)。Microsoft C/C++ 7.0 中标准时间点指定为 1899 年 12 月 31 日 0 时 0 分 0 秒,而其它版本的 Microsoft C/C++ 和所有不同版本的 Visual C++ 中标准时间点指定为 1970 年 1 月 1 日 0 时 0 分 0 秒。日历时间与时区无关。

  • Epoch

    时间点。时间点在标准 C/C++ 中是一个整数( time_t ),它用此刻的时间和标准时间点相差的秒数(即日历时间)来表示。目前大部分 UNIX 系统采用 32 位记录时间,正值表示为 1970 年以后,负值则表示 1970 年以前。可简单地估算出所能表达的时间范围:1970±((231-1)/3600/24/365)≈[1901,2038] 年。为表示更久远的时间,某些编译器厂商引入 64 位甚至更长的整型数来保存日历时间。

2. 进程时间

进程时间也称 CPU 时间,用以度量进程使用的中央处理器资源。进程时间以时钟滴嗒计算,通常使用三个进程时间值,即实际时间(Real)、用户 CPU 时间(User)和系统 CPU 时间(Sys)。

实际时间指实际流逝的时间;用户时间和系统时间指特定进程使用的 CPU 时间。具体区别如下:

  • Real:是从进程开始执行到完成所经历的挂钟(wall clock)时间,包括其他进程使用的时间片(time slice)和本进程耗费在阻塞(如等待 I/O 操作完成)上的时间。该时间对应秒表(stopwatch)直接测量。

  • User:是进程执行用户态代码(内核外)耗费的 CPU 时间,仅统计该进程执行时实际使用的 CPU 时间,而不计入其他进程使用的时间片和本进程阻塞的时间。

  • Sys:是该进程在内核态运行所耗费的 CPU 时间,即内核执行系统调用所使用的 CPU 时间。

CPU 总时间(User+Sys)是 CPU 执行用户进程操作和内核(代表用户进程执行)系统调用所耗时间的总和,即该进程(包括其线程和子进程)所使用的实际 CPU 时间。若程序循环遍历数组,则增加用户 CPU 时间;若程序执行 exec 或 fork 等系统调用,则增加系统 CPU 时间。

在多核处理器机器上,若进程含有多个线程或通过 fork 调用创建子进程,则实际时间可能小于 CPU 总时间——因为不同线程或进程可并行执行,但其时间会计入主进程的 CPU 总时间。若程序在某段时间处于等待状态而并未执行,则实际时间可能大于 CPU 总时间。其数值关系总结如下:

  • Real < CPU,表明进程为计算密集型(CPU bound),利用多核处理器的并行执行优势。

  • Real ≈ CPU,表明进程为计算密集型(CPU bound),未并行执行。

  • Real > CPU,表明进程为 I/O 密集型(I/O bound),多核并行执行优势并不明显。

在单核处理器上,Real 时间和 CPU 时间之差,即 Real- (User+Sys) 是所有延迟程序执行的因素的总和。可估算程序运行期间的 CPU 利用率为 CpuUsage = (User + Sys) / Real * 100(%)
 
在 SMP(对称多处理系统)上,该差值近似为 Real* ProcessorNum - (User + Sys)。这些因素包括:

  • 调入程序文本和数据的 I/O 操作。

  • 获取程序实际使用内存的 I/O 操作。

  • 由其它程序消耗的 CPU 用时。

  • 由操作系统消耗的 CPU 用时。

3. LInux命令

在 Linux 下,命令有几种类型,包括:

  • 可以通过 $PATH 来找到的程序可执行文件,即文件系统中的命令;

  • 通过 shell 内置命令 alias 创建的 Linux 别名,即用户定义的命令;

  • shell 程序设计中的保留字,即 shell keyword,如 if、then、fi、for、while、case、esac、else、until 等;

  • 在 shell 脚本中写的 shell 函数;

  • shell 中内置的 Linux 命令,如 pwd、cd、bg、alias、history、type、source、read、exit 等,我们可以通过 Linux 内置的 type 命令来列出或检查 Linux 内置命令。

    $ type pwd
    pwd is a shell builtin
    $ type cd
    cd is a shell builtin
    $ type if then
    if is a shell keyword
    then is a shell keyword

    【左右滑动查看完整信息】


命令详解

当测试一个程序或比较不同算法时,执行时间是非常重要的,一个好的算法应该是用时最短的。所有类UNIX系统都包含 time(shell keyword),使用这个命令可以统计时间消耗。我们常用的 time 其实是一个 Shell 关键字,还有一个外部命令 /usr/bin/time,两者最主要的区别在于外部命令 /usr/bin/time 功能更强大。

$ type -a time
time is a shell keyword      #time 是一个保留字(关键字)
time is /usr/bin/time        #还有一个外部命令 time

【左右滑动查看完整信息】

/usr/bin/time 功能非常强大,我们可以使用 -v 参数查看打印出来比较详细的信息:

$ /usr/bin/time -v
Usage: /usr/bin/time [-apvV] [-f format] [-o file] [--append] [--verbose]
       [--portability] [--format=format] [--output=file] [--version]
       [--help] command [arg...]

$ /usr/bin/time -v echo "hello,time."
hello,time.
    Command being timed: "echo hello,time."
    User time (seconds): 0.00
    System time (seconds): 0.00
    Percent of CPU this job got: 63%
    Elapsed (wall clock) time (h:mm:ss or m:ss): 0:00.00
    Average shared text size (kbytes): 0
    Average unshared data size (kbytes): 0
    Average stack size (kbytes): 0
    Average total size (kbytes): 0
    Maximum resident set size (kbytes): 624
    Average resident set size (kbytes): 0
    Major (requiring I/O) page faults: 0
    Minor (reclaiming a frame) page faults: 203
    Voluntary context switches: 1
    Involuntary context switches: 0
    Swaps: 0
    File system inputs: 0
    File system outputs: 0
    Socket messages sent: 0
    Socket messages received: 0
    Signals delivered: 0
    Page size (bytes): 4096
    Exit status: 0

【左右滑动查看完整信息】

外部命令 /usr/bin/time 一些常用参数:

  • 使用 -o 选项将执行时间写入到文件中

    /usr/bin/time -o outfile.txt ls

    【左右滑动查看完整信息】

  • 使用 -a 选项追加信息

    /usr/bin/time -a -o outfile.txt ls

    【左右滑动查看完整信息】

  • 使用 -f 选项格式化时间输出

    /usr/bin/time -f "time: %U" ls

    【左右滑动查看完整信息】

  • -f 选项后的参数:

    参数  描述
    %E    real 时间,执行指令所花费的时间,显示格式为[小时:]分钟:秒。注意这个数字并不代表实际的 CPU 时间。
    %e    执行指令所花费的时间,单位是秒。请注意这个数字并不代表实际的 CPU 时间。
    %U    user 时间,指令执行时在使用者模式(user mode)所花费的时间,单位是秒。
    %S    sys 时间,指令执行时在核心模式(kernel mode)所花费的时间,单位是秒。
    %P    进程所获取的 CPU 时间百分比,这个值等于 user+system 时间除以总共的运行时间。
    %C    进行计时的命令名称和命令行参数。
    %D    进程非共享数据区域,以 KB 为单位。
    %x    命令退出状态。
    %k    进程接收到的信号数量。
    %w    进程被交换出主存的次数。
    %Z    系统的页面大小,这是一个系统常量,不用系统中常量值也不同。
    %K    进程的平均总内存使用量(data+stack+text),单位是 KB。
    %w    进程主动进行上下文切换的次数,例如等待 I/O 操作完成。
    %c    进程被迫进行上下文切换的次数(由于时间片到期)。

    【左右滑动查看完整信息】


实际操作

对 echo、gzip、自己编写的 python 程序,使用 time 对时间消耗进行统计:

$ /usr/bin/time -f "%U(user) %S(system) %E(elapsed) %P(cpu) %M(max RAM KB)" echo "Hello, world."
Hello, world.
0.00(user) 0.00(system) 0:00.01(elapsed) 0%(cpu) 624(max RAM KB)

$ /usr/bin/time -f "%U(user) %S(system) %E(elapsed) %P(cpu) %M(max RAM KB)" gzip -d CONTROL5.clean.fasta.gz
3.98(user) 0.58(system) 0:04.57(elapsed) 99%(cpu) 732(max RAM KB)

$ /usr/bin/time -f "%U(user) %S(system) %E(elapsed) %P(cpu) %M(max RAM KB)" python getFileSize.py -p "/data/train/pca-plots;/data/Bioinfo/fastq" -o output_size.txt
0.03(user) 0.00(system) 0:00.04(elapsed) 100%(cpu) 7888(max RAM KB)

【左右滑动查看完整信息】

关于 time 更多详细信息,可以点击下面 "阅读原文" 进一步了解。

·end·

—如果喜欢,快分享给你的朋友们吧—

我们一起愉快的玩耍吧

本文分享自微信公众号 - 生信科技爱好者(bioitee)。
如有侵权,请联系 support@oschina.cn 删除。
本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

Linux下程序时间消耗监控与统计的更多相关文章

  1. Linux下精确控制时间的函数

    Linux下精确控制时间的函数 在测试程序接口运行时间的时候,常用time,gettimeofday等函数,但是这些函数在程序执行的时候是耗费时间的,如果仅仅测试时间还行,但是如果程序中用到时间控制类 ...

  2. 性能测试分析过程(三)linux下查看最消耗CPU/内存的进程

    linux下查看最消耗CPU  内存的进程 1.CPU占用最多的前10个进程:  ps auxw|head -1;ps auxw|sort -rn -k3|head -10  2.内存消耗最多的前10 ...

  3. Linux下程序的机器级表示学习心得

    Linux下程序的机器级表示学习心得 上周学习完Linux程序的机器级表示后,对于其中有些还是掌握的不太透彻.对于老师提出的关于本章一些细节的问题还是有不会,所以又重新温习了一下上周的学习内容,以下为 ...

  4. Linux下长时间ping网络加时间戳并记录到文本

    Linux下长时间ping网络加时间戳并记录到文本   由于一些原因,比如需要检查网络之间是否存在掉包等问题,会长时间去ping一个地址,由于会输出大量的信息而且最好要有时间戳,因此我们可以使用简单的 ...

  5. Linux下设置时间

    Linux下设置时间 提供两种最根本有效的方式,就是更改时区.这里以更改为国内上海时间例子,其他地方时区同理. 方法一 备份文件 mv /etc/localtime /etc/localtime.ba ...

  6. Linux下系统时间函数、DST等相关问题总结(转)

    Linux下系统时间函数.DST等相关问题总结 下面这个结构体存储了跟时区相关的位移量(offset)以及是否存在DST等信息,根据所在的时区信息,很容易找到系统时间与UTC时间之间的时区偏移,另外根 ...

  7. linux下定位异常消耗的线程实战分析

    前言: 之前分享过一篇Linux开发coredump文件分析实战分享 ,今天再来分享一篇实战文章. 在我们嵌入式linux开发过程中,开发过程中我们经常会使用多进程.多线程开发.那么多线程使用过程中, ...

  8. [转] Linux下程序的加载、运行和终止流程

    TAG: linux, main, _start DATE: 2013-08-08 原文地址: http://blog.csdn.net/tigerscorpio/article/details/62 ...

  9. Linux下Java线程具体监控和其dump的分析使用----分析Java性能瓶颈[张振华-Jack]

    作者:张振华(Jack) 这里对linux下.sun(oracle) JDK的线程资源占用问题的查找步骤做一个小结: linux环境下,当发现java进程占用CPU资源非常高,且又要想更进一步查出哪一 ...

  10. 制作Linux下程序安装包——使用脚本打包bin、run等安装包

    制作简单的安装包的时候可以简单的用cat命令连接两个文件,然后头部是脚本文件,执行的时候把下面的文件分解出来就行了.一般这个后部分的文件是个压缩 包,那样,就能够打包很多文件了,在脚本中解压出来即可. ...

随机推荐

  1. C++库封装JNI接口——实现java调用c++

    1. JNI原理概述 通常为了更加灵活高效地实现计算逻辑,我们一般使用C/C++实现,编译为动态库,并为其设置C接口和C++接口.用C++实现的一个库其实是一个或多个类的简单编译链接产物.然后暴露其实 ...

  2. day128:MySQL进阶:MySQL安装&用户/权限/连接/配置管理&MySQL的体系结构&SQL&MySQL索引和执行计划

    目录 1.介绍和安装 2.基础管理 2.1 用户管理 2.2 权限管理 2.3 连接管理 2.4 配置管理 3.MySQL的体系结构 4.SQL 5.索引和执行计划 1.介绍和安装 1.1 数据库分类 ...

  3. python:模拟购票的小程序

    问题描述:小白学习python的第N天,继续练习.做一个模拟购票的小程序,没有用数据库和文件来存储数据,只是能够单词选择. # hzh 每天进步一点点 # 2022/5/13 17:24 import ...

  4. JVM的内存分配及各种常量池的区别(静态常量池、运行时常量池、字符串常量池)

    JVM内存分配 先了解下JVM中的内存分配,此处以hotspot vm为例(官方jdk采用的vm) 程序计数器 栈 1. 虚拟机栈 2. 本地方法栈 Java堆 堆内存是各个线程共享的区域 方法区 它 ...

  5. Linux(三)磁盘管理

    Linux磁盘管理 Linux中的tree工具 tree可以查看目录的树形结构,前提是需要自行安装 yum install tree -y [root@hadoop100 ~]# tree ./ ./ ...

  6. RDIFramework.NET开发框架在线表单设计整合工作流程的使用

    1.概述 在RDIFramework.NET开发框架在线表单设计助力可视化快速开发文章中,我们介绍了不使用编码的方式进行表单的在线设计并挂接在对应的模块下,加速应用的落地与实现.同样,通过在线设计的表 ...

  7. DRF版本控制(源码分析)

    DRF中版本控制的五种情况(源码分析) 在restful规范中要去,后端的API中需要体现版本. drf框架中支持5种版本的设置. 1. URL的GET参数传递(*) 示例: user/?versio ...

  8. Kubernetes入门实践(Job/CronJob)

    基于Pod的设计理念,Kubernetes有两种对象Job和CronJob Job和CronJob组合了Pod,实现了对离线业务的处理.如Nginx和busybox,分别代表了Kubernetes里的 ...

  9. CSS 基础拾遗(核心知识、常见需求)

    本篇文章围绕了 CSS 的核心知识点和项目中常见的需求来展开.虽然行文偏长,但较基础,适合初级中级前端阅读,阅读的时候请适当跳过已经掌握的部分. 这篇文章断断续续写了比较久,也参考了许多优秀的文章,但 ...

  10. Python工具箱系列(三十)

    PostgreSQL MySQL的口号是"世界上最流行的开源关系型数据库",而PostgreSQL的Slogan则是"世界上最先进的开源关系型数据库(PostgreSQL ...