Linux下有关时间的函数:time,times,clock,gettimeofday等
因为项目需要,所以把Linux下时间相关的内容刷了一遍。终于抽出时间总结一下。
目录
1. 时间的概念
首先理解时钟时间,也叫做墙上时钟时间,可以简单理解为宏观上经过的时间。细究起来就是进程运行的时钟总量,其值与系统中同时运行的进程数有关。既然有多个进程,那么进程就会出现等待,阻塞,运行几个状态,且都需要消耗时间。这些都包含在时钟时间内。上面这个概念最为重要。下面还有几个概念:
用户CPU时间:是执行用户指令所用的时间。
系统CPU时间:是为该进程执行内核程序所经历的时间。
用户CPU时间+系统CPU时间=运行时间,也称作CPU时间。CPU时间通常表现为滴答计数,保存在数据结构clock_t中,sysconf可以得到每秒的滴答数值设定值。
归纳来说,就是时钟时间包括进程的等待,阻塞和运行三大部分的时间,而运行时间又分为用户CPU时间和系统CPU时间。
一般来说,我们通常就关注两类时间,一类是真实时间及时钟时间,另一类是进程时间通常用CPU时间来表示。
2. 获得时钟时间的函数
获得时间的方法有几个函数可以实现,大体来说分为两类。
一类是获得时钟时间,通常会得到从过去某个时间点到当前时刻的时间差,这个过去的时间点通常为1970年。当然,在一些封装好了的函数中,并不需要你知道过去的时间点是什么具体的时刻,内部会帮你换算好,返回当前的实际时间。
2.1 时钟时间的存储类型
linux下存储时间常见的有两种存储方式,一个是从1970年到现在经过了多少秒,一个是用一个结构来分别存储年月日时分秒的。
第一种存储方式涉及到一种数据类型time_t,关于time_t,是在头文件time.h中定义的。这里可以明确的看到,time_t的数据类型其实就是长整型,而其表示的含义即从1970年到现在经过的秒数。
#ifndef __TIME_T
#define __TIME_T
typedef long time_t;
#endif
第二种存储方式更加精确,可以精确到微秒级。用一个结构体表示
struct timeval
{
long tv_sec; /*秒*/
long tv_usec; /*微秒*/
};
2.2 time函数
首先看函数声明,该函数包含在time.h头文件中,其返回值类型为time_t。是自Epoch以来经过的秒数。如果其传入参数不为NULL,那么该秒数还会被赋给传入的参数中。
#include <time.h>
time_t time(time_t *timep);
// returns number of seconds since the Epoch, or -1 on error
使用实例如下:
void testTime()
{
time_t t;
t = time(NULL);
cout << t << endl;
}
2.3 gettimeofday函数
同样先看看书声明,该函数包含在sys/time.h头文件中,其返回值为int类型,返回0表示调用函数成功,返回-1表示调用失败。其函数参数有两个,第一个保存获得的具体时间,第二个参数是历史产物,现在已经不用,赋成NULL即可。
#include <sys/time.h>
int gettimeofday(struct timeval *tv, stuct timezone *tz);
// return 0 on success, or -1 on error
使用实例如下:
void testGettimeofday()
{
timeval t1;
gettimeofday(&t1, NULL);
cout << t1.tv_sec << endl;
cout << t1.tv_usec << endl;
}
3. 获得程序运行的时间(即进程时间)
另外一类是cpu时间,即运行时间。这类时间其实也是返回的时间差,时间差的计算起点通常是进程开始的时间,其实和1970年这种过去时间节点的概念是一致的。但是返回的cpu时间单位往往不是时间的单位,而是cpu的时钟计时单元。想要获得直观的时间,还需要进行滴答数和时间的换算,即通常的一秒钟会有多少个时钟计时单元。
3.1 进程时间的存储类型
Cpu时间可以通过times()函数或者clock()函数获得,介绍这两种方法之前,先介绍一个数据类型clock_t和一个结构体tms。
Clock_t是时钟计数单元的计数,而其通常是以结构体tms的形式呈现的,结构体tms的定义如下:
struct tms{
clock_t tms_utime; // 调用进程到目前为止使用的用户CPU时间
clock_t tms_stime; // 调用进程到目前为止使用的系统cpu时间
clock_t tms_cutime; // 包含等待所有子进程的用户cpu时间
clock_t tms_cstime; // 包含等待所有子进程的系统cpu时间
};
有了这两个概念,下面可以讨论上述两种函数的区别和用法了。
3.2 times函数
首先是times函数,声明如下。可以看到times函数的返回类型为clock_t,且其定义包含在头文件sys/time.h中。可以调用sysconf(_SC_CLK_TCK)来获得实际的时间。这里要注意times函数和上面提到的time函数的功能是不同的,times函数是获得进程时间的方法,time函数是获得时钟时间的方法。
#include <sys/times.h>
clock_t times(struct tms *buf);
// returns number of clock ticks(sysconf(_SC_CLK_TCK))since "arbitrary" time in past on success, or (clock_t)-1 on error
上面提到clock_t通常是以结构体tms的形式呈现的,在实际写程序中,一般先定义一个clock_t类型的变量,通过传参的方式传入times函数,得到对应的时间。
void testTimes()
{
tms t1;
tms t2;
long clockticks = sysconf(_SC_CLK_TCK);
cout << clockticks << endl;
if(times(&t1) == -1)
cout << "call times() error" << endl;
cout << "user cpu time is: " << (double)t1.tms_utime / clockticks << endl;
cout << "system cpu time is: " << (double)t1.tms_stime / clockticks << endl;
//cout << (double)t1.tms_utime << endl;
//sleep(10);
for(int i=0; i<100000000; i++)
getppid();
if(times(&t2) == -1)
cout << "call times() error" << endl;
cout << "user cpu time is: " << (double)t2.tms_utime / clockticks << endl;
cout << "system cpu time is: " << (double)t2.tms_stime / clockticks << endl;
//cout << "user cpu time containing waiting is: " << (double)t2.tms_cutime / clockticks << endl;
//cout << "system cpu time containing waiting is: " << (double)t2.tms_cstime / clockticks << endl;
}
这里需要注意的是,由于times得到的是cpu的运行时间,所以需要cpu真实的运行才能看出t2得到的变化的时间,这里使用getppid()函数。不能用sleep函数,因为sleep函数代表将进程进行阻塞,这部分时间是不算在times函数的时间里的。
3.3 clock函数
首先看clock函数的声明,与times函数相同,同样返回clock_t类型的返回值。但是这两者返回的值是不同的,其对应的每秒的次数是CLOCKS_PER_SEC,这个值有可能会根据系统内的定义而又所不同,可以将其打印出来看一下。不过其总是和clock这个函数是对应的,相除之后得到的就是对应的秒数。
#include <time.h>
clock_t clock(void);
// returns total CPU time used by calling process measured in CLOCKS_PER_SEC, or -1 on error
同样,由于clock函数得到的也是cpu的运行时间,所以程序中不能用sleep来进行实验,sleep的时间不算在clock计算的时间内。
void testClock()
{
clock_t clocktime;
cout << "CLOCKS_PER_SEC " << CLOCKS_PER_SEC << endl;
for(int i=0; i<100000000; i++)
getppid();
//sleep(5);
clocktime = clock();
cout << "cpu running time is: " << clocktime / CLOCKS_PER_SEC << endl;
}
4. 补充说明
sys/times.h ,sys/time.h 和 time.h的区别:sys/time.h这个头文件是Linux系统的头文件,只能用在linux的平台上,time.h的头文件是c语言标准的头文件,可以跨平台使用。time_t这类的数据结构是linux的,所以只调用time.h,就需要自己定义time_t(如果使用到了的话)。sys/times.h是包含times函数的头文件,其定义的是获得进程时间的方法。sys/time.h是包含gettimeofday函数的头文件,其定义的是获得时钟时间的方法。
_SC_CLK_TCK 在头文件unistd.h中
Times函数和clock函数的功能基本上是一致的,只是处理的方式不同,这是历史原因造成的,一个是POSIX.1标准,一个是C语言编程标准。在转换为实际时间的过程当中,sysconf(_SC_CLK_TCK)和CLOCKS_PER_SEC不要使用混淆。
更多推荐
所有评论(0)