我想计算上下文切换时间,我想使用互斥和条件变量在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添加到某个易失性浮点变量切换以查看它是否对切换时间有影响.