哈工大操作系统实验3-进程运行轨迹的追踪和统计
实验任务:
1.基于模板 process.c 编写多进程的样本程序,实现如下功能: + 所有子进程都并行运行,每个子进程的实际运行时间一般不超过 30 秒; + 父进程向标准输出打印所有子进程的 id,并在所有子进程都退出后才退出;
2.在 Linux0.11 上实现进程运行轨迹的跟踪。 + 基本任务是在内核中维护一个日志文件 /var/process.log,把从操作系统启动到系统关机过程中所有进程的运行轨迹都记录在这一 log 文件中。
3.在修改过的 0.11 上运行样本程序,通过分析 log 文件,统计该程序建立的所有进程的等待时间、完成时间(周转时间)和运行时间,然后计算平均等待时间,平均完成时间和吞吐量。可以自己编写统计程序,也可以使用 python 脚本程序—— stat_log.py(在 /home/teacher/ 目录下) ——进行统计。
4.修改 0.11 进程调度的时间片,然后再运行同样的样本程序,统计同样的时间数据,和原有的情况对比,体会不同时间片带来的差异。
即分为4个小任务,相关的阅读材料包括:
1.process.c 的编写涉及到 fork() 和 wait() 系统调用。
2.0.11 内核修改涉及到 init/main.c、kernel/fork.c 和 kernel/sched.c。
1.基于模板 process.c 编写多进程的样本程序.主要就是编写main程序。
#include <stdio.h>
#include <unistd.h>
#include <time.h>
#include <sys/times.h>
#include <sys/types.h>
#include <stdlib.h> //为了使用EXIT_SUCCESS
#define HZ 100
void cpuio_bound(int last, int cpu_time, int io_time);
int main(){
pid_t childPid;
int t=5;
int i = 0;
int numDead = 0;
for(i=0;i<t;i++){
switch(fork()){
case 0:
printf("child %d started with pid %ld\n",i,(long)getpid());
cpuio_bound(10,1,0);
_exit(EXIT_SUCCESS);
default:
break;
}
}
numDead = 0;
for(;;){
childPid = wait(NULL);
if(childPid==-1){
exit(EXIT_SUCCESS);
}
numDead++;
printf("child pid is %ld,numDead = %d\n",(long)childPid,numDead);
}
return 0;
}
void cpuio_bound(int last, int cpu_time, int io_time)
{
struct tms start_time, current_time;
clock_t utime, stime;
int sleep_time;
while (last > 0)
{
times(&start_time);
do
{
times(¤t_time);
utime = current_time.tms_utime - start_time.tms_utime;
stime = current_time.tms_stime - start_time.tms_stime;
} while ( ( (utime + stime) / HZ ) < cpu_time );
last -= cpu_time;
if (last <= 0 )
break;
sleep_time=0;
while (sleep_time < io_time)
{
sleep(1);
sleep_time++;
}
last -= sleep_time;
}
}
2.打开日志文件:/var/process.log
按照操作步骤操作即可:在Init/main.c中添加相关代码
有一个问题就是:需不需要在init()中删除相应的代码???–> init()函数就在main()函数正下方,注释掉对应相同的code。
//……
move_to_user_mode();
/***************添加开始***************/
setup((void *) &drive_info);
// 建立文件描述符0和/dev/tty0的关联
(void) open("/dev/tty0",O_RDWR,0);
//文件描述符1也和/dev/tty0关联
(void) dup(0);
// 文件描述符2也和/dev/tty0关联
(void) dup(0);
(void) open("/var/process.log",O_CREAT|O_TRUNC|O_WRONLY,0666);
/***************添加结束***************/
if (!fork()) { /* we count on this going ok */
init();
}
//……
3.在/kernel/printk.c中,加入实验指导的fprintk()函数。调用方法如下:
// 向stdout打印正在运行的进程的ID
fprintk(1, "The ID of running process is %ld", current->pid);
// 向log文件输出跟踪进程运行轨迹
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'R', jiffies);
如何找到进程切换点?
其隐藏在sched.c , fork.c , exit.c.
举例来说:1.在copy_process()开始和结束调用
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'N', jiffies);
fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);
2.在sys_pause() , sleep_on()等一切会调用schedule()的函数前加入:
printk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
3.在schedule()中switch_to(next)前加入:
printk(3, "%ld\t%c\t%ld\n", current->pid, 'R', jiffies);
运行示意图如下(有些地方\t敲成了%t):