0%

cpp time

时间分类

  1. real time 和 处理器时间(process time)
    从某个点测量的真实时间,比如从1970年开始的,或者从进程启动时候的点开始;
    进程使用CPU的时间,分用户时间(运行在用户态)和系统时间(运行在内核态)
  2. 硬件时间(hardware clock)
    一个带电池的硬件,内核在启动时候从这里初始化开始时间
  3. 软件时间(software clock, HZ, jiffy)
    大多数系统调用设置超时和测量时间的精度取决于HZ,是内核维护的一个最小精度,HZ取决于操作系统和硬件,最早是100,后来有100,250,300,1000
  4. 高精度定时器
    在 2.6.21 之前,定时器的精度取决于 jiffy; 从这个版本开始, linux支持使用高精度定时器硬件来设置定时器
  5. Epoch
    1970-01-01 00:00:00 +0000 (UTC) 开始的秒数
  6. Broken-down time
    struct tm 描述时间的各个部分,年月日分开

几个时间结构

  1. clock_t CPU时钟滴答
    要知道过了多少秒,需要除 CLOCKS_PER_SEC

  2. struct tms 进程运行时间

    1
    2
    3
    4
    5
    6
    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 */
    };
  3. struct timeval 精确到微秒

    1
    2
    3
    4
    struct timeval {
    time_t tv_sec; /* seconds */
    suseconds_t tv_usec; /* microseconds */
    };
  4. struct timespec 精确到纳秒

    1
    2
    3
    4
    struct timespec {
    time_t tv_sec; /* seconds */
    long tv_nsec; /* nanoseconds */
    };
  5. time_t 时间戳,精确到秒

  6. struct tm brokentime,年月日

  7. struct itimerspec 定时器使用,精确到纳秒
    struct itimerspec {
    struct timespec it_interval; /* Timer interval /
    struct timespec it_value; /
    Initial expiration */
    };

时间应用的地方

  1. 获取墙上时间
    (2)time_t time(time_t *t); // 精确到秒
    (2)int clock_gettime(clockid_t clk_id, struct timespec *tp); // 精确到纳秒,推荐
    (2)int gettimeofday(struct timeval *tv, struct timezone *tz); // 精确到毫秒,不再推荐

  2. 获取程序运行CPU时间(用户、系统)
    (2)clock_t clock(void); // 最简单的CPU时间,会回绕
    (2)clock_t times(struct tms *buf); // 获取CPU时间, 还知道child的时间, clock_t
    (2)int getrusage(int who, struct rusage *usage); // 跟times获取的结果差不多, 但不知道child的

(3)int clock_getcpuclockid(pid_t pid, clockid_t *clock_id); // 获取某个进程的定时器,配合clock_gettime(2)也能知道CPU时间

  1. 定时器
    // 精确到毫秒, 信号通知
    (2)int getitimer(int which, struct itimerval *curr_value);
    (2)int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);

// 精确到纳秒,信号通知
(2)int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);
(2)int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value);
(2)int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
(2)int timer_getoverrun(timer_t timerid);
(2)int timer_delete(timer_t timerid);

// 精确到纳秒,fd通知, 可以集成到 epoll, 推荐
(2)int timerfd_create(int clockid, int flags);
(2)int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
(2)int timerfd_gettime(int fd, struct itimerspec *curr_value);

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
// 获取当前进程占用的CPU时间,返回的值是clock,每秒的clock数量可以用 sysconf(_SC_CLK_TCK); 获取
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 */
};
(2)clock_t times(struct tms *buf);


// 获取进程占用的资源,里边也有时间
struct rusage {
struct timeval ru_utime; /* user CPU time used */
struct timeval ru_stime; /* system CPU time used */
long ru_maxrss; /* maximum resident set size */
long ru_ixrss; /* integral shared memory size */
long ru_idrss; /* integral unshared data size */
long ru_isrss; /* integral unshared stack size */
long ru_minflt; /* page reclaims (soft page faults) */
long ru_majflt; /* page faults (hard page faults) */
long ru_nswap; /* swaps */
long ru_inblock; /* block input operations */
long ru_oublock; /* block output operations */
long ru_msgsnd; /* IPC messages sent */
long ru_msgrcv; /* IPC messages received */
long ru_nsignals; /* signals received */
long ru_nvcsw; /* voluntary context switches */
long ru_nivcsw; /* involuntary context switches */
};
(2)int getrusage(int who, struct rusage *usage);

// 获取CPU时间, 要获取秒数需要 /CLOCKS_PER_SEC
(2)clock_t clock(void);
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
clockid_t:
CLOCK_REALTIME // 墙上时间, ns
CLOCK_REALTIME_COARSE // 精度不高的墙上时间,ms
CLOCK_MONOTONIC // 类似CLOCK_REALTIME
CLOCK_MONOTONIC_COARSE // 类似CLOCK_REALTIME_COARSE
CLOCK_MONOTONIC_RAW // 类似CLOCK_MONOTONIC
CLOCK_BOOTTIME // 跟CLOCK_MONOTONIC一样
CLOCK_PROCESS_CPUTIME_ID // CPU使用的高精度定时器,跟SMP相关
CLOCK_THREAD_CPUTIME_ID // 线程定时器,跟SMP相关
struct timespec {
time_t tv_sec; /* seconds */
long tv_nsec; /* nanoseconds */
};
// 获取时钟分辨率
(2)int clock_getres(clockid_t clk_id, struct timespec *res);
// 获取和设置时钟
(2)int clock_gettime(clockid_t clk_id, struct timespec *tp);
(2)int clock_settime(clockid_t clk_id, const struct timespec *tp);



// 获取墙上时间(2)
// 跟 clock_gettime 差不多,但获取的时间可能会不连续,clock_gettime(2)可以用CLOCK_MONOTONIC获取连续的墙上时间
// POSIX.1-2008不要这个函数了,推荐用 clock_gettime(2)
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
(2)int gettimeofday(struct timeval *tv, struct timezone *tz);
(2)int settimeofday(const struct timeval *tv, const struct timezone *tz);


// 设置个时间间隔,让系统慢慢调整为正确的墙上时间,比如设置一个正数,会每秒加快一些,直到调整到设置的数值
(3)int adjtime(const struct timeval *delta, struct timeval *olddelta);
// 这个是内核调用,一般用adjtime
(2)int adjtimex(struct timex *buf);

操作 struct timeval

1
2
3
4
5
6
7
8
9
// res=a+b
void timeradd(struct timeval *a, struct timeval *b, struct timeval *res);
// res=a-b
void timersub(struct timeval *a, struct timeval *b, struct timeval *res);
void timerclear(struct timeval *tvp);
// tvp设置了非零值
int timerisset(struct timeval *tvp);
// CMP: >, <, !=
int timercmp(struct timeval *a, struct timeval *b, CMP);

每进程的时钟

1
2
3
4
5
6
// 获取某个进程的clockid,然后配合 clock_gettime(2) 获取该进程的cpu时间
(3)int clock_getcpuclockid(pid_t pid, clockid_t *clock_id);
// 获取线程的
(3)int pthread_getcpuclockid(pthread_t thread, clockid_t *clock_id);


定时器

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
// 设置定时器,到期使用信号通知
struct itimerval {
struct timeval it_interval; /* next value */
struct timeval it_value; /* current value */
};
struct timeval {
time_t tv_sec; /* seconds */
suseconds_t tv_usec; /* microseconds */
};
which:
ITIMER_REAL 在实时时间定时
ITIMER_VIRTUAL 在用户时间定时
ITIMER_PROF 在CPU时间定时(包括用户和系统时间)
(2)int getitimer(int which, struct itimerval *curr_value);
(2)int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);


// 创建定时器,到期使用信号通知,比setitimer(2)更通用,包括SMP的考虑
(2)int timer_create(clockid_t clockid, struct sigevent *sevp, timer_t *timerid);
(2)int timer_settime(timer_t timerid, int flags, const struct itimerspec *new_value, struct itimerspec * old_value);
(2)int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
(2)int timer_getoverrun(timer_t timerid);
(2)int timer_delete(timer_t timerid);


// 使用fd设置定时器,到期使用fd通知
(2)int timerfd_create(int clockid, int flags);
(2)int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
(2)int timerfd_gettime(int fd, struct itimerspec *curr_value);
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
// 1. 获取时间
// time_t 时间戳
(2)time_t time(time_t *t); // 获取当前时间戳 time_t

// 2.
// 将 time_t 转换成UTC时间,
struct tm *gmtime(const time_t *timep);
struct tm *gmtime_r(const time_t *timep, struct tm *result);

// 将 time_t 转换成当地时间,受tzset(3)影响
struct tm *localtime(const time_t *timep);
struct tm *localtime_r(const time_t *timep, struct tm *result);

// 将 time_t 转换成 "Wed Jun 30 21:49:08 1993\n" 这样的格式
char *ctime(const time_t *timep);
char *ctime_r(const time_t *timep, char *buf);

// 将 struct tm 转换成 "Wed Jun 30 21:49:08 1993\n" 这样的格式
char *asctime(const struct tm *tm);
char *asctime_r(const struct tm *tm, char *buf);

// 将 struct tm 转换成 time_t
time_t mktime(struct tm *tm);

// 格式化的字符串转换成 struct tm
char *strptime(const char *s, const char *format, struct tm *tm);

// struct tm 格式化成字符串
size_t strftime(char *s, size_t max, const char *format, const struct tm *tm);

c++11的时间库chrono

3个类型

  1. Clocks
    system_clock: 系统获取的时钟, 常用这个
    steady_clock: 不能被修改的时钟
    high_resolution_clock: 高精度时钟

system_clock::now() // 返回 std::chrono::time_point 获取当前时刻
system_clock::to_time_t() // 返回 std::time_t 时间戳
system_clock::from_time_t() // std::time_t变回time_point

  1. Time point
    time_point: 特定clock从开始时间流逝的时间段

time_since_epoch() // 返回从开始时间到现在的时间间隔
time_point_cast<>

  1. Duration
    duration: 时间段

count() // 周期数
duration_cast<>() // 转换成另一种类型的时间间隔

template<std::intmax_t Num, std::intmax_t Denom = 1> class ratio; // 分辨率,Num/Denom 秒
template<class Rep, class Period = std::ratio<1>> class duration; // 时间间隔, Rep个分辨率

常用分辨率:
typedef duration <Rep, ratio<3600,1>> hours;
typedef duration <Rep, ratio<60,1>> minutes;
typedef duration <Rep, ratio<1,1>> seconds;
typedef duration <Rep, ratio<1,1000>> milliseconds;
typedef duration <Rep, ratio<1,1000000>> microseconds;
typedef duration <Rep, ratio<1,1000000000>> nanoseconds;

std::chrono::seconds(3) // 3秒

duration.count() 获取当前分辨率下的时钟周期个数,比如 seconds(3).count() == 3, hours(4).count() == 4

  • 格式化输出
    auto t = chrono::system_clock::to_time_t(std::chrono::system_clock::now());
    cout<< std::put_time(std::localtime(&t), “%Y-%m-%d %X”)<<endl;
    cout<< std::put_time(std::localtime(&t), “%Y-%m-%d %H.%M.%S”)<<endl;