码迷,mamicode.com
首页 > 其他好文 > 详细

KVM虚拟化技术-实战与原理解析

时间:2017-04-10 21:51:09      阅读:332      评论:0      收藏:0      [点我收藏+]

标签:包括   spec   stopped   epoll   分辨率   efi   结构体   ctr   暂停   

第23章 定时器与休眠

1.间隔定时器setitimer和alarm

两个重要的结构体:定时器参数struct itimerval和表示时间struct timerval。

struct itimerval {
    struct timeval it_interval;     /* Interval for periodic timer */
    struct timeval it_value;        /* Current value (time until next expiration) */  为0则是一次性定时器。
};

struct timeval {
    time_t      tv_sec;             /* Seconds */
    suseconds_t tv_usec;            /* Microseconds (long int) */
};

setitimer和alarm原型:

#include <sys/time.h>
int setitimer(int which, const struct itimerval *new_value, struct itimerval *old_value);
    Returns 0 on success, or –1 on error
int getitimer(int which, struct itimerval *curr_value);
    Returns 0 on success, or –1 on error

#include <unistd.h>
unsigned int alarm(unsigned int seconds);
    Always succeeds, returning number of seconds remaining on any previously set timer, or 0 if no timer previously was set

setitimer可以指定三种不同类型定时器:ITIMER_REAL(SIGALARM)、ITIMER_VIRTUAL(SIGVTALRM)、ITIMER_PROF(SIGPROF)。

  • 进程只能拥有三种定时器的一种。
  • alarm()和setitimer()针对统一进程共享同一实时定时器。
  • 三种定时器的参考时间不同,ITIMER_REAL(真实时间)、ITIMER_VIRTUAL(进程虚拟时间,用户CPU时间)、ITIMER_PROF(进程的用户和内核时间总和)。
  • 如果这些信号不设置处理函数,则默认会终止进程。

2.定时器的调度及精度

  • 系统可能会在定时器到期的瞬间之后才去调度其所属进程,这取决于当前负载和对进程的调度。
  • setitimer()定时器虽然可能延迟一定时间,但是后续的定时器仍然按照固定间隔。比如2秒定时器,2.3超时,下一个应该在4.3秒超时。
  • 虽然setitimer精度达到微妙,但是受制于软件时钟频率。比如jiffy为4ms,间隔为19100微妙,实际间隔是20ms。
  • 高分辨率定时器需要内核CONFIG_HIGH_RES_TIMERS。

3.为阻塞操作设置超时

4.休眠一段时间

低分辨率休眠sleep()

#include <unistd.h>
unsigned int sleep(unsigned int seconds);
    如果休眠正常结束,返回0。如果被中断,返回剩余秒数。可能由于系统负载调度原因,会在sleep到时候才对进程重新加以调度。

高分辨率休眠nanosleep()

#define _POSIX_C_SOURCE 199309
#include <time.h>
int nanosleep(const struct timespec *request, struct timespec *remain);
    Returns 0 on successfully completed sleep, or –1 on error or interrupted sleep

request指定了休眠持续时间,理论上精度可以达到纳秒级,但受制于软件时钟间隔。如果间隔并非间隔值,者向上取整。

nanosleep()不基于信号实现,但是可以通过型号处理函数来中断,如SIGINT(Ctrl-C)。
再被中断之后,剩余时间可以通过remain中获取。将remain赋给request,则可以继续睡眠剩余时间。

 

 

5.POSIX时钟

POSIX时钟API必须以-lrt选项进行编译,从而与librt函数库链接,主要系统调用包括获取当前值的clock_gettime()、返回时钟分辨率的clock_getres()、以及更新时钟的clock_settime()。

要测定特定进程或线程所消耗的CPU时间,可以借助clock_getcpuclockid/pthread_getcpuclockid来获取时钟ID,接着再以此返回ID去调用clock_gettime(),从而获得进程或线程耗费的CPU时间。pid为0是,clock_getcpuclockid()返回调用进程的CPU时间时钟ID。

#define _POSIX_C_SOURCE 199309
#include <time.h>
int clock_gettime(clockid_t clockid, struct timespec *tp);
int clock_getres(clockid_t clockid, struct timespec *res);
    Both return 0 on success, or –1 on error

int clock_settime(clockid_t clockid, const struct timespec *tp);
    Returns 0 on success, or –1 on error

int clock_getcpuclockid(pid_t pid, clockid_t *clockid);
    Returns 0 on success, or a positive error number on error

int pthread_getcpuclockid(pthread_t thread, clockid_t *clockid);
    Returns 0 on success, or a positive error number on error

int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain);
    Returns 0 on successfully completed sleep or a positive error number on error or interrupted sleep

Linux特有的clock_nanosleep()系统调用也可以暂停调用进程,知道经理一段指定时间,亦或是收到信号才恢复运行。

int clock_nanosleep(clockid_t clockid, int flags, const struct timespec *request, struct timespec *remain);
Returns 0 on successfully completed sleep,or a positive error number on error or interrupted sleep

默认情况下(flags为0),request指定休眠间隔是相对时间;如果flags设定TIMER_ABSTIME,request则表示clockid时钟所测量的绝对时间。

相对时间问题:如果只是先获取当前时间,计算与目标时间差距,再以相对时间进行休眠,进程可能执行到一半就奔抢占了,结果实际休眠时间回避预期要久。如果被信号处理函数中断并使用循环重启休眠,则“嗜睡”问题尤其明显。如果信号频率很高,则按相对时间休眠的进程则会有较大时间误差。

避免嗜睡问题:先调用clock_gettime()获取时间,加上期望休眠的时间量,再以TIMER_ABSTIME标识调用clock_nanosleep()函数。指定TIMER_ABSTIME,不再使用参数remain。如果信号中断clock_nanosleep()调用,再次调用该函数来重启休眠时,request参数不变。clock_nanosleep()和nanosleep()另一区别在可以选择不同的时钟来测量休眠间隔时间。

6.POSIX间隔式定时器

 

#define _POSIX_C_SOURCE 199309
#include <signal.h>
#include <time.h>
int timer_create(clockid_t clockid, struct sigevent *evp,timer_t *timerid);
    Returns 0 on success, or –1 on error

int timer_settime(timer_t timerid, int flags,const struct itimerspec *value, struct itimerspec *old_value);
    Returns 0 on success, or –1 on error

int timer_gettime(timer_t timerid, struct itimerspec *curr_value);
    Returns 0 on success, or –1 on error

int timer_delete(timer_t timerid);
    Returns 0 on success, or –1 on error

int timer_getoverrun(timer_t timerid);
    Returns timer overrun count on success, or –1 on error

CLOCK_REALTIME时钟是一种系统级时钟,用于度量真实时间。

CLOCK_MONOTONIC系统启动后就不会发生改变,适用于那些无法容忍系统时钟发生跳跃性变化的应用。Linux上这种时钟对事件的测量食欲系统启动。

CLOCK_PROCESS_CPUTIME_ID时钟测量调用进程所消耗的用户和系统CPU时间。

CLOCK_THREAD_CPUTIME_ID时钟用于测量进程中单条线程的用户和系统CPU时间。

技术分享

7.文件描述符定时器:timerfd API

Linux特有的timerfd API,可以从文件描述符中读取其所创建定时器的到期通知,也可以用使用select()、poll()、epoll()监控。

#include <sys/timerfd.h>
int timerfd_create(int clockid, int flags);
clockid可以设置为CLOCK_REALTIME或者CLOCK_MONOTONIC。
相当于open创建一个句柄,可以使用close()关闭响应文件描述符。

int timerfd_settime(int fd, int flags, const struct itimerspec *new_value, struct itimerspec *old_value);
int timerfd_gettime(int fd, struct itimerspec *curr_value);

timerfd_settime()启动了定时器,可以通过read()来读取定时器到期信息。read缓冲区必须容纳uint64_t类型,读取返回值是已发生的到期次数。

执行./demo_timerfd 1:1 100,使用Ctrl-Z将其变成挂起到背景执行,fg拉倒前台,Ctrl-C终止执行。可以看出在背景执行期间有10此到期。

./demo_timerfd 1:1 100
1.000: expirations read: 1; total=1
2.000: expirations read: 1; total=2
3.000: expirations read: 1; total=3
4.000: expirations read: 1; total=4
^Z
[2]+  Stopped                 ./demo_timerfd 1:1 100
fg
./demo_timerfd 1:1 100
14.734: expirations read: 10; total=14
15.000: expirations read: 1; total=15
16.000: expirations read: 1; total=16
17.000: expirations read: 1; total=17
18.000: expirations read: 1; total=18
^Z
[2]+  Stopped                 ./demo_timerfd 1:1 100

8.总结

setitimer()和alarm()设定定时器,以便于在经历指定的一段实际时间后收到信号通知。

sleep()和nano_sleep()指定程序暂停执行一段特定间隔的实际时间。

timerfd_create()、timerfd_settime()、timerfd_gettime()提供一组创建定时器的接口,允许从文件秒速附中读取特定定时器通知。可以使用read()、select()、poll()、epoll()、close()来操作这些描述符。

KVM虚拟化技术-实战与原理解析

标签:包括   spec   stopped   epoll   分辨率   efi   结构体   ctr   暂停   

原文地址:http://www.cnblogs.com/arnoldlu/p/6681915.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!