gettimeofday/clock_gettime

article/2025/10/21 12:18:25

我们写程序的时候经常会使用计时函数,比如RPC中计算超时时间,日志中打印当前时间,性能profile中计算某个函数的执行时间等。在使用时间函数的时候,我们一般默认认为时间函数本身的性能是很高的,对主逻辑的影响可以忽略不计。虽然绝大部分情况下这个假设都没问题,但是了解更多细节能够增加我们对问题的把控力,利于系统的设计和问题的调查。

首先来比较gettimeofday/clock_gettime的性能。

程序代码见后

 

Glibc版本:

$rpm -qa|grep glibc-comm

glibc-common-2.5-81

内核版本:

$uname -a

2.6.32-220.23.2

 

$./a.out -help

 [gettimeofday/clock_gettime] thread_number loop_count

 

$./a.out gettimeofday 1 100000000

gettimeofday(50035480681901) , times : 100000000

thread 1105828160 consume 4000225 us

图1看出,gettimeofday走的是vsyscall[1](虚拟系统粗糙的描述就是不经过内核进程的切换就可以调用一段预定好的内核代码),没有线程切换的开销。

图1 gettimeofday 走vsyscall

图2 gettimeofday能将usr态cpu消耗压到100%

因为走vsyscall,没有线程切换,所以多线程运行性能跟单线程是类似的。

$./a.out gettimeofday 12 100000000

gettimeofday(51127820371298) , times : 100000000

thread 1201568064 consume 4111854 us

 

$./a.out clock_gettime 1 100000000

clock_gettime(50265567600696623) , times : 100000000

thread 1107867968 consume 10242448 us

单线程clock_gettime大概每次100ns

图3 clock_gettime 走真正的系统调用

图4 clock_gettime 70%的cpu花在sys态,确实进入了系统调用流程

因为开销集中在系统调用本身,而不是花在进程切换上,所以多线程结果跟单线程类似。

$./a.out clock_gettime 12 100000000

clock_gettime(50369061997211567) , times : 100000000

thread 1122031936 consume 10226828 us

这里说“开销集中在系统调用本身”意思是说clock_gettime本身的执行就非常耗费时间,其大概的调用路径是

clock_gettime -> sys_call -> sys_clock_gettime -> getnstimeofday -> read_tsc -> native_read_tsc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
void  getnstimeofday( struct  timespec *ts)
{
     unsigned  long  seq;
     s64 nsecs;
     WARN_ON(timekeeping_suspended);
do  {
     // 下面代码执行过程中xtime可能会被更改,这里通过持有一个序号来避免显示加锁,如果该代码执行完毕之后,seq并未改变,说明xtime未被更改,此次执行成功,否则重试;无论这里重试与否,CPU都会一直干活;
     seq = read_seqbegin(&xtime_lock);
         *ts = xtime;
         nsecs = timekeeping_get_ns();  //从当前时钟源取更细致的时间精度
         /* If arch requires, add in gettimeoffset() */
         nsecs += arch_gettimeoffset();  // 中断从发出到执行有时间消耗,可能需要做补偿
     while  (read_seqretry(&xtime_lock, seq));
     timespec_add_ns(ts, nsecs);  //时间转换
}
/* Timekeeper helper functions. */
static  inline  s64 timekeeping_get_ns( void )
{
     cycle_t cycle_now, cycle_delta;
     struct  clocksource * clock ;
     /* read clocksource: */
clock  = timekeeper. clock ;
// 使用系统注册的时钟源[2]来读取,当前情况下,一般tsc是默认时钟源
// /sys/devices/system/clocksource/clocksource0/current_clocksource
// 下面的调用最终执行native_read_tsc, 里面就是一条汇编指令rdtsc
     cycle_now =  clock ->read( clock );
     /* calculate the delta since the last update_wall_time: */
     cycle_delta = (cycle_now -  clock ->cycle_last) &  clock ->mask;
     /* return delta convert to nanoseconds using ntp adjusted mult. */
     return  clocksource_cyc2ns(cycle_delta, timekeeper.mult,
                   timekeeper.shift);
}

  

上面说到时钟源是可以替换的,

$cat /sys/devices/system/clocksource/clocksource0/available_clocksource

tsc hpet acpi_pm

这是所有可用的时钟源。硬件出问题或者内核bug有时候会使得tsc不可用,于是时钟源默认会切换到hpet,使用hpet后gettimeofday和clock_gettime性能如何?测试一下。

$sudo bash -c "echo hpet > /sys/devices/system/clocksource/clocksource0/current_clocksource"

$cat /sys/devices/system/clocksource/clocksource0/current_clocksource

hpet

 

$./a.out gettimeofday 1 100000000

gettimeofday(50067118117357) , times : 100000000

thread 1091926336 consume 71748597 us

延时是原来的17倍,大概700ns一次;clock_gettime 与此类似,因为此时瓶颈已经不是系统调用,而是hpet_read很慢。

此时大概的调用路径是

clock_gettime -> sys_call -> sys_clock_gettime -> getnstimeofday -> read_hpet -> hpet_readl –> readl

实现非常直白,但是readl是读时钟设备的内存映射,慢是肯定的了。

 

总结来说,上文制定的内核和glibc版本下,tsc时钟源,gettimeofday 比 clock_gettime快1倍多,适合做计时用(clock_gettime使用CLOCK_REALTIME_COARSE也是很快的);如果因为tsc不稳定(硬件或者内核bug都可能导致,碰到过),hpet一般不会同时出问题,这时hpet成为了新的时钟源,整体性能下降数十倍,两者没啥区别了。

 

[1].     On vsyscalls and the vDSO : http://lwn.net/Articles/446528/

[2].     Linux内核的时钟中断机制 : http://wenku.baidu.com/view/4a9f37f24693daef5ef73d32.html

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
#include <sys/time.h>
#include <iostream>
#include <time.h>
using  namespace  std;
uint64_t now()
{
     struct  timeval tv;
     gettimeofday(&tv, NULL);
     return  tv.tv_sec * 1000000 + tv.tv_usec;
}
void * func_gettimeofday( void * p)
{
     int32_t c = *(int32_t*)p;
     uint64_t start = now();
     uint64_t us = 0;
     int  i = 0;
     while  (i++ < c) {
         struct  timeval tv;
         gettimeofday(&tv, NULL);
         us += tv.tv_usec;  // avoid optimize
     }
     cout <<  "gettimeofday("  << us <<  ") , times : "  << c << endl;
     cout <<  "thread "  << pthread_self() <<  " consume "  << now() - start <<  " us"  << endl;
     return  0;
}
void * func_clockgettime( void * p)
{
     int32_t c = *(int32_t*)p;
     uint64_t start = now();
     uint64_t us = 0;
     int  i = 0;
     while  (i++ < c) {
         struct  timespec tp;
         clock_gettime(CLOCK_REALTIME, &tp);
         us += tp.tv_nsec;
     }
     cout <<  "clock_gettime("  << us <<  ") , times : "  << c << endl;
     cout <<  "thread "  << pthread_self() <<  " consume "  << now() - start <<  " us"  << endl;
     return  0;
}
int  main( int  argc,  char ** argv)
{
     if  (argc != 4) {
         cout <<  " [gettimeofday/clock_gettime] thread_number loop_count"  << endl;
         exit (-1);
     }
     string mode = string(argv[1]);
     int  n =  atoi (argv[2]);
     int  loop =  atoi (argv[3]);
     pthread_t* ts =  new  pthread_t[n];
     for  ( int  i = 0; i < n; i++) {
         if  (mode ==  "gettimeofday" ) {
             pthread_create(ts+i, NULL, func_gettimeofday, &loop);
         else  {
             pthread_create(ts+i, NULL, func_clockgettime, &loop);
         }
     }
     for  ( int  i = 0; i < n; i++) {
         pthread_join(ts[i], NULL);
     }
     delete  [] ts;
     return  0;
}

http://chatgpt.dhexx.cn/article/TQaTtRhy.shtml

相关文章

gettimeofday 函数

使用C语言编写程序需要获得当前精确时间&#xff08;1970年1月1日到现在的时间&#xff09;&#xff0c;或者为执行计时&#xff0c;可以使用gettimeofday()函数。 库为 #include <sys/time.h> 函数原型 int gettimeofday(struct timeval*tv, struct timezone *tz); …

clock_gettime 函数笔记

函数"clock_gettime"是基于Linux C语言的时间函数,他可以用于计算精度和纳秒。 #include<time.h> int clock_gettime(clockid_t clk_id,struct timespec *tp); clk_id : 检索和设置的clk_id指定的时钟时间。 CLOCK_REALTIME:系统实时时间,随系统实时时间改变…

date.gettime()与时间的获取

date.gettime()返回的是什么&#xff1f; java.util.Date ----------- date.getTime()返回的是什么&#xff1f; 问题&#xff1a; ------------- Date date new Date(); System.out.println(date.getTime()); 输出结果是1210745780625 编译时间当时时间大概是2008年5…

Linux下clock_gettime函数详解

要包含这头文件<time.h> 且在编译链接时需加上 -lrt ;因为在librt中实现了clock_gettime函数。 --- struct timespec ts; clock_gettime(CLOCK_MONOTONIC,ts); printf("%d %d",ts.tv_sec, ts.tv_nsec);打印出来的时间跟 cat /proc/uptime第一个参数一样 /proc/…

Gettimeofday的用法

先看gettimeofday的语法定义&#xff1a; 使用前先包含头文件#include<sys/time.h> 第一个参数&#xff1a;是个timeval *类型的结构体&#xff0c;该结构体如下 timeval.tv_sec 就是秒呗 timeval.tv_usec 就是微秒 一般我们使用gettimeofday是用来…

Java中Date类中getTime()方法

public long getTime() 返回自1970年1月1日以来&#xff0c;由 Date对象表示的00:00:00 GMT的毫秒 数 。 结果 自1970年1月1日以来&#xff0c;以此日期为准的00:00:00 GMT的毫秒数。 这是JDK文档中对于getTime()方法的官方解读 在我实际使用中发现这个方法可以解决日期月日输…

PPT插入视频

最近需要在PPT中插入一段视频&#xff0c;但是发现在插入的时候并不是一帆风顺&#xff0c;所以在这里做一下记录。 1、可能出现如下的提示 2、解决的办法 在OFFICE2010中插入视屏和音频文件时, 注意应确认是微软的格式, 即wmv及wma格式, 否则即使插入后, 在插入时也可能出现…

怎么将PPT中的视频文件保存下来

先右键包含视频的PPT文件&#xff0c;选择‘打开方式’&#xff0c;打开方式的子菜单栏中有一个选择其他应用。 因为我之前操作过&#xff0c;所以会显示那个WinRAR的应用程序&#xff0c;第一个使用的话一般不会出现&#xff0c;点击‘更多应用’&#xff0c;找到‘在这台电脑…

如何在PPT中自动同时播放两个视频

嵌入视频 视频工具中选择自动播放 动画中第二个视频选择和上一动画同时

从视频中提取图片(截取ppt)

从视频中提取图片 大聪明2.0上线 本文将介绍如何快速从网课视频中提取ppt Step1 从视频中提取图片 使用win自带的“电影与电视” 点击这个小铅笔&#xff0c;选择“保存视频中的照片” 在弹出的新窗口内就可以将视频按一帧一帧的照片展示出来&#xff0c;对想要保存的照片点击…

PPt插入视频同时播放

1.导入需要的三个视频 2.对每个视频在 动画 里面设置为 播放 3.选择第一个视频的 4.其他的视频设置为

wps——ppt中的视频提取

在写小丸工具箱时我已经删除了自己录的视频&#xff0c;只有ppt中有存稿&#xff0c;在查阅后成功的提取视频文件。这里要骂骂骂wps没有媒体视频另存为的选项要不然也不需要在ppt外部进行处理。&#xff08;如果是我没有找到&#xff0c;那烦请提醒我这个选项在那里&#xff0c…

如何使用计算机讲解ppt,如何录制PPT讲解视频?

录制PPT视频方式推荐 如何在电脑上录制PPT视频&#xff1f;本文介绍了三种方案&#xff0c;让你轻松将幻灯片录制为视频。 Microsoft PowerPoint 微软Office自带录制幻灯片功能&#xff0c;需要注意的是Office 2007版本没有此功能&#xff0c;可以先升级到高版本的Office&#…

PPT幻灯片放映时不显示视频(旁白)

问题&#xff1a;PPT录制的视频在非放映的时候可以播放&#xff0c;但是进入幻灯片放映模式就不显示。 解决方法&#xff1a;幻灯片放映 → \rightarrow → 播放旁白 勾选上。

PPT制作相册视频

目标&#xff1a;使用免费工具将图片快速转为视频&#xff0c;实现视频上传抖音、微视频。 工具 PowerPoint 2019等新版本格式工厂 PPT制作 制作一个自动播放的PPT 打开PPT插入相册&#xff1a;插入->相册。插入照片用于制作电子相册动画设置&#xff1a;设置单页PPT内不…

PPT录制视频的方法有哪些?分享5种亲测好用的方法

PPT文稿可以通过图文或者动画的形式&#xff0c;直观形象地把内容展现给观众&#xff0c;从而给观众留下深刻的印象。比如老师讲课时会用到PPT&#xff0c;公司开会时也会用到PPT。除了需要使用到PPT文稿之外&#xff0c;有时还要对它进行录制。 那你知道PPT录制视频的方法有哪…

计算机课怎样制作ppt 课件,如何制作PPT课件视频

由于计算机的大量普及和多媒体技术的发展&#xff0c;使用多媒体上课已经是一种常见的事。我们在课堂和线上学习时&#xff0c;经常可以看到老师制作的相关知识的PPT课件。虽然我们都知道PPT课件是由PPT制作的幻灯片&#xff0c;可还是比较好奇老师是如何把一段完整PPT课件视频…

PPT 录制视频

有时候&#xff0c;需要使用PPT录制视频&#xff0c;比如在线学术会议需要上传录制好的video。具体如何操作呢&#xff1f; 选择 幻灯片放映 --> 录制幻灯片演示 --> 从头开始录制 这样录制结束后&#xff0c;每一页会多了一个音频&#xff0c;这就是录入的 旁白。 选择…

【从ppt里导出视频的方法】

找到ppt文件 在查看里显示后缀 Win xp&#xff1a;https://jingyan.baidu.com/article/2a1383285f0bd4464b134f56.html Win7&#xff1a;https://jingyan.baidu.com/article/8ebacdf005661108f65cd5b7.html Win8&#xff1a;https://jingyan.baidu.com/article/6d704a132cd46d6…

办公小技巧:ppt怎么录视频?

ppt怎么录视频&#xff1f;办公软件中最常用到的软件有哪个&#xff1f;基本上都是word、excel、ppt、pdf这四个是最为常用的&#xff0c;当你想要制作宣传海报的时候你会选择哪个软件呢&#xff1f;是的&#xff0c;选择ppt是最合适的。 ppt最被人常用到的就是用于制作宣传广告…