glibc中关于时间的函数

一、总览

1.获取时间的的函数:time、gettimeofday、clock_gettime 

2.时间转换的函数:asctime, ctime, gmtime, localtime, mktime, asctime_r, ctime_r, gmtime_r, localtime_r 

3.时间设置函数:settimeofday

4.计算程序运行时间相关函数:clock、times、clock_gettime(实时函数,也可以用做获取当前时间)

二、获取程序运行时间

2.1、clock函数

2.1.1、简介

#include <time.h>
clock_t clock(void);

 返回值:

The clock() function returns an approximation of processor time used by the program.

The value returned is the CPU time used so far as a clock_t; to get the number of seconds used, divide by CLOCKS_PER_SEC. If the processor time used is not available or its value cannot be represented, the function returns the value (clock_t) -1.

https://linux.die.net/man/3/clock

2.1.2、源码分析

不同平台的实现略有差别,以unix为例:

/sysdeps/unix/sysv/linux/clock.c

#include <sys/times.h>
#include <time.h>
#include <unistd.h>

clock_t
clock (void)
{
  struct __timespec64 ts;

  _Static_assert (CLOCKS_PER_SEC == 1000000,
		  "CLOCKS_PER_SEC should be 1000000");

  if (__glibc_unlikely (__clock_gettime64 (CLOCK_PROCESS_CPUTIME_ID, &ts) != 0))
    return (clock_t) -1;

  return (ts.tv_sec * CLOCKS_PER_SEC
	  + ts.tv_nsec / (1000000000 / CLOCKS_PER_SEC));
}

2.1.3、使用实例

#include <time.h>  
#include <stdio.h>  
 
int main()
{
	double start, end, cost;
	start = clock();
 
	int i = 100000000;
	while (i > 0)
	{
		i--;
	}
 
	end = clock();
	cost = (end - start)/CLOCKS_PER_SEC;//CLOCKS_PER_SEC表示时钟次数
	printf("%f\n", cost);
	return 0;
}

2.1.4、深入分析

如何理解“approximation of processor time used by the program”?

1、approximation

也许你会想,程序不就是一条条指令么,每一条指令序列都有固定执行时间,为什么不能精确计算时间?真实情况下,我们的计算机并不是只运行一个程序的,进程的切换,各种中断,共享的多用户,网络流量,高速缓存的访问,转移预测等,都会对计时产生影响。对于进程调度来讲,花费的时间分为两部分,第一是计时器中断处理的时间,也就是当且仅当这个时间间隔的时候,操作系统会选择,是继续当前进程的执行还是切换到另外一个进程中去。第二是进程切换时间,当系统要从进程A切换到进程B时,它必须先进入内核模式将进程A的状态保存,然后恢复进程B的状态。因此,这个切换过程是有内核活动来消耗时间的。具体到进程的执行时间,这个时间也包括内核模式和用户模式两部分,模式之间的切换也是需要消耗时间,不过都算在进程执行时间中了”。ok,读完上面这段话,你应该很清楚的知道一个程序即使每次执行相同的命令,所花费的时间也不一定相同,因为其花费的时间与系统运行相关。原因就在于无论是windows还是linux,都是多任务操作系统。

2、processor time used by the program

对执行一个程序所消耗的时间进行分类,如下:

  • 实际运行时间(real time):也就是进程从开始到结束所用的实际时间。这个时间包括其他进程使用的时间片和进程阻塞的时间(比如等待I/O完成)。
  • 用户CPU时间(user CPU time):进程执行用户态代码(核心之外)所使用的时间。这是执行此进程所消耗的实际CPU时间,其他进程和此进程阻塞的时间并不包括在内。
  • 系统CPU时间(system CPU time):进程在内核态消耗的CPU时间,即在内核执行系统调用所使用的CPU时间。

       现在有没有这样的疑问,实际运行时间(1)是不是等于(2)+(3)?对于一个进程而言,除了用户和系统之外难道还有别人么?答案是肯定的,了解了系统调度原理就能理解了。

real time > user time + sys time 这种关系始终成立么?答案是否定的。原因就在于并行计算。

那么,什么情况下进程开始到结束所经过的时间会比进程所消耗的用户时间和系统时间(user time + sys time)小呢?
User+Sys为进程所使用的实际CPU时间。在多处理器的系统上,一个进程如果有多个线程或者有多个子进程并行执行,就可能导致Real time比CPU time(User + Sys time)要小,这是很容易理解的。

clock()算出的时间究竟属于上面的哪一个呢?为此我们设计如下一个实验:
该段代码为测试执行一亿次空循环所消耗的时间

int main( void )
{
    clock_t start, finish;
    double duration;
    long i,j;
    start = clock();
    for( i=0;i<100;i++){
        for( j=0;j<1000000;j++);
        }
    finish = clock();
    duration = (double)(finish- start) / CLOCKS_PER_SEC;
    printf( "Time to do %ld empty loops is ",i*j);
    printf( "%f seconds\n",duration );
    return 0;
}

Time to do 100000000 empty loops is 0.290000 seconds

我们在其中加一句sleep(5);

int main( void )
{
    clock_t start, finish;
    double duration;
    long i,j;
    start = clock();
    for( i=0;i<100;i++){
        for( j=0;j<1000000;j++)
            sleep(5);
        }
    finish = clock();
    duration = (double)(finish- start) / CLOCKS_PER_SEC;
    printf( "Time to do %ld empty loops is ",i*j);
    printf( "%f seconds\n",duration );
    return 0;
}

Time to do 100000000 empty loops is 0.290000 seconds

一样!现在证明了clock函数是计算的CPU时间,即“processor time”

clock()函数计算出来的时间就为总的CPU时间。也就是说,clock函数不能区分用户空间和内核空间。

clock函数在计算并行程序用时中存在的问题_clock 不支持并发-CSDN博客

2.2、clock_gettime函数

2.2.1、简介

#include <time.h>
int clock_gettime(clockid_t clk_id, struct timespec *tp);
输入参数:
clock IDmeaning
CLOCK_REALTIME

System-wide real-time clock.墙上时间,时间同步后可能改变。

This clock is supported by all implementations and returns the number of seconds and nanoseconds since the Epoch. This clock can be set via clock_settime but doing so requires appropriate privileges. When the system time is changed, timers that measure relative intervals are not affected but timers for absolute point in times are.

CLOCK_REALTIME_COARSE (Linux-specific)Faster than CLOCK_REALTIME but not as accurate.
CLOCK_MONOTONIC

Clock that cannot be set and represents monotonic time since some unspecified starting point. This clock is not affected by discontinuous jumps in the system time (e.g., if the system administrator manually changes the clock), but is affected by the incremental adjustments performed by adjtime(3) and NTP. However, NTP adjustments will not cause this clock to jump; it's rate might be adjusted to compensate for clock drift. 

系统启动开始计时,单调增长。

CLOCK_MONOTONIC_RAW (Linux-specific)Similar to CLOCK_MONOTONIC, but provides access to a raw hardware-based time that is not subject to NTP adjustments.
CLOCK_MONOTONIC_COARSE (Linux-specific)Like CLOCK_MONOTONIC but faster and not as accurate.
CLOCK_PROCESS_CPUTIME_ID

High-resolution per-process timer from the CPU.

The CLOCK_PROCESS_CPU_TIME_ID clock measures only the CPU time consumed by the process. If the kernel puts the process to sleep, the time it spends waiting is not counted. 

进程sleep的时间不算在内

CLOCK_THREAD_CPUTIME_ID

Thread-specific CPU-time clock.

CLOCK_THREAD_CPUTIME_ID is similar but measures only the CPU time spent on the thread that is making the request.

仅计算发出请求的进程的cpu time

https://stackoverflow.com/questions/14270300/what-is-the-difference-between-clock-monotonic-clock-monotonic-raw/14270415#14270415
 输出参数:
struct timespec {
	time_t   tv_sec;        /* seconds */
	long     tv_nsec;       /* nanoseconds */
};

https://linux.die.net/man/2/clock_gettime

CS 416 Documents

2.3、times函数

2.3.1、简介

times系统调用获取当前进程及其子进程使用的用户时间和系统时间 

#include <sys/times.h>

clock_t times(struct tms *buf);

struct tms {
	clock_t tms_utime;  /* user time */
	clock_t tms_stime;  /* system time */
	clock_t tms_cutime; /* user time of children */
	clock_t tms_cstime; /* system time of children */
};

所有的参数单位是clock_t.,clock_t 的定义取决于系统,一般是long类型,也有可能是long long。所有的时间值以"clock ticks"表示。 ticks是一个不断递增的值,递增频率可以通过以下宏定义获取,通常来讲是100。因此,一次时钟滴答的具体时间间隔应该是10ms。

#include <unistd.h>

sysconf(_SC_CLK_TCK);

2.3.2、输出型参数 tms *buf

/* times: report times used by the current process */
/* Paul Krzyzanowski */

#include <stdio.h>		/* defines printf() */
#include <stdlib.h>		/* to define exit() */
#include <unistd.h>		/* for sysconf() */
#include <stdint.h>		/* used for casting clock_t to uintmax_t for printf */
#include <sys/times.h>		/* needed for the times() system call */
#include <sys/types.h>
#include <sys/stat.h>		/* used for open() */
#include <fcntl.h>		/* used for open() */

void kill_time(void);

int
main(int argc, char **argv) {
	struct tms t;	/* the time values will be placed into this struct */

	printf("tick frequency is: %lu\n", sysconf(_SC_CLK_TCK));

	kill_time();		/* do something to use up some time */
	if (times(&t) < 0) {
		perror("times");	/* error - print a message and exit */
		exit(1);
	}
	/* print the results */
	printf("user time: %ju ticks\n", (uintmax_t) t.tms_utime);
	printf("system time: %ju ticks\n", (uintmax_t) t.tms_stime);
	printf("chidren - user time: %ju ticks\n", (uintmax_t) t.tms_cutime);
	printf("chidren - system time: %ju ticks\n", (uintmax_t) t.tms_cstime);

	exit(0);
}

void
kill_time(void) {
	long long i, j;	/* use these in a loop to kill time */
	int fd;
	char buf[2048];

	printf("doing some cpu wasting stuff\n");
	for (i=0; i<100000000; i++)
		j += i;

	printf("doing some kernel wasting stuff\n");
	/* do some stuff to waste system time */
	if ((fd = open("/dev/urandom", O_RDONLY)) < 0) {
		perror("open");
		exit(1);
	}
	for (i=0; i < 1000; i++) 
		read(fd, buf, 2048);
	close(fd);
}

2.3.3、返回值

The times system call returns the current tick count. 

注意,这个值可能会回绕“wrapping back through 0”,对于64 bit操作系统,5.8×109 years;对于32bit操作系统,2 year左右。

 2.3.3、实例

测量程序代码片段运行时间

/* times: use times() to get the elapsed time */
/* Paul Krzyzanowski */

#include <stdio.h>		/* declares printf() */
#include <stdlib.h>		/* declares exit() */
#include <unistd.h>		/* declares sysconf() */
#include <stdint.h>		/* used for casting clock_t to uintmax_t for printf */
#include <sys/times.h>		/* needed for the times() system call */

int
main(int argc, char **argv) {
	struct tms t;		/* parameter to times() - we'll ignore it */
	unsigned long freq;	/* clock frequency */
	uintmax_t start;	/* starting tick value */
	uintmax_t end;		/* ending tick value */

	printf("sizeof(clock_t) = %lu\n", sizeof(clock_t));
	printf("tick frequency is: %lu\n", freq=sysconf(_SC_CLK_TCK));

	if ((start = times(&t)) < 0) {	/* mark the start time */
		perror("times");	/* error - print a message and exit */
		exit(1);
	}
	sleep(2);	/* sleep for two seconds */
	if ((end = times(&t)) < 0) {	/* mark the end time */
		perror("times");	/* error - print a message and exit */
		exit(1);
	}
	printf("elapsed time: %ju - %ju = %ju ticks\n", end, start, end-start);
	printf("elapsed time: %5.2f seconds\n", (double)(end-start)/freq);
	exit(0);
}

CS 416 Documents

ref:

C/C++获取时间方法:gettimeofday()_c++ gettimeofday-CSDN博客

Linux下统计程序、函数、代码运行时间_主函数运行时间和代码量-CSDN博客

4.代码片断收集-linux下运行时间测量_linux 测量代码执行时间-CSDN博客

c++中计时程序_c++ clocks_per_sec-CSDN博客

https://www.cnblogs.com/wfwenchao/p/5195022.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值