代码如下:
#include
#include
#include
//return us
int time_diff(struct timeval* t1, struct timeval* t2) {
return (t2->tv_sec - t1->tv_sec) * 1000000 + (t2->tv_usec - t1->tv_usec);
}
int main() {
int i;
struct timeval curr, now;
if (gettimeofday(&curr, NULL) == -1) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
for (i = 0; i < 10; ++i) {
if (gettimeofday(&now, NULL) != 0) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
printf("time elaps %d us\n", time_diff(&curr, &now));
}
return 0;
}
执行结果如下:
最多精确到us,并且大致精确(并不完全精确),需要多迭代几次减少误差。
本处以执行0字节的读取为例来测试此系统调用的时间:
#include
#include
#include
#include
#include
#include
#include
int time_diff(struct timeval* t1, struct timeval* t2) {
return (t2->tv_sec - t1->tv_sec) * 1000000 + (t2->tv_usec - t1->tv_usec);
}
int main() {
int i;
char buf[2];
int fd = open("./tmp.txt", O_CREAT | O_APPEND | O_RDWR, S_IRWXU);
struct timeval curr, now;
if (gettimeofday(&curr, NULL) == -1) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
for (i = 0; i < 100; ++i) {
if (read(fd, buf, 0) != 0) {
fprintf(stderr, "read error\n");
exit(1);
}
}
if (gettimeofday(&now, NULL) != 0) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
printf("time elaps %d us\n", time_diff(&curr, &now));
return 0;
}
执行结果如下:
执行了100次后的结果为19us,也就是每次执行调用耗时约0.2us。
此处测试write和read管道的总时间,代码更改如下(这里是为实验三做准备):
#include
#include
#include
#include
#include
#include
#include
int time_diff(struct timeval* t1, struct timeval* t2) {
return (t2->tv_sec - t1->tv_sec) * 1000000 + (t2->tv_usec - t1->tv_usec);
}
int main() {
int i;
char buf[] = "a";
int fds[2];
struct timeval curr, now;
if (gettimeofday(&curr, NULL) == -1) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
pipe(fds);
for (i = 0; i < 20000; ++i) {
if (write(fds[1], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
if (read(fds[0], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
}
if (gettimeofday(&now, NULL) != 0) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
printf("time elaps %d us\n", time_diff(&curr, &now));
return 0;
}
测试结果如下:
可见在没有上下文切换的情况下,20000次的读取和写入需要11326 us。
其原理是通过设置两个管道,第一个进程写入数据后读取数据,此时陷入阻塞,进程被挂起,切换到第二个进程,而第二个进程读取数据后,再次写入管道后自身进行读取操作进而陷入阻塞状态,系统再度切换到第一个进程执行,如此往复循环可以测试得到具体的切换成本。(多核系统注意调用sched_setaffinity函数)
#include
#include
#include
#include
#include
#include
#include
#include
int main() {
int i;
char buf[] = "a";
int fds1[2], fds2[2];
struct timeval begin, end;
pipe(fds1);
pipe(fds2);
int rc = fork();
if (rc == -1){
fprintf(stderr, "fork error\n");
exit(1);
} else if (rc == 0) {
close(fds1[0]);
close(fds2[1]);
if (gettimeofday(&begin, NULL) == -1) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
printf("test begin at %lu s and %lu us\n", begin.tv_sec, begin.tv_usec);
for (i = 0; i < 10000; ++i) {
if (write(fds1[1], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
if (read(fds2[0], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
}
close(fds1[1]);
close(fds2[0]);
exit(0);
}
close(fds1[1]);
close(fds2[0]);
for (i = 0; i < 10000; ++i) {
if (read(fds1[0], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
if (write(fds2[1], buf, 1) != 1) {
fprintf(stderr, "read error\n");
exit(1);
}
}
if (gettimeofday(&end, NULL) != 0) {
fprintf(stderr, "gettimeofday error\n");
exit(1);
}
printf("test end at %lu s and %lu us\n", end.tv_sec, end.tv_usec);
close(fds1[1]);
close(fds2[0]);
wait(NULL);
return 0;
}
系统总用时的计算公式如下:
t a l l = t s w i t c h _ a l l + t r e a d _ a n d _ w r i t e _ a l l t_{all} = t_{switch\_all}+t_{read\_and\_write\_all} tall=tswitch_all+tread_and_write_all
这其中包含20000次对管道的读取和写入以及20000次的进程切换,通过计算可得
t s w i t c h = t s w i t c h _ a l l c o u n t = t a l l − t r e a d _ a n d _ w r i t e _ a l l c o u n t t_{switch} = \frac{ t_{switch\_all}}{count} = \frac{ t_{all} - t_{read\_and\_write\_all}}{count} tswitch=counttswitch_all=counttall−tread_and_write_all
最终得到切换所需要的总切换开销为26114us而单次切换的开销大约为1.3us。