如何在Linux中获得最准确的实时周期性中断?

前端之家收集整理的这篇文章主要介绍了如何在Linux中获得最准确的实时周期性中断?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我希望在10的幂的频率下被中断,因此启用/ dev / rtc的中断并不理想.我想在中断之间睡1毫秒或250微秒.

从/ dev / hpet启用定期中断非常有效,但它似乎在某些机器上不起作用.显然我不能在没有HPET的机器上使用它.但是我无法让它在一些可以作为时钟源使用的机器上工作.例如,在Core 2 Quad上,当设置为poll时,内核文档中包含的示例程序在HPET_IE_ON处失败.

使用Linux提供的itimer接口而不是直接与硬件设备驱动程序连接会更好.在某些系统上,itimer提供的定期中断随着时间的推移更加稳定.也就是说,由于hpet不能以我想要的频率中断,因此中断开始从挂起时间开始漂移.但我看到一些系统比使用itimer更长时间(10毫秒)睡眠.

这是一个使用itimer进行中断的测试程序.在某些系统上,它只打印出一个警告,它在目标时间内睡眠约100微秒左右.在其他情况下,它将打印出批次警告,它在目标时间内睡了10毫秒.用-lrt编译并运行sudo chrt -f 50 [name]

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <unistd.h>
  4. #include <error.h>
  5. #include <errno.h>
  6. #include <sys/ioctl.h>
  7. #include <sys/types.h>
  8. #include <sys/time.h>
  9. #include <time.h>
  10. #include <signal.h>
  11. #include <fcntl.h>
  12. #define NS_PER_SECOND 1000000000LL
  13. #define TIMESPEC_TO_NS( aTime ) ( ( NS_PER_SECOND * ( ( long long int ) aTime.tv_sec ) ) \
  14. + aTime.tv_nsec )
  15.  
  16. int main()
  17. {
  18. // Block alarm signal,will be waited on explicitly
  19. sigset_t lAlarm;
  20. sigemptyset( &lAlarm );
  21. sigaddset( &lAlarm,SIGALRM );
  22. sigprocmask( SIG_BLOCK,&lAlarm,NULL );
  23.  
  24. // Set up periodic interrupt timer
  25. struct itimerval lTimer;
  26. int lReceivedSignal = 0;
  27.  
  28. lTimer.it_value.tv_sec = 0;
  29. lTimer.it_value.tv_usec = 250;
  30. lTimer.it_interval = lTimer.it_value;
  31.  
  32. // Start timer
  33. if ( setitimer( ITIMER_REAL,&lTimer,NULL ) != 0 )
  34. {
  35. error( EXIT_FAILURE,errno,"Could not start interval timer" );
  36. }
  37. struct timespec lLastTime;
  38. struct timespec lCurrentTime;
  39. clock_gettime( CLOCK_REALTIME,&lLastTime );
  40. while ( 1 )
  41. {
  42. //Periodic wait
  43. if ( sigwait( &lAlarm,&lReceivedSignal ) != 0 )
  44. {
  45. error( EXIT_FAILURE,"Failed to wait for next clock tick" );
  46. }
  47. clock_gettime( CLOCK_REALTIME,&lCurrentTime );
  48. long long int lDifference =
  49. ( TIMESPEC_TO_NS( lCurrentTime ) - TIMESPEC_TO_NS( lLastTime ) );
  50. if ( lDifference > 300000 )
  51. {
  52. fprintf( stderr,"Waited too long: %lld\n",lDifference );
  53. }
  54. lLastTime = lCurrentTime;
  55. }
  56. return 0;
  57. }

解决方法

裸机setitimer()设置我遇到了同样的问题.
问题是默认情况下,您的进程由静态优先级0的SCHED_OTHER策略调度.这意味着您在所有其他进程的池中,并且动态优先级决定.有一些系统负载的那一刻,你会得到延迟.

解决方案是使用sched_setscheduler()系统调用,将静态优先级提高到至少一个,并指定SCHED_FIFO策略.它引起了戏剧性的改善.

  1. #include <sched.h>
  2. ...
  3. int main(int argc,char *argv[])
  4. {
  5. ...
  6. struct sched_param schedp;
  7. schedp.sched_priority = 1;
  8. sched_setscheduler(0,SCHED_FIFO,&schedp);
  9. ...
  10. }

您必须以root身份运行才能执行此操作.另一种方法是使用chrt程序执行相同操作,但您必须知道RT过程的PID.

  1. sudo chrt -f -p 1 <pid>

请参阅我的博客文章here.

猜你在找的Linux相关文章