HITOS_LAB5 进程运行轨迹的跟踪与统计

5. 进程运行轨迹的跟踪与统计

5.1. 实验目的

  • 掌握 Linux 下的多进程编程技术;
  • 通过对进程运行轨迹的跟踪来形象化进程的概念;
  • 在进程运行轨迹跟踪的基础上进行相应的数据统计,从而能对进程调度算法进行实际的量化评价, 更进一步加深对调度和调度算法的理解,获得能在实际操作系统上对调度算法进行实验数据对比的直接经验。

5.2. 实验内容

编写样本程序

process.c

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <time.h>
#include <sys/times.h>#define HZ	100void cpuio_bound(int last, int cpu_time, int io_time);int main(int argc, char * argv[])
{pid_t fd_1, fd_2;int fd;printf("The Parent Pid = [%d].\n", getpid());fd_1 = fork();if(fd_1 == 0){printf("[%d] Is Running Now.\n", getpid());cpuio_bound(10, 1, 0);exit(0);}fd_2 = fork();if(fd_2 == 0){printf("[%d] Is Running Now.\n", getpid());cpuio_bound(10, 1, 0);exit(0);}fd = wait(NULL);printf("[%d] Have Exited.\n",fd);fd = wait(NULL);printf("[%d] Have Exited.\n",fd);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(&current_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;}
}

跟踪进程运行轨迹

首先修改init文件夹下的main.c中的main()函数,应当在内核启动时就打开log文件。

在这里插入图片描述

打开log文件的参数指定为只写模式,如果文件已经存在,则清空其现有内容。文件权限设置为所有人可读可写。
kernel/printk.c中添加fprintk函数。

#include <stdarg.h>
#include <stddef.h>
#include <linux/kernel.h>
#include "linux/sched.h"
#include "sys/stat.h"static char logbuf[1024];
static char buf[1024];
extern int vsprintf(char * buf, const char * fmt, va_list args);int printk(const char *fmt, ...)
{va_list args;int i;va_start(args, fmt);i=vsprintf(buf,fmt,args);va_end(args);__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $buf\n\t""pushl $0\n\t""call tty_write\n\t""addl $8,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (i):"ax","cx","dx");return i;
}int fprintk(int fd, const char *fmt, ...)
{va_list args;int count;struct file * file;struct m_inode * inode;
va_start(args, fmt);count=vsprintf(logbuf, fmt, args);va_end(args);if (fd < 3){__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $logbuf\n\t""pushl %1\n\t""call sys_write\n\t""addl $8,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (count),"r" (fd):"ax","cx","dx");}else{if (!(file=task[0]->filp[fd]))return 0;inode=file->f_inode;
__asm__("push %%fs\n\t""push %%ds\n\t""pop %%fs\n\t""pushl %0\n\t""pushl $logbuf\n\t""pushl %1\n\t""pushl %2\n\t""call file_write\n\t""addl $12,%%esp\n\t""popl %0\n\t""pop %%fs"::"r" (count),"r" (file),"r" (inode):"ax","cx","dx");}return count;
}

jiffies

jiffieskernel/sched.c文件中定义为一个全局变量:

long volatile jiffies=0;

其记录了从系统开机到当前时间的时钟中断发生次数,也被称为“滴答数”。

kernel/sched.c文件中的sched_init()函数中,时钟中断处理函数被设置为:

set_intr_gate(0x20,&timer_interrupt);

这表明jiffies表示了从系统开机时到目前为止的时钟中断次数,即“滴答数”。

此外,在sched_init()函数中,以下代码用于设置每次时钟中断的间隔,即LATCH

outb_p(0x36, 0x43);
outb_p(LATCH&0xff, 0x40);
outb_p(LATCH>>8, 0x40);

三条语句的目的是配置8253定时芯片的工作模式,并设置时钟中断的触发频率。其中,LATCH是在kernel/sched.c文件中定义的一个宏:

kernel/sched.c

#define LATCH  (1193180/HZ)

include/linux/sched.h

#define HZ 100

寻找状态切换点

需要在所有发生进程状态切换的代码点添加适当的代码,以记录进程状态变化的情况并输出到log文件中。

总体而言,Linux 0.11支持四种主要的进程状态转移:从就绪到运行、从运行到就绪、从运行到睡眠以及从睡眠到就绪。此外,还存在新建和退出两种情况。其中,就绪到运行的状态转移通过schedule()函数实现(该函数同时涵盖调度算法);运行到睡眠的转移则依赖于sleep_on()interruptible_sleep_on(),以及进程主动休眠的系统调用如sys_pause()sys_waitpid();而从睡眠到就绪的转移则依赖于wake_up()。通过在这些函数的适当位置插入处理语句,可以实现对进程运行轨迹的全面跟踪。

kernel/fork.c文件中的copy_process()函数中,修改如下,以在新建态N时输出新建进程信息到文件:

	p->start_time = jiffies;fprintk(3, "%ld\t%c\t%ld\n", p->pid, 'N', jiffies);

kernel/sched.c

schedule()函数:

if (((*p)->signal & ~(_BLOCKABLE & (*p)->blocked)) &&(*p)->state==TASK_INTERRUPTIBLE){(*p)->state=TASK_RUNNING;fprintk(3, "%ld\t%c\t%ld\n", (*p)->pid, 'J', jiffies);	}

由于中断信号影响,由可中断的阻塞态W变为就绪态J

	if(task[next]->pid != current->pid){if(current->state==TASK_RUNNING)fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'J', jiffies);fprintk(3, "%ld\t%c\t%ld\n", task[next]->pid, 'R', jiffies);}switch_to(next);

sys_pause()函数:

int sys_pause(void)
{if(current->state!=TASK_INTERRUPTIBLE )fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);current->state = TASK_INTERRUPTIBLE;schedule();return 0;
}

sleep_on()函数:

void sleep_on(struct task_struct **p)
{struct task_struct *tmp;if (!p)return;if (current == &(init_task.task))panic("task[0] trying to sleep");tmp = *p;*p = current;current->state = TASK_UNINTERRUPTIBLE;fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);		schedule();if (tmp)tmp->state=0;fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);		
}

interruptible_sleep_on()函数:

void interruptible_sleep_on(struct task_struct **p)
{struct task_struct *tmp;if (!p)return;if (current == &(init_task.task))panic("task[0] trying to sleep");tmp=*p;*p=current;
repeat:	current->state = TASK_INTERRUPTIBLE;fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);schedule();if (*p && *p != current) {(**p).state=0;fprintk(3, "%ld\t%c\t%ld\n", (**p).pid, 'J', jiffies);goto repeat;}*p=NULL;if (tmp)tmp->state=0;fprintk(3, "%ld\t%c\t%ld\n", tmp->pid, 'J', jiffies);
}

wake_up()函数:

void wake_up(struct task_struct **p)
{if (p && *p) {(**p).state=0;fprintk(3, "%ld\t%c\t%ld\n", (**p).pid, 'J', jiffies);	*p=NULL;}
}

修改kernel/exit.c

do_exit()函数:

fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'E', jiffies);

sys_waitpid()函数:

fprintk(3, "%ld\t%c\t%ld\n", current->pid, 'W', jiffies);
schedule();

Linux-0.11

make all
sudo ./mount-hdc
sudo umount hdc
./run

在这里插入图片描述
日志文件process.log

在这里插入图片描述

统计进程时间

chmod +x stat_log.py
./stat_log.py process.log 12 13 14 15 -g | more

在这里插入图片描述

修改linux-0.11进程调度的时间片

Linux 0.11所采用的调度算法是一种综合考虑进程优先级并具有动态反馈机制,能够调整时间片的轮转调度算法。该算法为每个进程分配一个称为时间片的时间段,即该进程被允许运行的时间。如果在时间片结束时进程仍在运行,CPU将会被剥夺,并分配给另一个进程;而如果进程在时间片结束前阻塞或结束,则CPU会立即进行切换。调度程序的主要任务是维护一个就绪进程列表,当进程用完它的时间片后,它将被移到队列的末尾。那么综合考虑进程优先级又是什么呢?这意味着一个进程在阻塞队列中停留的时间越长,其优先级就越高,因此下次将被分配更大的时间片。

进程之间的切换是需要时间的。如果时间片设定得太小,将导致频繁的进程切换,从而浪费大量时间在进程切换上,影响系统效率;相反,如果时间片设定得足够大,虽然不会浪费时间在进程切换上,但会降低系统的利用率,且可能对用户交互性产生不良影响。因此,时间片的大小需要在保持CPU利用率和用户交互性之间取得平衡。

为了调整每个进程的时间片,可以通过修改INIT_TASK宏中的counter来实现。在这里,counter代表进程的时间片。通过增加它,可以延长进程被分配CPU的时间。下图中,平均等待时间以及平均完成时间随着时间片的切片数增多而减少 。

在这里插入图片描述

5.3. 实验报告

  1. 结合自己的体会,谈谈从程序设计者的角度看,单进程编程和多进程编程最大的区别是什么?

在单进程编程中,程序是按照顺序执行的,一个任务完成后才会执行下一个任务。这种方式不涉及到多个任务之间的切换和数据保存,但是在等待I/O时,CPU可能处于空闲状态,导致CPU利用率相对较低。

相比之下,多进程编程允许多个进程交替执行。当一个进程等待I/O时,系统可以切换到另一个就绪的进程执行,从而提高了CPU的利用率。然而,多进程编程涉及到进程切换时的数据保存和复杂的调度机制,这可能导致一些额外的开销和复杂性。

执行方式

  • 单进程编程: 顺序执行,程序从上到下逐行执行。一个任务的执行完成后,才会执行下一个任务。
  • 多进程编程: 并发执行,多个进程可以同时运行。进程之间可以交替执行,提高系统的响应速度和资源利用率。

数据是否同步

  • 单进程编程: 数据是同步的,因为在单进程中修改数据会直接影响整个进程的状态。
  • 多进程编程: 数据是异步的,因为每个进程有自己的内存空间,进程之间的数据修改不会直接影响其他进程的数据。

CPU利用率

  • 单进程编程: CPU利用率相对较低。当进程在等待I/O操作时,CPU处于空闲状态。
  • 多进程编程: CPU利用率相对较高。当一个进程在等待I/O时,其他进程可以继续执行,充分利用了CPU资源。

适用场景

  • 单进程编程: 适用于简单的、线性的任务,不涉及多任务协同工作的场景。
  • 多进程编程: 适用于需要同时处理多个任务、有并发需求的场景,例如服务器程序、并行计算等。

2.你是如何修改时间片的?仅针对样本程序建立的进程,在修改时间片前后, log 文件的统计结果(不包括Graphic)都是什么样?结合你的修改分析一下为什么会这样变化,或者为什么没变化?

通过在sched.h文件中的INIT_TASK宏进行时间片的修改。观察到在样本程序建立的进程中,随着时间片的较大幅度修改,并没有引起log文件统计结果的显著变化。

  • 系统处理能力不变: 关键在于系统处理的进程数量并没有发生改变。即使时间片较大,系统在单位时间内仍能处理相同数量的进程。这导致了吞吐量在一定范围内没有明显的变化。

  • 平均等待时间和平均完成时间的变化: 在一定范围内,随着时间片的增大,平均等待时间和平均完成时间呈下降趋势。这是因为在较小的时间片情况下,CPU花费更多时间在调度切换上,导致平均等待时间增加。随着时间片的增大,这种等待时间减小。然而,当时间片足够大时,进程调度可能变得类似于先来先服务(FCFS),平均等待时间和平均完成时间趋于稳定。

  • 调度策略影响: 随着时间片的修改,RR轮转调度逐渐转变为FCFS先来先服务。这导致了吞吐量的相对稳定性,因为在单位时间内完成的进程数量受到系统处理能力的限制。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/210874.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

高德地图加载三维模型vue(.obj转.gltf)

官方glTF模型案例 obj2gltf 的开发文档 第一步&#xff1a;这里首先要将我们的.obj文件转换为.gltf文件 全局安装 npm install -g obj2gltf终端打开.obj文件所在的文件夹执行 obj2gltf -i model.obj -o model.gltf -t &#xff08;-i model.obj对应你的obj文件的名字&#x…

Node包管理工具 - nvm、npm、yarn、cnpm、pnpm

转载说明 原文地址 简介 nvm : 可以实现一台电脑&#xff0c;拥有多个版本的Node npm : node package manager 下载Node后自带的一个包管理工具 yarn : npm 的升级版&#xff0c;更优秀 cnpm : 配置下载非官方地址的依赖&#xff08;淘宝、华为、腾讯镜像&#xff09; pnpm :…

前端时间的失败总结复盘

分享失败经验&#xff0c;前段时间的总结复盘&#xff1a; 与伙伴合作面对异常决策要及时提出质疑&#xff0c;怼&#xff0c;别太客气&#xff0c;客气起来&#xff0c;小心翼翼在意他人情绪那么这个项目就会让人难受&#xff0c;不要因为因为伙伴身上有标签/光环/权威就觉得…

java后端自学错误总结

java后端自学错误总结 MessageSource国际化接口总结 MessageSource国际化接口 今天第一次使用MessageSource接口,比较意外遇到了一些坑 messageSource是spring中的转换消息接口&#xff0c;提供了国际化信息的能力。MessageSource用于解析 消息&#xff0c;并支持消息的参数化…

题目:区间更新(蓝桥OJ 3291)

题目描述&#xff1a; 解题思路&#xff1a; 差分模板题。 题解&#xff1a; #include<bits/stdc.h> using namespace std;const int N 1e5 10; int a[N], diff[N] ;//数组的大小不可能开到大于1e9int res(int n, int m) {for(int i 1; i < n; i)cin >&g…

抖音视频如何无水印保存?抖音视频无水印保存教程

抖音视频如何无水印保存&#xff1f;当下短视频盛行时代&#xff0c;抖音作为当下主流短视频平台之一&#xff0c;每天都有数以亿计的用户在抖音上分享自己的创作&#xff0c;然后当我们遇到感兴趣的视频&#xff0c;下载保存后会发现带有水印&#xff0c;那么抖音视频如何无水…

人、机不同在于变与多

人擅长变&#xff0c;如变模态、变尺度&#xff0c;而机器侧重多&#xff0c;如多模态、多尺度。 人类擅长变化的能力是由于我们的大脑和思维能力的灵活性所决定的。我们可以通过学习和适应&#xff0c;改变我们的态度、行为方式和观点&#xff0c;以适应不同的情境和环境。例如…

51 代码审计-PHP框架MVC类上传断点调试挖掘

目录 知识点1:知识点2:知识点3:演示案例:PHPStormxdebu断点调试演示Beescms无框架后台任意文件上传Finecms基于前台MVC任意文件上传CItphp基于前台TP5框架任意文件上传 涉及资源: 知识点1: #关键字搜索: (函数&#xff0c;关键字&#xff0c;全局变量等) 文件上传&#xff0c;…

国标GB28181协议/RTSP视频监控汇聚平台EasyCVR(V.3.4)页面UI大更新

为提高用户体验&#xff0c;增强平台功能&#xff0c;旭帆科技的Easy系列平台也在不断优化更新中。在最新的EasyCVR&#xff08;V.3.4&#xff09;中&#xff0c;其最显著的区别即为首页UI的调整。 其亮点是在【配置中心】-【基础配置】-【展示信息】中&#xff0c;首页UI可分…

短视频账号矩阵系统源码/saas独立源头技术开发

一、批量剪辑&#xff08;采用php语言&#xff0c;数学建模&#xff09; 短视频合成批量剪辑的算法主要有以下几种&#xff1a; 1. 帧间插值算法&#xff1a;通过对多个视频的帧进行插帧处理&#xff0c;从而合成一段平滑的短视频。 2. 特征提取算法&#xff1a;提取多个视频中…

Spring容器启动过程中的自定义操作插口汇总

目录标题 PostConstruct注解EventListener方式InitializingBean的afterPropertiesSet方法实现ApplicationRunner接口重写run方法实现AplicationContextAware接口重写setApplicationContext实现ServletContextListener接口contextInitialized方法实现ServletContextAware接口set…

MacDroid Pro for Mac – 安卓设备文件传输助手,实现无缝连接与传输!

想要在Mac电脑上轻松管理和传输您的安卓设备文件吗&#xff1f;MacDroid Pro for Mac 是您的最佳选择&#xff01;这款强大的文件传输助手可以让您在Mac上与安卓设备之间实现快速、方便的文件传输。 MacDroid Pro for Mac 提供了简单易用的界面&#xff0c;让您能够直接在Mac上…

WordPress插件大全-免费的WordPress插件汇总

随着互联网的不断发展&#xff0c;网站建设变得日益普及。对于大多数人而言&#xff0c;WordPress是一个熟悉且易于使用的网站建设平台。然而&#xff0c;有时候我们可能会觉得WordPress的功能还不够满足我们的需求&#xff0c;这时候&#xff0c;插件就成了解决问题的得力工具…

数据库管理-第122期 配置Halo数据库(202301204)

数据库管理-第122期 配置Halo数据库&#xff08;202301204&#xff09; 在120期完成了HaloDB的安装&#xff0c;那么紧接着就需要对数据库进行具体配置。 1 数据库配置 这里首先说一下我这里数据库的给的硬件配置&#xff1a;2个CPU&#xff0c;16GB内存 1 配置数据库访问控…

记录一下Mac配置SpringBoot开发环境

由于很多项目喜欢使用传统的 Java 8 进行开发&#xff0c;而且 Java 8 的稳定性也是经过长久考验的&#xff0c;我们接下来就尝试一下&#xff0c;在一台新的 Mac 中配置 Java 环境&#xff0c;并且开始创建 SpringBoot 项目。 首先&#xff0c;去 Oracle 官网下载 java8 JDK …

通过时间交织技术扩展ADC采样速率的简要原理

前言 数据采集是将自然界中存在的模拟信号通过模数转换器&#xff08;ADC&#xff09;转换成数字信号&#xff0c;再对该数字信号进行相应的接收和处理。数据采集系统作为数据采集的手段&#xff0c;在移动通信、图向采集、无线电等领域有重要作用。随着电子信息技术的飞速发展…

感冒 发烧 咳嗽记录

感冒 风寒: 清鼻涕 热感冒: 细菌记录, 脓鼻涕. 咳嗽 先是清痰咳嗽, 后是浓痰,细菌感染, 白细胞噬菌体, 所以要补充蛋白质,维生素. 胸骨上窝 , 天突穴 ,后面上支气管的位置, 往下会变成左右两支,连接到肺部 普通咳嗽: 用哈气拍打背部的方式. 把痰去除. 吃点 盐酸氨溴索片 增加支…

怎么让百度快速收录,百度SEO收录工具

百度收录对于一个网站的重要性不言而喻。拥有良好的百度收录意味着网站能够更好地被搜索引擎收录&#xff0c;为用户提供更精准的搜索结果。而怎样实现百度快速收录成为了许多网站管理员关注的焦点。 百度收录的重要性 百度是国内最大的搜索引擎之一&#xff0c;拥有数以亿计的…

蓝桥杯真题:四平方和-Java版

import java.io.*;/*先找后两个数for(int i 0; 2 * i * i < n;i)for(int j i; i * i j * j < n;j ) 再找前两个数 for(int i 0;4 * i * i < n; i )for(int j i;2 * (j * j i * i) < n;j )//这样就可以让后两个数尽量大,前两个数尽量小 这样就可以确定后…

题目:小明的彩灯(蓝桥OJ 1276)

题目描述&#xff1a; 解题思路&#xff1a; 一段连续区间加减&#xff0c;采用差分。最终每个元素结果与0比较大小&#xff0c;比0小即负数输出0。 题解&#xff1a; #include<bits/stdc.h> using namespace std;using ll long long; const int N 1e5 10; ll a[N],…