一文搞懂core-scheduling核心机制

news2024/10/3 0:33:38

cookie的原理借助于unsigned long型,和refcount_t引用计数器。

32位64位
char *4字节8字节
unsigned long4字节8字节

数据结构修改

首先看看实现core scheduling功能对数据结构有哪些修改

task_struct

struct task_struct{
    struct rb_node core_node;
    unsigned long core_cookie;
    unsigned int core_occupation;
}

sched_statistics

struct sched_statistics{
    u64 core_forceidle_sum;
}

sched_core_cookie

cookie本质就是一个内核引用计数器refcount_t成员构成的struct结构体。然后task_struct中保存的core_cookie是unsigned long型数据,刚好能存放指针变量值,就是存放的该结构体的内存地址。

使用alloc分配出来的sched_core_cookie结构体的address内存地址作为一个task的cookie值,cookie 类型是unsigned long的指针。

/*新增*/
struct sched_core_cookie{
    refcount_t refcnt;
}

rq

rq中增加了有关core sched的开关等信息。

struct rq {
    //...省略
#ifdef CONFIG_SCHED_CORE
    /* per rq */
    struct rq       *core;
    struct task_struct  *core_pick;
    unsigned int        core_enabled;
    unsigned int        core_sched_seq;
    struct rb_root      core_tree;        /*可以使用同一个core的都要加入红黑树*/

    /* shared state -- careful with sched_core_cpu_deactivate() */
    unsigned int        core_task_seq;
    unsigned int        core_pick_seq;
    unsigned long       core_cookie;
    unsigned int        core_forceidle_count;
    unsigned int        core_forceidle_seq;
    unsigned int        core_forceidle_occupation;
    u64         core_forceidle_start;
#endif
}

这部分初始化

#ifdef CONFIG_SCHED_CORE
        rq->core = rq;
        rq->core_pick = NULL;
        rq->core_enabled = 0;
        rq->core_tree = RB_ROOT;
        rq->core_forceidle_count = 0;
        rq->core_forceidle_occupation = 0;
        rq->core_forceidle_start = 0;

        rq->core_cookie = 0UL;
#endif

cfs_rq

struct cfs_rq{
    //...省略代码
    #ifdef CONFIG_SCHED_CORE
    unsigned int        forceidle_seq;
    u64         min_vruntime_fi;
#endif
}

cookie

用户态程序通过prctl系统调用来操作相关进程的cookie动作。

prctl接口

prctl系统调用接口中新增有关PR_SCHED_CORE的操作处理函数。

SYSCALL_DEFINE5(prctl, int, option, unsigned long, arg2, unsigned long, arg3,
        unsigned long, arg4, unsigned long, arg5)
{
    ...
#ifdef CONFIG_SCHED_CORE
    case PR_SCHED_CORE:
        error = sched_core_share_pid(arg2, arg3, arg4, arg5);
        break;
#endif
}
int sched_core_share_pid(unsigned int cmd, pid_t pid, enum pid_type type,
             unsigned long uaddr)
{
    unsigned long cookie = 0, id = 0;
    struct task_struct *task, *p;
    struct pid *grp;
    int err = 0;

    //...省略

    rcu_read_lock();
    if (pid == 0) {
        task = current;        /*pid为0,则是设置进程本身*/
    } else {
        task = find_task_by_vpid(pid);    /*根据pid查找进程PCB*/
        if (!task) {
            rcu_read_unlock();
            return -ESRCH;
        }
    }
    get_task_struct(task);    /*该函数就是为了给task_struct引用符计数+1,防止中断处理中程序被kill掉访问非法PCB指针*/
    rcu_read_unlock();

    /* 检查进程是否有权限修改指定的进程
     * Check if this process has the right to modify the specified
     * process. Use the regular "ptrace_may_access()" checks.
     */
    if (!ptrace_may_access(task, PTRACE_MODE_READ_REALCREDS)) {
        err = -EPERM;
        goto out;
    }

    switch (cmd) {
    case PR_SCHED_CORE_GET:        
        if (type != PIDTYPE_PID || uaddr & 7) {
            err = -EINVAL;
            goto out;
        }
        cookie = sched_core_clone_cookie(task);        /*获取task任务的cookie值*/
        if (cookie) {
            /* XXX improve ? */
            ptr_to_hashval((void *)cookie, &id);
        }
        err = put_user(id, (u64 __user *)uaddr);
        goto out;

    case PR_SCHED_CORE_CREATE:
        cookie = sched_core_alloc_cookie();        /*创建task任务的cookie值*/
        if (!cookie) {
            err = -ENOMEM;
            goto out;
        }
        break;

    case PR_SCHED_CORE_SHARE_TO:
        cookie = sched_core_clone_cookie(current);        /*共享继承指定task任务的cookie值*/
        break;

    case PR_SCHED_CORE_SHARE_FROM:
        if (type != PIDTYPE_PID) {
            err = -EINVAL;
            goto out;
        }
        cookie = sched_core_clone_cookie(task);
        __sched_core_set(current, cookie);            /*将自身cookie共享给指定的task任务*/
        goto out;

    default:
        err = -EINVAL;
        goto out;
    };

    if (type == PIDTYPE_PID) {
        __sched_core_set(task, cookie);        /*设置任务task的cookie值*/
        goto out;
    }

    read_lock(&tasklist_lock);                /*这里是对任务组进行设置,对任务组中每个任务都设置cookie*/
    grp = task_pid_type(task, type);

    do_each_pid_thread(grp, type, p) {
        if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS)) {
            err = -EPERM;
            goto out_tasklist;
            goto out_tasklist;
        }
    } while_each_pid_thread(grp, type, p);

    do_each_pid_thread(grp, type, p) {
        __sched_core_set(p, cookie);
    } while_each_pid_thread(grp, type, p);
out_tasklist:
    read_unlock(&tasklist_lock);

out:
    sched_core_put_cookie(cookie);        /*cookie指针计数器减1,并检查是否为0,没有人用则需要释放*/
    put_task_struct(task);                /*检查task指针技术减1*/
    return err;
}

该函数中,out出口时为何需要对cookie进行put,对task进行put?

  • 对task进行put是因为调用了get_task_struct(task)函数,该函数中会对task引用计数加1,所以在sched_core_share_pid()函数末尾需要对task指针引用计数减1
  • 对cookie计数减1,是因为在get_cookie,clone_cookie,allock_cookie等函数中对cookie的引用计数加了1,然后再**__sched_core_set函数中又调用get_cookie,又再次对cookie的计数加了1,一共加了两次,所以函数末尾需要相应的对cookie计数减1并检查是否为0(__sched_core_set**函数中也有一次减1操作,不过是对old_cookie的操作)。所以最终cookie的引用次数整体还是加了1的
    在这里插入图片描述

创建cookie

何时需要创建cookie?是每个进程都有一个cookie么?cookie值保存在哪里?

static unsigned long sched_core_alloc_cookie(void)
{
    struct sched_core_cookie *ck = kmalloc(sizeof(*ck), GFP_KERNEL);
    if (!ck)
        return 0;

    refcount_set(&ck->refcnt, 1);    /*cookie的计数器加1*/
    sched_core_get();                /*enable core sched功能,就是打开开关标志*/

    return (unsigned long)ck;
}

在这里插入图片描述

获取cookie

static unsigned long sched_core_get_cookie(unsigned long cookie)
{
    struct sched_core_cookie *ptr = (void *)cookie;

    if (ptr)
        refcount_inc(&ptr->refcnt);

    return cookie;
}

入参:某个task_struct的cookie值,p->core_cookie; 类型unsigned long存放的其实是指针,该指针指向结构体sched_core_cookie计数器。

get_cookie的操作主要就是对cookie中的refcnt计数器加1。

共享cookie

task任务共享当前current任务的cookie

cookie = sched_core_clone_cookie(current);
__sched_set_core(task, cookie);
static unsigned long sched_core_clone_cookie(struct task_struct *p)
{
    unsigned long cookie, flags;

    raw_spin_lock_irqsave(&p->pi_lock, flags);
    cookie = sched_core_get_cookie(p->core_cookie);    //获取指定进程的core_cookie值
    raw_spin_unlock_irqrestore(&p->pi_lock, flags);

    return cookie;
}

分享cookie

分享当前current任务的cookie给指定任务task。

cookie = sched_core_clone_cookie(task);
__sched_core_set(current, cookie);

清除cookie

static void sched_core_put_cookie(unsigned long cookie)
{
    struct sched_core_cookie *ptr = (void *)cookie;

    if (ptr && refcount_dec_and_test(&ptr->refcnt)) {
        kfree(ptr);
        sched_core_put();
    }
}

当清除task_struct时,也要记得清除其中的cookie

put_task_struct
__put_task_struct
sched_core_free
sched_core_put_cookie
void sched_core_free(struct task_struct *p)
{
    sched_core_put_cookie(p->core_cookie);
}

父子进程cookie关系

在fork系统调用中,copy_process创建新进程的时候,子进程的cookie值继承父进程的cookie值。

copy_process
sched_core_fork
void sched_core_fork(struct task_struct *p)
{
    RB_CLEAR_NODE(&p->core_node);        /*core_node红黑树节点清空*/
    p->core_cookie = sched_core_clone_cookie(current);    /*子进程cookie = 父进程cookie*/
}

周期性调度器

scheduler_tick()周期性调度器中也会涉及到core sched的操作。

scheduler_tick
sched_core_tick
__sched_core_tick
__sched_core_account_forceidle

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

Downie4.6.7

Downie是Mac下一个简单的下载管理器,可以让您快速将不同的视频网站上的视频下载并保存到电脑磁盘里然后使用您的默认媒体播放器观看它们,文章末尾附下载地址。主要特点支持许多网站目前支持超过1,000个不同的网站(包括YouTube,Vim…

06 OpenCV‘阈值处理、自适应处理与ostu方法

1 基本概念 CV2中使用阈值的作用是将灰度图像二值化,即将灰度图像的像素值根据一个设定的阈值分成黑白两部分。阈值处理可以用于图像分割、去除噪声、增强图像对比度等多个领域。例如,在物体检测和跟踪中,可以通过对图像进行阈值处理来提取目…

回收站清空了还能找回来吗?回收站恢复的4个方法(最全)

回收站作为一个数据回收的地方,可以保存已删除的文件很久,直到用户手动永久删除这些数据,这为用户避免了许多数据丢失的问题。但是回收站数据过多,难免会影响电脑的运行速度。为此,我们都会定期进行清理。 清理过程中…

LeetCode 92. 反转链表 II

原题链接 难度&#xff1a;middle\color{orange}{middle}middle 题目描述 给你单链表的头指针 headheadhead 和两个整数 leftleftleft 和 rightrightright &#xff0c;其中 left<rightleft < rightleft<right 。请你反转从位置 leftleftleft 到位置 rightrightrig…

Scala 入门(第一章Scala 环境搭建、插件的安装)

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 第 1 章 Scala 入门1.1 概述1.1.1 为什么学习 Scala1.1.2 Scala 发展历史1.1.3 Scala 和 Java 关系1.1.4 Scala 语言特点1.2 Scala 环境搭建1.3 Scala 插件安装1.4 HelloWorl…

Web 容器、HTTP 服务器 、Servlet 容器区别与联系

首先浏览器发起 HTTP 请求&#xff0c;像早期的时候只会请求一些静态资源&#xff0c;这时候需要一个服务器来处理 HTTP 请求&#xff0c;并且将相应的静态资源返回。 这个服务器叫 HTTP 服务器。 简单点说就是解析请求&#xff0c;然后得知需要服务器上面哪个文件夹下哪个名字…

三【mybatis的批量删除】

目录一 .批量删除的流程1.1 快速创建实体类1.1.1 创建完毕后 除了属性 其他内容进行删除1.2 创建mapper接口的抽象方法1.3 编写sql语句1.4 测试类Arrays.asList(删除对应的 id 值)运行结果✅作者简介&#xff1a;Java-小白后端开发者 &#x1f96d;公认外号&#xff1a;球场上的…

C语言指针剖析(初阶) 最详细!

什么是指针&#xff1f;指针和指针类型野指针指针运算指针和数组二级指针指针数组什么是指针&#xff1f;指针是内存中一个最小单元的编号&#xff0c;也就是地址。1.把内存划分为一个个的内存单元&#xff0c;一个内存单元的大小是一个字节。2.每个字节都给定唯一的编号&#…

GEE学习笔记九十一:栅格影像叠置分析

最近发现好多人都在问一个问题&#xff0c;两张影像如何取其相交区域&#xff1f;其实这个问题简单来讲就是多张栅格影像进行叠加分析。在GEE中栅格影像不像矢量数据那样有直接的函数来做数据分析&#xff0c;需要我们自己手动写一些代码来实现这些操作。要实现这个功能有很多方…

微信怎么开小店?【企业商家微信开店】

企业商家入局微信做营销已经是经营规划中必须做的一件事了&#xff0c;对于企业商家来说&#xff0c;最简单直接的方式就是开一个微信小店&#xff0c;然后通过自己宣传推广来在微信小店中成商品。那么企业商家在微信怎么开小店呢&#xff1f;下面内容分享给想在微信开店的企业…

滑块连杆模型仿真(含三菱ST+博途SCL计算源代码)

由滑块位置逆计算曲柄角度,请参看下面的文章链接,这篇博客主要计算由曲柄转动角度计算滑块位置。 https://blog.csdn.net/m0_46143730/article/details/128943228https://blog.csdn.net/m0_46143730/article/details/128943228简单的看下连杆滑块模型 模型的数学推导过程,大…

跨境电商新形式下,如何选择市场?

2022年&#xff0c;全球经济已经有增长乏力、通胀高起的趋势&#xff0c;美国等国家的通货膨胀情况令人担忧&#xff0c;不少行业面临更为复杂的外部环境以及严峻的市场挑战。不过&#xff0c;跨境电商行业依旧保持着较高的增长速度&#xff0c;越来越多有远见的卖家将电商事业…

C++之RALL机制

RALL是Resource acquisition is initialization的缩写&#xff0c;意思是“资源获取即初始化”&#xff0c;其核心思想是利用C对象生命周期的概念来控制程序的资源。它的技术原理很简单&#xff0c;如果希望对某个重要资源进行跟踪&#xff0c;那么创建一个对象&#xff0c;并将…

C语言之结构体内存的计算

结构体的内存 一.提出疑问 结构体占用的是一片连续的内存空间&#xff0c;大小是由成员变量的类型决定的。但并不是计算所有成员变量的类型大小之和那么简单。 先举一个实例&#xff1a; struct student {int age; //4个字节int telephone; //4个字节 }; int main() {struc…

如何用P6软件编制项目进度计划(下)

卷首语 根据项目合同包含的工作范围进行工作分解&#xff08;WBS&#xff09;&#xff0c;按照业主的要求及项目管理的需要&#xff0c;考虑不同阶段和层次&#xff0c;适时编制出项目管理所要求的的各级进度计划。 4搜集项目计划与进度控制相关信息 搜集与项目计划编制与进…

IP地址在金融行业有哪些应用?

中国加入WTO以来经济得到迅速发展&#xff0c;金融行业随着经济发展体系越来越完善。随着西方金融公司和理念的加入中国金融行业开始多样化发展。金融行业在快速发展的同时也引发了许多弊端。如何维护挖掘客户更大需求&#xff1f;如何获取更多优质客户&#xff1f;如何提升网络…

使用netty+springboot打造的tcp长连接通讯方案

文章目录项目背景正文一、项目架构二、项目模块三、业务流程四、代码详解1.消息队列2.执行类3.客户端五、测试六、源码后记项目背景 最近公司某物联网项目需要使用socket长连接进行消息通讯&#xff0c;捣鼓了一版代码上线&#xff0c;结果BUG不断&#xff0c;本猿寝食难安&am…

大公司如何用A/B测试解决增长问题?

摘要&#xff1a;上线六年&#xff0c;字节跳动的短视频产品——抖音已成为许多人记录美好生活的平台。除了抖音&#xff0c;字节跳动旗下还同时运营着数十款产品&#xff0c;从资讯、游戏&#xff0c;到房产、教育等横跨多个领域。在产品迭代速度和创新能力的快速发展下&#…

AcWing语法基础课笔记 第三章 C++中的循环结构

第三章 C中的循环结构 学习编程语言语法是次要的&#xff0c;思维是主要的。如何把头脑中的想法变成简洁的代码&#xff0c;至关重要。 ——闫学灿 学习循环语句只需要抓住一点——代码执行顺序&#xff01; while循环 可以简单理解为循环版的if语句。If语句是判断一次&#xf…

MQ技术选型

RocketMQ部署架构图NameServer&#xff1a;主要是对元数据的管理&#xff0c;包括Topic和路由信息的管理&#xff0c;底层由netty实现&#xff0c;是一个提供路由管理、路由注册和发现的无状态节点&#xff0c;类似于ZooKeeperBroker&#xff1a;消息中转站&#xff0c;负责收发…