多核调度预备知识

问题

内核对进程调度时发生了什么?

进程调度的本质

任务 / 进程 切换

  • 即:上下文切换,内核对处理器上的执行的进程进行切换
  • "上下文" 指:寄存器的值
  • "上下文切换" 指:
    • 将寄存器的值保存在内存中 (进程被剥夺处理器,停止执行)
    • 将另一组寄存器的值从内存中加载到寄存器 (调度下一个进程执行)

进程调度的本质

当时间片耗完,不管进程正在执行什么代码,都一定会发生上下文切换!

上下文切换必然导致进程状态的转换

上下文切换由中断触发 (时钟中断,IO中断,等)

上下文切换是在中断触发的,中断触发的时候一般会把中断给关闭,等中断服务程序执行结束再打开中断

详解 Linux 进程状态 (ps au)

helloworld.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>

static void* thread_entry(void* arg)
{
    while(1);
    
    return arg;
}

static void make_thread()
{
    pthread_t tid = 0;
    
    pthread_create(&tid, NULL, thread_entry, NULL);
}

int main(void)
{
    printf("pid = %d, ppid = %d, pgid = %d\n", 
            getpid(), getppid(), getpgrp());
    
    printf("hello world\n");
    
    // make_thread();
    
    while(1) sleep(1);
    
    return 0;
}


编译后运行,使用 ps au 命令查看该进程的状态

进程状态为 S+,表示该进程处于可中断的睡眠状态,并且该进程位于前台进程组中

修改程序,将主进程的 sleep 去掉,查看进程的状态

helloworld.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>

static void* thread_entry(void* arg)
{
    while(1);
    
    return arg;
}

static void make_thread()
{
    pthread_t tid = 0;
    
    pthread_create(&tid, NULL, thread_entry, NULL);
}

int main(void)
{
    printf("pid = %d, ppid = %d, pgid = %d\n", 
            getpid(), getppid(), getpgrp());
    
    printf("hello world\n");
    
    // make_thread();
    
    while(1);
    
    return 0;
}


编译后运行,使用 ps au 命令查看该进程的状态

进程的状态为 R+,表示进程正在执行,处于前台进程组中,此时该进程的 CPU 占用率是 100%

修改程序,在主进程中创建一个线程,在这个线程中也做死循环操作

helloworld.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>

static void* thread_entry(void* arg)
{
    while(1);
    
    return arg;
}

static void make_thread()
{
    pthread_t tid = 0;
    
    pthread_create(&tid, NULL, thread_entry, NULL);
}

int main(void)
{
    printf("pid = %d, ppid = %d, pgid = %d\n", 
            getpid(), getppid(), getpgrp());
    
    printf("hello world\n");
    
    make_thread();
    
    while(1);
    
    return 0;
}


编译后运行,使用 ps au 命令查看该进程的状态

进程的状态为 Rl+,表示该进程正在执行,处于前台进程组中,并且有多个线程

此时该进程的 CPU 占用率为 189%,超过了 100%

我们使用 lscpu 命令,来查看 cpu 的信息

该 cpu 是个双核 cpu,我们猜想 helloworld.out 这个进程 cpu 占用率为 189%,是因为这个 cpu 的两个核同时在执行这两个线程

为了验证这个猜想,我们使用 taskset -c 0 helloworld.out 这个命令,让 helloworld.out 这个进程只能运行在 cpu0 上,然后使用 ps au 命令查看该进程的状态

可以看出 cpu 占用率变为了 95.5%,现在该进程的两个线程都在 cpu0 上执行

这个实验说明了线程是最小的执行单位,并且不同的线程可以同时运行于多个 cpu 上

细说空闲状态

处理器上电后,开始一直不停的向下执行指令

当系统中没有进程时,会执行一个 "不执行任何操作的" 的空闲进程

空闲进程的职责:执行特殊指令使处理器进入休眠状态 (低功耗状态)

空闲状态是一种暂态,但凡出现就绪进程,空闲状态立即结束

Linux 性能工具简介

ps -- 查看进程运行时数据 (ps au)

top -- Linux 整体性能监测工具 (类似任务管理器)

sar -- Linux 活动情况报告 (系统性能分析工具)

Linux 系统平均负载

即:Linux 系统负载平均值 (Linux System Load Averages)

该值表示的是一段时间内任务对系统资源需求的平均值 (1、5 和 15 分钟)

  • 如果平均值接近 0,意味着系统处于空闲状态
  • 如果平均值大于 1,意味着系统繁忙,任务需要等待,无法及时执行
    • 如果 1min 平均值高于 5min 或 15min 平均值,则负载正在增加
    • 如果 1min 平均值低于 5min 或 15min 平均值,则负载正在减少

详解 sar -q

runq-sz:执行队列的长度

plist-sz:运行中的任务 (进程 & 线程) 总数

ldavg-1:最近 1min 系统平均负载

ldavg-5:最近 5min 系统平均负载

ldavg-15:最近 15min 系统平均负载

系统调度观察实验

通过 Linux 性能工具观察进程调度

  • 单处理器运行过程
  • 多处理器运行过程

helloworld.c


#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <pthread.h>
#include <unistd.h>

static void* thread_entry(void* arg)
{
    while(1);
    
    return arg;
}

static void make_thread()
{
    pthread_t tid = 0;
    
    pthread_create(&tid, NULL, thread_entry, NULL);
}

int main(void)
{
    printf("pid = %d, ppid = %d, pgid = %d\n", 
            getpid(), getppid(), getpgrp());
    
    printf("hello world\n");
    
    // make_thread();
    
    while(1);
    
    return 0;
}


当前的 cpu 是双核 cpu,可以同时运行两个线程,我们使用 taskset -c 0 helloworld.out & 和 taskset -c 1 helloworld.out & 命令,分别在两个 cpu 上面运行该程序,然后使用 top -d 1 命令和 sar -q 1 命令来查看当前系统性能相关信息

可以看出最近 1min 的平均负载为 2.04,大于了处理器的数量,2 个 cpu 的占用率接近了 100%,当前系统运行繁忙,无法及时执行任务

然后将 cpu1 上运行的 helloworld.out 进程 kill 掉,再次查看结果

可以看出最近 1min 的平均负载为 1.16,cpu0 的占用率接近 100%,cpu1的占用率接近 0%

系统调度核心性能指标

吞吐量:单位时间内的工作总量 (越大越好)

  • 处理器资源消耗越多 (空闲状态占比越低),吞吐量越大
  • 对于进程调度而言,吞吐量指单位时间处理的进程数量

延迟:从开始处理任务到结束处理任务所耗费的时间 (越短越好)

  • 对于进程而言,延迟即生命期,指进程从运行到结束所经历的时间
  • 注意:运行 和 执行 不同,运行时间可能很长,但执行时间可能很短

吞吐量计算一

吞吐量计算二

吞吐量计算三

假设:每个进程固定执行 60ms

则:进程运行结束时

结论:

处理器的能力由硬件设计决定,吞吐量决定一个上限

当吞吐量未达上限,进程的延迟取决于进程自身

当吞吐量达到上限,随着进程数量增加,总延迟增加,但平均延迟不变

思考

多核吞吐量计算

现实中的系统

理想状态:进程正在执行,并且没有就绪状态的进程

空闲状态:处理器占用率低,吞吐量低

繁忙状态:

多个进程同时运行,但存在多个就绪状态的进程

此时,吞吐量很高(可能达到峰值),但总延迟会变长

  • 18
    点赞
  • 19
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值