操作系统导论-课后作业-ch6

补充:测量作业

1. 测试函数gettimeofday

代码如下:

#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;
}

执行结果如下:
操作系统导论-课后作业-ch6_第1张图片
最多精确到us,并且大致精确(并不完全精确),需要多迭代几次减少误差。

2. 测试系统调用时间

2.1 测试读取0字节耗时

本处以执行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。

2.2 测试write和read总时间

此处测试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。

3. 测量上下文切换成本

其原理是通过设置两个管道,第一个进程写入数据后读取数据,此时陷入阻塞,进程被挂起,切换到第二个进程,而第二个进程读取数据后,再次写入管道后自身进行读取操作进而陷入阻塞状态,系统再度切换到第一个进程执行,如此往复循环可以测试得到具体的切换成本。(多核系统注意调用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=counttalltread_and_write_all
最终得到切换所需要的总切换开销为26114us而单次切换的开销大约为1.3us。

你可能感兴趣的:(#,操作系统导论,算法,linux,运维)