测量线程的上下文切换时间

我想计算上下文切换时间,我想使用互斥和条件变量在2个线程之间发出信号,这样一次只能运行一个线程.我可以使用CLOCK_MONOTONIC来测量整个执行时间,使用CLOCK_THREAD_CPUTIME_ID来测量每个线程运行的时间.

然后上下文切换时间是(total_time – thread_1_time – thread_2_time).

为了获得更准确的结果,我可以循环并取平均值.

这是接近上下文切换时间的正确方法吗?我想不出任何可能出错的事情,但我得到的答案不到1纳秒.

我忘了提到我循环它的时间越多,取平均值,我得到的结果就越小.

编辑

这是我的代码片段

    typedef struct
    {
      struct timespec start;
      struct timespec end;
    }thread_time;

    ...


    // each thread function looks similar like this
    void* thread_1_func(void* time)
    {
       thread_time* thread_time = (thread_time*) time;

       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &(thread_time->start)); 
       for(x = 0; x < loop; ++x)
       {
         //where it switches to another thread
       }
       clock_gettime(CLOCK_THREAD_CPUTIME_ID, &(thread_time->end));

       return NULL;
   };

   void* thread_2_func(void* time)
   {
      //similar as above
   }

   int main()
   {
      ...
      pthread_t thread_1;
      pthread_t thread_2;

      thread_time thread_1_time;
      thread_time thread_2_time;

      struct timespec start, end;

      // stamps the start time 
      clock_gettime(CLOCK_MONOTONIC, &start);

      // create two threads with the time structs as the arguments 
      pthread_create(&thread_1, NULL, &thread_1_func, (void*) &thread_1_time);
      pthread_create(&thread_2, NULL, &thread_2_func, (void*) &thread_2_time); 
      // waits for the two threads to terminate 
      pthread_join(thread_1, NULL);
      pthread_join(thread_2, NULL);

      // stamps the end time 
      clock_gettime(CLOCK_MONOTONIC, &end);

      // then I calculate the difference between between total execution time and the total execution time of two different threads..
   }

最佳答案 首先,使用CLOCK_THREAD_CPUTIME_ID可能非常错误;这个时钟将在用户模式下给出在该线程中花费的时间.但是在用户模式下不会发生上下文切换,您需要使用另一个时钟.此外,在多处理系统上,时钟可以为处理器提供不同的值!因此,我建议您使用CLOCK_REALTIME或CLOCK_MONOTONIC.但是请注意,即使您快速连续两次读取其中任何一个,时间戳通常也会相隔数十纳秒.

至于上下文切换 – 有很多种上下文切换.最快的方法是完全用软件从一个线程切换到另一个线程.这只是意味着您将旧寄存器压入堆栈,设置任务切换标志以便SSE / FP寄存器将被延迟保存,保存堆栈指针,加载新堆栈指针并从该函数返回 – 因为另一个线程已经完成相同的操作,该函数的返回发生在另一个线程中.

这个线程到线程切换非常快,其开销与任何系统调用大致相同.从一个进程切换到另一个进程要慢得多:这是因为必须通过设置CR0寄存器来刷新和切换用户空间页表.这导致TLB中的未命中,其将虚拟地址映射到物理地址.

然而,< 1 ns上下文切换/系统调用开销似乎并不合理 – 这里很可能存在超线程或2个CPU内核,所以我建议你在该进程上设置CPU亲和力,以便Linux只有在第一个CPU核心上运行它:

#include <sched.h>

cpu_set_t  mask;
CPU_ZERO(&mask);
CPU_SET(0, &mask);
result = sched_setaffinity(0, sizeof(mask), &mask);

那么你应该非常确定你测量的时间来自真正的上下文切换.另外,要测量切换浮点/ SSE堆栈的时间(这种情况很懒散),您应该有一些浮点变量并在上下文切换之前对它们进行计算,然后在上下文之后将.1添加到某个易失性浮点变量切换以查看它是否对切换时间有影响.

点赞