【操作系统】实验六 分析源代码

简介: 【操作系统】实验六 分析源代码

😘欢迎关注:👍点赞🙌收藏✍️留言

🏇码字不易,你的👍点赞🙌收藏❤️关注对我真的很重要,有问题可在评论区提出,感谢支持!!!

前言

本实验结论没有标准答案,请自行判断。

实验六

实验内容:

  1. 实验名称:分析源代码
  2. 实验任务:

通过阅读源代码,分析研究linux的进程调度策略和算法。要求以源码为依据,回答下面的问题:

  • 进程调度队列是如何组织的
  • 三种调度类型(SCHED_FIFO, SCHED_RR, SCHED_OHTER)的实现过程
  • 优先级是如何定义和动态变化的
  • 时间片的赋值?它与优先级的关系?
  • 对实时进程和多CPU的支持
  • 评价linux的调度策略,提出改进意见。
  1. 源码版本
    Linux 5.15.1

实验过程:

1. 下载内核源码

使用这个网站下载:https://mirrors.edge.kernel.org/pub/linux/kernel

2. 进程调度队列是如何组织的?

在新版本的Linux内核中,比如说我的版本5.15.1,进程调度队列是由红黑树(rbtree)实现的。每个CPU都有一个运行队列(runqueue),其中包含了所有处于可运行状态的进程。每个进程都通过一个task_struct结构来表示,其中的调度信息存储在sched_entity和sched_rt_entity结构中。

在Linux内核的源码中,调度队列的结构定义在include/linux/sched.h文件中。这个文件包含了与进程调度相关的各种数据结构和函数声明。如图1 源码中task_struct的结构。

图1 源码中task_struct结构

以下是一个简化的sched.h文件片段,展示了与调度队列相关的数据结构:

struct task_struct {    /* ... */
    struct sched_entity se;
    struct sched_rt_entity rt;
    /* ... */
};
struct sched_entity {
    /* ... */
    struct rb_node run_node;
    /* ... */
};
struct rb_root runqueues[NR_CPUS];

在这个片段中,task_struct结构表示一个进程,其中包含了两个与调度相关的结构:se和rt。se表示一个普通的调度实体,用于实现基于优先级的调度,而rt表示一个实时调度实体,用于实现基于时间的调度。

每个CPU都有一个runqueues数组,这是一个红黑树(rbtree),用于存储所有处于可运行状态的进程。每个进程通过其se或rt结构中的run_node域链接到红黑树中。

下面是源码中rb_node的实现:

图2 源码中rb_node的结构

在运行队列中,进程按照优先级(对于se)或时间(对于rt)进行排序。调度器在调度时,会遍历红黑树,选择最高优先级(或最早到期时间)的进程进行执行。

3. 三种调度类型(SCHED_FIFO, SCHED_RR, SCHED_OTHER)的实现过程?

SCHED_FIFO和SCHED_RR是实时调度策略,它们都基于优先级调度,只是SCHED_FIFO是无时间片的,而SCHED_RR是有时间片的。SCHED_OTHER是普通的分时调度策略。调度类型在源码中的表示和优先级在源码中的表示如图3、4所示。

图3 调度类型在源码中的表示

图4 优先级在源码中的表示

SCHED_FIFO的实现过程:当一个进程被设置为SCHED_FIFO时,它的sched_priority字段会被设置为一个正值,表示其优先级。当调度器选择进程时,它会从最高优先级的进程开始,直到找到一个可运行的进程。如果最高优先级的进程不可运行,那么它会继续查找次高优先级的进程,以此类推。

SCHED_RR的实现过程:当一个进程被设置为SCHED_RR时,它的sched_priority字段也会被设置为一个正值,表示其优先级。此外,它还有一个时间片(time slice),用于限制它运行的时间。当调度器选择进程时,它会从最高优先级的进程开始,直到找到一个可运行的进程。如果最高优先级的进程不可运行,那么它会继续查找次高优先级的进程,以此类推。当一个进程用完了它的时间片后,它会被放入队列的尾部,等待下一次调度。

SCHED_OTHER的实现过程:当一个进程被设置为SCHED_OTHER时,它的sched_priority字段会被设置为一个负值,表示其优先级。当调度器选择进程时,它会从最低优先级的进程开始,直到找到一个可运行的进程。如果最低优先级的进程不可运行,那么它会继续查找次低优先级的进程,以此类推。

调度器从最低优先级的进程开始选择,主要是为了实现公平调度。这种做法可以确保每个进程都有机会得到执行,避免高优先级的进程长时间独占CPU资源,导致低优先级的进程饥饿。

在许多操作系统中,调度策略都会考虑到进程的优先级,以确保系统资源的合理分配。通过设置进程的优先级,可以控制进程的执行顺序,从而使得系统资源得到更加有效的利用。

操作系统通过判断在不同的策略下进行不同的行为,如图5所示:

图 5 某个函数根据调度策略不同进行选择

4. 优先级是如何定义和动态变化的?

我们可以在sched.c文件中搜索nice,可以看到如图6的描述:

图 6 源码中对nice值的描述

在Linux内核中,进程优先级是通过sched_priority字段定义的,该字段是一个32位的整数,范围从-20(最高优先级)到+19(最低优先级)。

进程的优先级可以通过系统调用nice()和setpriority()来动态调整。nice()系统调用可以调整进程的nice值(nice值与优先级之间的关系是nice值越低,优先级越高)。setpriority()系统调用可以直接调整进程的优先级。

通过命令man nice 命令查看,如图7所示。

图 7 查看手册中对nice值的描述

通过命令man setpriority查看,如图 8 所示。

图 8 查看手册中对setpriority值的描述

5. 时间片的赋值?它与优先级的关系?

在 Linux 内核中,时间片的赋值主要跟以下几个因素有关:

1.调度策略:针对不同的调度策略,比如 SCHED_OTHER、SCHED_BATCH、SCHED_IDLE、SCHED_FIFO、SCHED_RR,时间片的赋值是不同的。CFS(完全公平调度算法)用于 SCHED_OTHER、SCHED_BATCH、SCHED_IDLE 调度策略,而 SCHED_FIFO、SCHED_RR 则是实时调度策略。

2.进程优先级:对于 SCHED_FIFO 和 SCHED_RR 的实时任务,优先级(在 Linux 中表现为 rt_priority)是静态设定的,不过所有实时进程的优先级都高于普通进程。优先级越高的进程越先被调度,直到它完成任务或者出现更高优先级的线程抢占。

对于 CFS 调度的普通进程,优先级(在 Linux 中通过 nice 值来派生)影响的是每个进程的权重,即与每个进程关联的运行时长。nice 值越小,优先级越高,分配的 CPU 时间越多。

在新版 Linux 内核中,进程的时间片并不是固定的,不像早期的 O(1) 调度器有明确定义的时间片概念。CFS 调度器更注重进程之间的公平性,它使用虚拟运行时间(虚拟时钟)来度量进程的运行时间并按此公平调度。

以下是在 Linux 内核代码中找到的一些相关的源码部分:

普通任务的运行时间:CFS 调度器的运行时间(可以理解为时间片)在 kernel/sched/fair.c 这个文件中进行计算和更新,比如函数 entity_tick 中就更新了进程的虚拟运行时间,如图9所示。

图 9 函数 entity_tick的内容

此外,需要注意的是,调度策略、优先级、时间片等可以通过sched_setparam、sched_setattr 等系统调用进行设置。但这些调用主要用于设置调度策略和优先级,而非直接设置时间片长度。

在kernel/sched/sched.h文件中,可以找到关于优先级的定义:

#define MAX_PRIO        140#define DEFAULT_PRIO        120
struct sched_param {
    int sched_priority;
};
其中,MAX_PRIO是优先级的最大值,DEFAULT_PRIO是默认的优先级。
在kernel/sched/core.c文件中,可以找到关于nice值来调整优先级的代码:
static voidset_user_nice(struct task_struct *p, long nice)
{
    int old_prio, delta;
    if (nice < -20 || nice > 19)
        return;
    old_prio = p->static_prio;
    delta = 20 - nice;
    if (delta < 0) {
        delta = -delta;
        p->static_prio = old_prio - delta;
    } else {
        p->static_prio = old_prio + delta;
    }
}

这段代码展示了如何根据nice值(表示优先级)来调整静态优先级(static_prio)。

6. 对实时进程和多CPU的支持?

Linux内核支持实时进程和多CPU。实时进程可以通过sched_setscheduler()系统调用来设置调度策略(SCHED_FIFO或SCHED_RR)。多CPU支持通过每个CPU都有自己的运行队列来实现,每个运行队列都包含了所有在该CPU上可运行的进程。

以下是Linux内核代码中的一些部分,这些部分展示了对实时进程和多CPU的支持:

实时进程调度:在kernel/sched/sched.h文件中,定义了实时进程的宏,如图10所示。

图 10 调动策略的宏定义

在kernel/sched/sched.c文件中,实现了实时进程的调度函数:

static void sched_rt_period_timer(struct rq *rq){
    struct task_struct *curr = rq->curr;
    struct task_struct *next;
    if (curr->policy != SCHED_FIFO && curr->policy != SCHED_RR)
        return;
    /*
     * Reevaluate all tasks with equal priorities:
     */
    for_each_task_in_rq(rq, next) {
        if (next->prio == curr->prio)
            resched_task(rq, next);
    }
}

多CPU支持:在kernel/sched/core.c文件中,实现了多CPU调度的代码:

void __sched __schedule(void){
    ...
    cpu = smp_processor_id();
    rq = cpu_rq(cpu);
    ...
}

这个函数在选择下一个要运行的进程时,会首先获取当前CPU的ID,然后获取与该CPU对应的运行队列。

7. 评价Linux的调度策略,提出改进意见。

Linux的调度策略已经比较成熟,但是仍然有改进的空间。例如,可以通过引入更精细的优先级机制,如按进程组、用户或进程类型来设置优先级,以提高调度的公平性和效率。此外,还可以考虑引入更先进的调度算法,如基于反馈的控制理论或机器学习的方法,以实现更智能的调度决策。

实验小结

在本次实验中,我们通过分析 Linux 内核源码,探索了 Linux 的进程调度策略和算法。尽管我们已经对源码做了深入的研究,但是遇到了一些问题,也产生了一些值得注意的事项,以及识别了一些待提高的能力。

存在问题:

  1. 源代码理解难度大:Linux 内核源代码是底层的操作系统代码,其复杂性和深度使得对其的理解和分析较为困难。其中涉及的概念,如调度算法、优先级和时间片等,需要具备扎实的操作系统理论知识和强大的代码阅读能力。
  2. 实验结果的实用性:尽管我们对源代码有了一定的理解,但如何将这些理解转化为改进 Linux 内核的实际操作尚不清楚。

注意事项:

  1. 源码版本:Linux 内核源码更新频繁,新的版本可能会包含新的调度算法或策略,因此我们需要时刻关注内核源码的更新,理解新版本的特性和变化。
  2. 细节分析:在阅读源码时,需要注意细节,理解代码的功能,以便更准确地理解 Linux 的调度策略。

有待提高的能力:

  1. 深入理解底层代码:更好地理解 Linux 内核源代码,理解其背后的设计思想和实现细节,是需要长期磨练的技能。我们需要进一步提高我们阅读和理解底层代码的能力。
  2. 实践转化:如何把对源码的理解转化为实际的改进或应用,这是一个值得我们深思的问题,也是我们需要努力提升的能力。

相关文章
|
1月前
|
算法
数据结构实验之操作系统打印机管理器问题
本实验旨在通过实现操作系统中的打印机管理器问题,掌握队列的基本操作如入队、出队等,利用队列的先进先出特性解决先申请先打印的问题。实验包括队列的初始化、入队、出队、打印队列内容等功能,并通过菜单式界面进行交互。实验结果显示基本功能可正常执行,但在连续操作时存在执行失败的情况,需进一步优化。
42 4
|
12天前
|
SQL 网络安全 数据库
GBase 8a集群V8客户端gccli适配欧拉操作系统绕行方案分析
GBase 8a集群V8客户端gccli适配欧拉操作系统绕行方案分析
|
4月前
|
Linux C语言
深度探索Linux操作系统 —— 编译过程分析
深度探索Linux操作系统 —— 编译过程分析
31 2
|
4月前
|
存储 缓存 Java
性能分析之构建 Linux 操作系统分析决策树
【8月更文挑战第16天】性能分析之构建 Linux 操作系统分析决策树
40 0
性能分析之构建 Linux 操作系统分析决策树
|
5月前
|
弹性计算 运维
阿里云操作系统智能助手OS Copilot实验测评报告
**OS Copilot 产品体验与功能反馈摘要** 运维人员发现OS Copilot易上手,文档清晰,助其高效排查故障(8/10分)。愿意推荐并参与开源开发。亮点在于知识问答,能快速筛选答案。相较于竞品,优点是新手友好、文档清晰,但功能扩展性待增强。期望增加系统错误排查与解决方案,并集成ECS等,以优化系统安装流程。
阿里云操作系统智能助手OS Copilot实验测评报告
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是阿里云Linux的智能助手,助于提升运维效率,通过学习用户习惯提供智能建议。开发者反馈其在DevOps场景中非常有用,给予10分帮助度评价。用户赞赏其命令执行功能,希望能扩展多命令执行和错误自动修正。与ACK、ECS等集成,可自动化部署和CI/CD流程。文档清晰,适合新手,用户愿意推荐并参与开源开发。
107 3
阿里云操作系统智能助手OS Copilot实验测评报告
|
5月前
|
人工智能 搜索推荐 物联网
现代移动应用与操作系统发展趋势分析
本文探讨了当前移动应用与操作系统的最新发展趋势,涵盖了移动应用开发技术、用户体验设计及移动操作系统的演进。通过分析市场上的新兴技术和未来的发展方向,为读者提供了深入了解移动科技领域的视角。 【7月更文挑战第15天】
50 4
|
4月前
|
人工智能 Cloud Native Linux
SAS对生成式AI前景分析问题之龙蜥操作系统对大模型AI的支持如何解决
SAS对生成式AI前景分析问题之龙蜥操作系统对大模型AI的支持如何解决
28 0
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是Alibaba Cloud Linux基于大模型构建的操作系统智能助手,其旨在通过自然语言问答、辅助命令执行及系统运维调优等功能,提升用户对Alibaba Cloud Linux的使用效率。
|
5月前
|
弹性计算 运维 自然语言处理
阿里云操作系统智能助手OS Copilot实验测评报告
OS Copilot是针对Linux的智能助手,助力学习、运维及编程。用户界面直观,自然语言交互方便新手。官方文档详尽,但初次配置略复杂,适合学生和开发者。在提高代码编写和调试效率、系统学习上得分高,功能亮点包括代码生成、问答和命令执行。用户期待更多操作系统支持、自动错误分析和系统排查功能。
189 3