2208-程序计时方法

常用的程序计时方法,总结来自师兄

方法1:time

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
#include <stdio.h>
#include <time.h>

int main()
{
time_t tm_now;

time(&tm_now);

// 1970-1-1,00:00:00到现在的秒数
printf("now time is %ld second\\n", tm_now);

// 转换成本地时间,精确到秒
struct tm *p_local_tm ;
p_local_tm = localtime(&tm_now) ;
printf("now datetime: %04d-%02d-%02d %02d:%02d:%02d\\n",
p_local_tm->tm_year+1900,
p_local_tm->tm_mon+1,
p_local_tm->tm_mday,
p_local_tm->tm_hour,
p_local_tm->tm_min,
p_local_tm->tm_sec);

return 0;
}

方法2:gettimeofday

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
#include <stdio.h>
#include <sys/time.h>
#include <time.h>

int main()
{
struct timeval tm_now;

// 获取当前时间戳(tv_sec, tv_usec)
gettimeofday(&tm_now,NULL); // 第二个参数是时区

// 转换成本地时间,精确到秒
struct tm *p_local_tm;
p_local_tm = localtime(&tm_now.tv_sec) ;
printf("now datetime: %04d-%02d-%02d %02d:%02d:%02d.%06ld\\n",
p_local_tm->tm_year+1900,
p_local_tm->tm_mon+1,
p_local_tm->tm_mday,
p_local_tm->tm_hour,
p_local_tm->tm_min,
p_local_tm->tm_sec,
tm_now.tv_usec); // 有微秒时间戳了

return 0;
}

方法3:clock_gettime

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
#include <stdio.h>
#include <unistd.h>
#include <time.h>

void print_timestamp(int use_monotonic)
{
struct timespec tm_now;

// 获取当前时间戳(tv_sec, tv_usec)
if(use_monotonic)
clock_gettime(CLOCK_MONOTONIC, &tm_now);
// 单调时间,屏蔽手动修改时间
else
clock_gettime(CLOCK_REALTIME, &tm_now);
// 机器时间

// 转换成本地时间,精确到秒
struct tm *p_local_tm;
p_local_tm = localtime(&tm_now.tv_sec) ;
printf("now datetime: %04d-%02d-%02d %02d:%02d:%02d.%09ld\\n",
p_local_tm->tm_year+1900,
p_local_tm->tm_mon+1,
p_local_tm->tm_mday,
p_local_tm->tm_hour,
p_local_tm->tm_min,
p_local_tm->tm_sec,
tm_now.tv_nsec);
// 纳秒时间
}

方法4:chrono库

1
2
3
4
5
6
7
8
9
#include<chrono>

auto start = std::chrono::system_clock::now();

...

auto end = std::chrono::system_clock::now();
std::chrono::duration<double> elapsed_seconds = end - start;
time1 = elapsed_seconds.count();

方法5:rdtsc

最精准也是最难用的方法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
uint64_t get_tsc() // Time Stamp Counter寄存器
{
#ifdef __i386__
uint64_t x;
__asm__ volatile("rdtsc" : "=A"(x));
return x;
#elif defined(__amd64__) || defined(__x86_64__)
uint64_t a, d;
__asm__ volatile("rdtsc" : "=a"(a), "=d"(d));
return (d << 32) | a;
#else // ARM架构
uint32_t cc = 0;
__asm__ volatile ("mrc p15, 0, %0, c9, c13, 0":"=r" (cc));
return (uint64_t)cc;
#endif
}

使用限制:

  1. 机器需要有constant_tsc的特性,使用:cat /proc/cpu_info | grep constant_tsc 命令可以确定是否有该特性
  2. 乱序执行核能会打乱时钟周期的测量,必要时需要制造“依赖指令”去避免乱序执行
  3. 必要时需要使用memory barrier
  4. cat /proc/cpuinfo | grep rdtscp 如果开启,可以使用rdtscp,更精准一点。使用方法基本一致:
    1
    uint64_t get_tscp() { uint64_t a, d; __asm__ volatile("rdtscp" : "=a"(a), "=d"(d)); return (d << 32) | a; }

小结

  • 如果使用C++,那么使用chrono库是最好的选择,相信STL不会翻大车
  • 如果机器有constant tsc特性,那么可以使用rdtsc方法
  • 如果没有,那么使用gettimeofday时一个比较稳定的方法

2208-程序计时方法
https://piscesfinalizer.github.io/2022/08/04/程序计时方法/
作者
PiscesFinalizer
发布于
2022年8月4日
许可协议