利用管道通信(pipe)测量进程间的上下文切换(context switch)开销
《https://pages.cs.wisc.edu/~remzi/OSTEP/cpu-mechanisms.pdf》
Measuring the cost of a context switch is a little trickier. The lmbench benchmark does so by running two processes on a single CPU, and setting up two UNIX pipes between them; a pipe is just one of many ways processes in a UNIX system can communicate with one another. The first process then issues a write to the first pipe, and waits for a read on the second; upon seeing the first process waiting for something to read from the second pipe, the OS puts the first process in the blocked state, and switches to the other process, which reads from the first pipe and then writes to the second. When the second process tries to read from the first pipe again, it blocks, and thus the back-and-forth cycle of communication continues. By measuring the cost of communicating like this repeatedly, lmbench can make a good estimate of the cost of a context switch. You can try to re-create something similar here, using pipes, or perhaps some other communication mechanism such as UNIX sockets.
然后,第一个进程(子进程)向第一个管道发出写操作,并等待第二个管道的读操作;在看到第一个进程等待从第二个管道读取内容时,操作系统会将第一个进程置于阻塞状态,并切换到另一个进程(父进程),后者从第一个管道读取内容,然后向第二个管道写操作。当第二个进程再次尝试从第一个管道中读取数据时,它就会阻塞,这样来回循环的通信就继续进行。
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/time.h>
#include <assert.h>const int N = 1e2 + 10; // Number of iterations for context switchesint main(int argc, char *argv[]) {int pipefd[2][2]; // Array to hold two pipes: one for each direction of communicationchar buf; // Buffer to hold the character read from the pipe// Check if the correct number of arguments are providedif (argc != 3) {fprintf(stderr, "Usage: %s <string> <string>\n", argv[0]);exit(EXIT_FAILURE);}// Create the two pipesif (pipe(pipefd[0]) == -1 || pipe(pipefd[1]) == -1) {perror("pipe");exit(EXIT_FAILURE);}// Fork the process to create a child processint rc1 = fork();if (rc1 < 0) {// Fork failedfprintf(stderr, "fork failed\n");exit(EXIT_FAILURE);} else if (rc1 == 0) { // Child processclose(pipefd[0][0]); // Close unused read end of the first pipeclose(pipefd[1][1]); // Close unused write end of the second pipefor (int i = 0; i < N; ++i) {// Write to the first pipewrite(pipefd[0][1], argv[1], strlen(argv[1]) + 1);// Read from the second pipewhile (read(pipefd[1][0], &buf, 1) > 0) {// ************//write(STDOUT_FILENO, &buf, 1);if (buf == '\0') {//write(STDOUT_FILENO, "\n", 1);break;}}}// Close the used pipe ends before exitingclose(pipefd[0][1]);close(pipefd[1][0]);exit(EXIT_SUCCESS);} else {// Parent processclose(pipefd[0][1]); // Close unused write end of the first pipeclose(pipefd[1][0]); // Close unused read end of the second pipestruct timeval start, end;// Get the start timeint rc1 = gettimeofday(&start, NULL);for (int i = 0; i < N; ++i) {// Read from the first pipewhile (read(pipefd[0][0], &buf, 1) > 0) {// ************//write(STDOUT_FILENO, &buf, 1);if (buf == '\0') {//write(STDOUT_FILENO, "\n", 1);break;}}// Write to the second pipewrite(pipefd[1][1], argv[2], strlen(argv[2]) + 1);}// Get the end timeint rc2 = gettimeofday(&end, NULL);assert(rc1 == 0 && rc2 == 0);// Calculate elapsed timedouble elapsed = (double) end.tv_sec + (double) end.tv_usec / 1e6 - ((double) start.tv_sec + (double) start.tv_usec / 1e6);// Calculate average context switch timedouble context_switch = elapsed / (2 * N);printf("Total time: %f seconds\n", elapsed);// Print the average context switch timeprintf("Average context switch time: %lf seconds\n", context_switch);// Close the used pipe endsclose(pipefd[1][1]);close(pipefd[0][0]);}return 0;
}
运行结果:[chap6] :) cc -o contextSwitch contextSwitch.c
[chap6] :) ./contextSwitch 1111 222222
Total time: 0.010745 seconds
Average context switch time: 0.000049 seconds
[chap6] :) ./contextSwitch 1111 222222
Total time: 0.014709 seconds
Average context switch time: 0.000067 seconds
[chap6] :) ./contextSwitch 1111 222222
Total time: 0.011982 seconds
Average context switch time: 0.000054 seconds
[chap6] :)