我试图“大致”计算Linux系统中线程上下文切换的时间。我编写了一个使用管道和多线程来实现此目的的程序。运行程序时,计算出的时间显然是错误的(请参见下面的输出)。我不确定这是由于我为此过程使用了错误的clock_id还是实现了
我已经实现了sched_setaffinity(),以便仅使程序在内核0上运行。我试图在代码中保留尽可能多的绒毛,以便仅测量上下文切换的时间,因此踩进程仅写入管道中有一个字符,父节点读取0字节。
我有一个父级踏步,它创建一个子线程,并在它们之间使用单向管道传递数据,该子线程运行一个简单的函数以写入管道。
void* thread_1_function()
{
write(fd2[1],"",sizeof("");
}
在父线程创建子线程时,启动时间计数器,然后在子线程写入的管道上调用read。
int main(int argc, char argv[])
{
//time struct declaration
struct timespec start,end;
//sets program to only use core 0
cpu_set_t cpu_set;
CPU_ZERO(&cpu_set);
CPU_SET(0,&cpu_set);
if((sched_setaffinity(0, sizeof(cpu_set_t), &cpu_set) < 1))
{
int nproc = sysconf(_SC_NPROCESSORS_ONLN);
int k;
printf("Processor used: ");
for(k = 0; k < nproc; ++k)
{
printf("%d ", CPU_ISSET(k, &cpu_set));
}
printf("\n");
if(pipe(fd1) == -1)
{
printf("fd1 pipe error");
return 1;
}
//fail on file descriptor 2 fail
if(pipe(fd2) == -1)
{
printf("fd2 pipe error");
return 1;
}
pthread_t thread_1;
pthread_create(&thread_1, NULL, &thread_1_function, NULL);
pthread_join(thread_1,NULL);
int i;
uint64_t sum = 0;
for(i = 0; i < iterations; ++i)
{
//initalize clock start
clock_gettime(CLOCK_MONOTONIC, &start);
//wait for child thread to write to pipe
read(fd2[0],input,0);
//record clock end
clock_gettime(CLOCK_MONOTONIC, &end);
write(fd1[1],"",sizeof(""));
uint64_t diff;
diff = billion * (end.tv_sec - start.tv_sec) + end.tv_nsec - start.tv_nsec;
diff = diff;
sum += diff;
}
我在运行此程序时得到的结果通常是这样的:
3000
3000
4000
2000
12000
3000
5000
依此类推,当我检查返回到起始和结束timespec结构的时间时,我看到tv_nsec似乎也是一个“四舍五入”的数字:
start.tv_nsec: 714885000, end.tv_nsec: 714888000
这是否是由于clock_monotonic不够精确而无法即时测量,还是我忽略了其他一些问题?
答案 0 :(得分:1)
我看到tv_nsec似乎也是一个“四舍五入”的数字:
2626, 714885000, 2626, 714888000
这是否是由于clock_monotonic不够精确导致 我正在尝试测量什么,或者我正在解决其他问题 俯瞰?
是的,这是有可能的。系统支持的每个时钟都有固定的分辨率。 struct timespec
能够支持具有纳秒分辨率的时钟,但这并不意味着您可以期望每个时钟实际上都具有这样的分辨率。看来您的CLOCK_MONOTONIC
的分辨率可能为1微秒(1000纳秒),但是您可以通过clock_getres()
函数进行检查。
如果您可以使用它,则可以尝试CLOCK_PROCESS_CPUTIME_ID
。对您来说,该分辨率可能比CLOCK_MONOTONIC
更高,但是请注意,单微秒的分辨率非常精确-在现代计算机上,每3000个CPU周期大约有一个滴答声。
即使如此,我仍然发现您的方法可能存在一些问题:
尽管将进程设置为对单个CPU具有亲和力,但这也不会阻止系统在该CPU上调度其他进程。因此,除非您采取了其他措施,否则您无法确定-甚至不可能-每个从程序线程之一移开的上下文切换都是到另一个线程。
您启动第二个线程,然后立即加入。此后,线程之间不再需要上下文切换,因为第二个线程在成功加入后不再存在。
read()
的计数为0可能会也可能不会检查错误,并且肯定不会传输任何数据。我完全不清楚为什么要用上下文切换时间来确定该呼叫的时间。
如果在您要计时的空间中确实发生了上下文切换,则至少需要在其中发生两次-远离程序并返回到程序。另外,您还需要测量在其他上下文中运行的所有其他设备所消耗的时间,而不仅仅是切换时间。因此,每1000纳秒的步长可能反映的是时间片,而不是切换时间。
您的主线程正在将空字符写入管道的写入端,但是似乎没有任何内容可以读取它们。如果确实没有,则最终将填满管道的缓冲区并阻塞。目的对我失去了。