【问题标题】:What causes the virtual run time to go slow when using setitimer() and ITIMER_VIRTUAL?使用 setitimer() 和 ITIMER_VIRTUAL 时,是什么导致虚拟运行时间变慢?
【发布时间】:2018-02-20 02:09:27
【问题描述】:

为了研究ITMER_REALITIMER_VIRTUAL 之间的区别,我整理了以下程序。

#include <stdlib.h>   // exit(), EXIT_FAILURE, EXIT_SUCCESS
#include <signal.h>   // sigaction()
#include <stdio.h>    // printf(), fprintf(), stdout, stderr, perror(), _IOLBF
#include <string.h>   // memset()
#include <sys/time.h> // ITIMER_REAL, ITIMER_VIRTUAL, ITIMER_PROF, struct itimerval, setitimer()
#include <stdbool.h>  // true, false 
#include <limits.h>   // INT_MAX

#define TIMEOUT    50             // ms 
#define TIMER_TYPE ITIMER_VIRTUAL // Type of timer.


/* The three types of timers causes different signals.

   type: type of timer, one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF.

   return value: the signal generated by the timer.

 */
int timer_signal(int timer_type) {
  int sig;

  switch (timer_type) {
    case ITIMER_REAL:
      sig = SIGALRM;
      break;
    case ITIMER_VIRTUAL:
      sig = SIGVTALRM;
      break;
    case ITIMER_PROF:
      sig = SIGPROF;
      break;
    default:
      fprintf(stderr, "ERROR: unknown timer type %d!\n", timer_type);
      exit(EXIT_FAILURE);
  }

  return sig;
}


/* Set a timer and a handler for the timer.

   Arguments

   type: type of timer, one of ITIMER_REAL, ITIMER_VIRTUAL, or ITIMER_PROF.

   handler: timer signal handler.

   ms: time in ms for the timer. 

 */
void set_timer(int type, void (*handler) (int), int ms) {
  struct itimerval timer;
  struct sigaction sa;

  /* Install signal handler for the timer. */
  memset (&sa, 0, sizeof (sa));
  sa.sa_handler =  handler;
  sigaction (timer_signal(type), &sa, NULL);

  /* Configure the timer to expire after ms msec... */
  timer.it_value.tv_sec = 0;
  timer.it_value.tv_usec = ms*1000;
  timer.it_interval.tv_sec = 0;
  timer.it_interval.tv_usec = 0;

  if (setitimer (type, &timer, NULL) < 0) {
    perror("Setting timer");
    exit(EXIT_FAILURE);
  };
}

/* Timer signal handler. */
void timer_handler (int signum) {
  static int count = 0;
  fprintf (stderr, "======> timer (%03d)\n", count++);
  set_timer(TIMER_TYPE, timer_handler, TIMEOUT);
}


/* Calculate the nth Fibonacci number using recursion. */
int fib(int n) {
  switch (n) {
    case 0:
      return 0;
    case 1:
      return 1;
    default:
      return fib(n-1) + fib(n-2);
  }
}

/* Print the Fibonacci number sequence over and over again.

   This is deliberately an unnecessary slow and CPU intensive
   implementation where each number in the sequence is calculated recursively
   from scratch.
*/

void fibonacci_slow() {
  int n = 0;
  while (true) {
    printf(" fib(%d) = %d\n", n, fib(n));
    n = (n + 1) % INT_MAX;
  }
}

/* Print the Fibonacci number sequence over and over again.

   This implementation is much faster than fibonacci_slow(). 
*/
void fibonacci_fast() {
  int a = 0;
  int b = 1;
  int n = 0;
  int next = a + b;

  while(true) {
    printf(" fib(%d) = %d\n", n, a);
    next = a + b;
    a = b;
    b = next;
    n++;
    if (next < 0) {
      a = 0;
      b = 1;
      n = 0;
    }
  }
}

int main () {
  /* Flush each printf() as it happens. */
  setvbuf(stdout, 0, _IOLBF, 0);
  setvbuf(stderr, 0, _IOLBF, 0);

  set_timer(TIMER_TYPE, timer_handler, TIMEOUT);

  // Call fibonacci_fast() or fibonacci_fast() 

  fibonacci_fast();
  // fibonacci_slow();

}

main() 我打电话给fibonacci_fast()fibonacci_slow()

正如预期的那样,当使用ITMER_REALmain() 调用fibonacci_fast()fibonacci_slow() 时,计时器滴答之间的挂钟时间没有差异。

当使用ITIMER_VIRTUALmain() 调用fibonacci_fast() 设置计时器时,每个计时器滴答之间的挂钟时间确实很长,但是如果main() 调用fibonacci_slow() 则每个计时器滴答之间的挂钟时间要长很多更小。

我想了解为什么fibonacci_fast() 使虚拟运行时比fibonacci_slow() 慢得多。与fibonacci_slow() 相比,使用fibonacci_fast() 时,CPU 调度程序是否给进程提供了更少的CPU 时间?如果是,为什么?如果不是,还有什么可以解释这种差异?

【问题讨论】:

    标签: c timer setitimer


    【解决方案1】:

    ITIMER_VIRTUAL 仅在进程以用户模式运行时运行。在您的两个斐波那契例程中,有一个 printf 调用涉及一个用于同步写入数据的系统调用,该调用不计入虚拟时间。 fibonacci_fast 实际上大部分时间都花在了printf 和这个系统调用上,所以计时器似乎运行得更慢了。

    【讨论】:

    • 谢谢!在 Mac OS(又名 OS X)上,setitimer() 的手册页仅说明“ITIMER_VIRTUAL 计时器在进程虚拟时间中递减。它仅在进程执行时运行。”没有明确提及用户模式。现在我看到man7.org/linux/man-pages/man2/setitimer.2.html 明确指出“此计时器对进程消耗的用户模式 ​​CPU 时间进行倒计时。”。现在看起来很明显,我应该已经意识到 I/O 系统调用不会添加到虚拟运行时,但我认为 Linux 手册页在明确这一点方面做得更好:-)
    猜你喜欢
    • 1970-01-01
    • 2015-02-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-08-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多