当2022级的同学考上研究生,这个暑假在云班课开启了Linux内核学习之旅,很多同学是零基础、本科非计算机专业,通过两个月的学习,他们逐渐踏入Linux内核的大门,开启性能探索之旅。
这篇报告主要根据CPU性能指标——运行队列长度、调度延迟和平均负载,对系统的性能影响进行简单分析。
CPU调度程序运行队列中存放的是那些已经准备好运行、正等待可用CPU的轻量级进程,如果准备运行 的轻量级进程数超过系统所能处理的上限,运行队列就会很长,运行队列长表明系统负载可能已经饱和。
代码源于参考资料1中map.c用于获取运行队列长度的部分代码:-
// 获取运行队列长度
// SEC("kprobe/update_rq_clock")
int update_rq_clock(struct pt_regs *ctx) {
u32 key = 0;
u32 rqKey = 0;
struct rq *p_rq = 0;
p_rq = (struct rq *)rq_map.lookup(&rqKey);
if (!p_rq) { // 针对map表项未创建的时候,map表项之后会自动创建并初始化
return 0;
}
bpf_probe_read_kernel(p_rq, sizeof(struct rq), (void *)PT_REGS_PARM1(ctx));
u64 val = p_rq->nr_running;
runqlen.update(&key, &val);
return 0;
}
挂载点:update_rq_clock()函数
update_rq_clock()被scheduler_tick()函数调用。
周期性调度器:
周期性调度器在scheduler_tick中实现. 如果系统正在活动中, 内核会按照频率HZ自动调用该函数. 如果没有进程在等待调度, 那么在计算机电力供应不足的情况下, 内核将关闭该调度器以减少能耗. 这对于我们的 嵌入式设备或者手机终端设备的电源管理是很重要的。
周期性调度器主流程:
scheduler_tick函数定义在kernel/sched/core.c,linux内核版本:5.15:
void scheduler_tick(void)
{
int cpu = smp_processor_id();
struct rq *rq = cpu_rq(cpu);
struct task_struct *curr = rq->curr;
struct rq_flags rf;
unsigned long thermal_pressure;
u64 resched_latency;
arch_scale_freq_tick();
sched_clock_tick();
rq_lock(rq, &rf);
update_rq_clock(rq);
.....
在这个函数中主要做两方面工作:
函数 | 描述 | 定义 |
---|---|---|
update_rq_clock | 处理就绪队列时钟的更新, 本质上 就是增加struct rq当前实例的时钟时间戳 | sched/core.c |
update_cpu_load_active | 负责更新就绪队列的cpu_load数 组, 其本质上相当于将数组中先前 存储的负荷值向后移动一个位置, 将当前就绪队列的符合记入数组的 第一个位置. 另外该函数还引入一 些取平均值的技巧, 以确保符合数 组的内容不会呈现太多的不联系跳读. | kernel/sched/fair.c |
calc_global_load_tick | 跟新cpu的活动计数, 主要是更新 全局cpu就绪队列的 calc_load_update | kernel/sched/loadavg.c |
2 . 激活负责当前进程调度类的周期性调度方法。
由于调度器的模块化结构, 主体工程其实很简单, 在更新统计信息的同时, 内核将真正的调度工作委 托给了特定的调度类方法。
内核先找到了就绪队列上当前运行的进程curr, 然后调用curr所属调度类sched_class的周期性调度 方法task_tick,即:
curr->sched_class->task_tick(rq, curr, 0);
task_tick的实现方法取决于底层的调度器类, 例如完全公平调度器会在该方法中检测是否进程已经 运行了太长的时间, 以避免过长的延迟, 注意此处的做法与之前就的基于时间片的调度方法有本质区 别, 旧的方法我们称之为到期的时间片, 而完全公平调度器CFS中则不存在所谓的时间片概念.
bpf_probe_read_kernel():读取内核结构体的成员
rq结构体:
linux内核用结构体rq(struct rq)将处于就绪(ready)状态的进程组织在一起。rq结构体包含cfs和rt成员,分别表示两个就绪队列:cfs就绪队列用于组织就绪的普通进程(这个队列上 的进程用完全公平调度器进行调度);rt就绪队列用于用于组织就绪的实时进程(该队列上的进程用实时调 度器调度)。在多核系统中,每个CPU对应一个rq结构体**。
struct rq {
/* runqueue lock: */
raw_spinlock_t lock;
/*
nr_running and cpu_load should be in the same cacheline because
remote CPUs use both these fields when doing load calculation.
*/
unsigned int nr_running;
....
nr_running:表示总共就绪的进程数(包括cfs,rq及正在运行的)
正常运行结果,查看第三列的运行队列长度:
压力测试工具 stress-ng :
这里进行压力测试后,再次查看运行队列长度:
可以看到运行队列长度的明显变化,从3左右变化到了10左右。
总结:
当系统运行队列长度等于虚拟处理器的个数时,用户不会明显感觉到性能下降,当运行队列长度达到虚 拟处理器的4倍或更多时,系统的响应就非常迟缓了。
CPU调度程序运行队列性能调优的一般原则:
如果在很长一段时间里,运行队列的长度一直都超过虚拟处理器个数的1倍,就需要关注了,只是暂时不需要立即采取行动。如果在很长一段时间里,运行队列的长度达到虚拟处理器个数的3~4倍或更高,则需要立即采取行动。
解决CPU调用程序运行队列过长有以下两个方法:
调度延迟
所谓调度延迟,是指一个任务具备运行的条件(进入 CPU 的 runqueue),到真正执行(获得 CPU 的 执行权)的这段时间。
runqlat是一个bcc和bpftrace工具,用于测量cpu调度程序延迟,通常称为运行队列延迟。
runqlat.py部分代码:
.......
int trace_wake_up_new_task(struct pt_regs *ctx, struct task_struct *p)
{
return trace_enqueue(p->tgid, p->pid);
}
int trace_ttwu_do_wakeup(struct pt_regs *ctx, struct rq *rq, struct task_struct
*p,
int wake_flags)
{
return trace_enqueue(p->tgid, p->pid);
}
// record enqueue timestamp
static int trace_enqueue(u32 tgid, u32 pid)
{
if (FILTER || pid == 0)
return 0;
u64 ts = bpf_ktime_get_ns();
start.update(&pid, &ts);
return 0;
}
/*trace_enqueue()函数只做了一件事情,就是记录当前这个pid进程进入 runqueue 的时间戳, 现在只
考虑最普通的情况,只记录pid的情况,因此每有一个 task 被加入到 runqueue 的时候,就记录这个
task 的 pid 和当前的纳秒时间戳。*/
int trace_run(struct pt_regs *ctx, struct task_struct *prev)
{
u32 pid, tgid;
// ivcsw: treat like an enqueue event and store timestamp
if (prev->__state == TASK_RUNNING) {
tgid = prev->tgid;
pid = prev->pid;
if (!(FILTER || pid == 0)) {
u64 ts = bpf_ktime_get_ns();
start.update(&pid, &ts);
}
}
tgid = bpf_get_current_pid_tgid() >> 32;
pid = bpf_get_current_pid_tgid();
if (FILTER || pid == 0)
return 0;
u64 *tsp, delta;
// fetch timestamp and calculate delta
tsp = start.lookup(&pid);
if (tsp == 0) {
return 0; // missed enqueue
}
delta = bpf_ktime_get_ns() - *tsp;
FACTOR
// store as histogram
STORE
start.delete(&pid);
return 0;
}
.....
# load BPF program
b = BPF(text=bpf_text)
if not is_support_raw_tp:
b.attach_kprobe(event="ttwu_do_wakeup", fn_name="trace_ttwu_do_wakeup")
b.attach_kprobe(event="wake_up_new_task", fn_name="trace_wake_up_new_task")
b.attach_kprobe(event="finish_task_switch", fn_name="trace_run")
print("Tracing run queue latency... Hit Ctrl-C to end.")
.....
挂载点:
唤醒睡眠进程: process_timeout->wake_up_process->try_to_wake_up->ttwu_queue-> ttwu_do_activate()->ttwu_do_wakeup
新进程创建后(do_fork),也会被唤醒(wake_up_new_task)
wake_up系列函数,完成两个主要功能:
进程被重新调度时无论是否为刚fork出的进程都会走到finish_task_switch这个函数,主要工作为:检查回收前一个进程资源,为当前进程恢复执行做一些准备工作。
使用runqlat工具:
正常情况下使用 runqlat工具,查看调度延迟分布情况:
压力测试:
压力测试后,再次查看调度延迟:
这里观察压力测试前后的调度延迟,从最大延迟511微秒变化到了32767微秒,可以明显的看到调度延迟 的变化。
以上的 runqlat脚本只能看出延迟时间的统计结果,如果要探究延迟为什么会增大,得用 perf 这样更精 细的工具。在保持 4 个 worker 线程的情况下,采样 5 秒内和 "sched" 相关的信息:perf sched record -- sleep 5,然后用 perf sched latency 解析,可以看到每个进程的运行时间、最大延迟等 信息。像这里,就是 stress-ng 进程有 4 个线程,总共运行了 20 秒左右,最大延迟为 5.151 毫秒。
说明:
当CPU 还被其他任务占据,还没有空出来,可能还有其他在 runqueue 中排队的任务。就会产生调度延 迟,排队的任务越多,调度延迟就可能越长,所以这也是间接衡量 CPU 负载的一个指标(CPU 负载通 过计算各个时刻 runqueue 上的任务数量获得)。
平均负载:
正常情况下的top命令:
看1分钟、5分钟、15分钟的load average分别为0.66、1.68、1.49,并且cpu基本上是空闲状态。压力测试后的top命令:
再次查看1分钟、5分钟、15分钟的load average分别为4.98、3.17、1.98,并且cpu占用率达到了 99.3%。
load average 是对 CPU 负载的评估,其值越高,说明其任务队列越长,处于等待执行的任务越多。
说明:
多核和多处理器下的平均负载,单个四核处理器和具有四个处理器(每个处理器一个核)的服务器是否 相同?相对来说,是的。多核和多处理器的主要区别在于,前者是指单个 CPU 具有多个内核,而后者是 指多个 CPU。总结一下:一个四核等于两个双核,也就是四个单核。平均负载与服务器中可用内核的数 量有关,而不是它们在 CPU 上的分布情况。这意味着最大利用率范围是单核 0-1、双核 0-2、四核 0- 4、八核 0-8,依此类推。在单核处理器上,负载为 1.00 意味着容量在单核处理器上恰到好处;而在双 核处理器上,负载为 1.50 意味着负载已满,另一个也要耗尽满。同样,四核处理器上的 5.00 负载是值 得担心的,而在八核处理器上,5.00 意味着正在消耗,并且仍有最佳可用空间。我的虚拟机是四核的, 这里看出,一分钟内的平均负载已经达到4.98,已经是非常高的了。
本文由哈喽比特于2年以前收录,如有侵权请联系我们。
文章来源:https://mp.weixin.qq.com/s/GBzBl2pZzGzRvkUP5oHDdw
京东创始人刘强东和其妻子章泽天最近成为了互联网舆论关注的焦点。有关他们“移民美国”和在美国购买豪宅的传言在互联网上广泛传播。然而,京东官方通过微博发言人发布的消息澄清了这些传言,称这些言论纯属虚假信息和蓄意捏造。
日前,据博主“@超能数码君老周”爆料,国内三大运营商中国移动、中国电信和中国联通预计将集体采购百万台规模的华为Mate60系列手机。
据报道,荷兰半导体设备公司ASML正看到美国对华遏制政策的负面影响。阿斯麦(ASML)CEO彼得·温宁克在一档电视节目中分享了他对中国大陆问题以及该公司面临的出口管制和保护主义的看法。彼得曾在多个场合表达了他对出口管制以及中荷经济关系的担忧。
今年早些时候,抖音悄然上线了一款名为“青桃”的 App,Slogan 为“看见你的热爱”,根据应用介绍可知,“青桃”是一个属于年轻人的兴趣知识视频平台,由抖音官方出品的中长视频关联版本,整体风格有些类似B站。
日前,威马汽车首席数据官梅松林转发了一份“世界各国地区拥车率排行榜”,同时,他发文表示:中国汽车普及率低于非洲国家尼日利亚,每百户家庭仅17户有车。意大利世界排名第一,每十户中九户有车。
近日,一项新的研究发现,维生素 C 和 E 等抗氧化剂会激活一种机制,刺激癌症肿瘤中新血管的生长,帮助它们生长和扩散。
据媒体援引消息人士报道,苹果公司正在测试使用3D打印技术来生产其智能手表的钢质底盘。消息传出后,3D系统一度大涨超10%,不过截至周三收盘,该股涨幅回落至2%以内。
9月2日,坐拥千万粉丝的网红主播“秀才”账号被封禁,在社交媒体平台上引发热议。平台相关负责人表示,“秀才”账号违反平台相关规定,已封禁。据知情人士透露,秀才近期被举报存在违法行为,这可能是他被封禁的部分原因。据悉,“秀才”年龄39岁,是安徽省亳州市蒙城县人,抖音网红,粉丝数量超1200万。他曾被称为“中老年...
9月3日消息,亚马逊的一些股东,包括持有该公司股票的一家养老基金,日前对亚马逊、其创始人贝索斯和其董事会提起诉讼,指控他们在为 Project Kuiper 卫星星座项目购买发射服务时“违反了信义义务”。
据消息,为推广自家应用,苹果现推出了一个名为“Apps by Apple”的网站,展示了苹果为旗下产品(如 iPhone、iPad、Apple Watch、Mac 和 Apple TV)开发的各种应用程序。
特斯拉本周在美国大幅下调Model S和X售价,引发了该公司一些最坚定支持者的不满。知名特斯拉多头、未来基金(Future Fund)管理合伙人加里·布莱克发帖称,降价是一种“短期麻醉剂”,会让潜在客户等待进一步降价。
据外媒9月2日报道,荷兰半导体设备制造商阿斯麦称,尽管荷兰政府颁布的半导体设备出口管制新规9月正式生效,但该公司已获得在2023年底以前向中国运送受限制芯片制造机器的许可。
近日,根据美国证券交易委员会的文件显示,苹果卫星服务提供商 Globalstar 近期向马斯克旗下的 SpaceX 支付 6400 万美元(约 4.65 亿元人民币)。用于在 2023-2025 年期间,发射卫星,进一步扩展苹果 iPhone 系列的 SOS 卫星服务。
据报道,马斯克旗下社交平台𝕏(推特)日前调整了隐私政策,允许 𝕏 使用用户发布的信息来训练其人工智能(AI)模型。新的隐私政策将于 9 月 29 日生效。新政策规定,𝕏可能会使用所收集到的平台信息和公开可用的信息,来帮助训练 𝕏 的机器学习或人工智能模型。
9月2日,荣耀CEO赵明在采访中谈及华为手机回归时表示,替老同事们高兴,觉得手机行业,由于华为的回归,让竞争充满了更多的可能性和更多的魅力,对行业来说也是件好事。
《自然》30日发表的一篇论文报道了一个名为Swift的人工智能(AI)系统,该系统驾驶无人机的能力可在真实世界中一对一冠军赛里战胜人类对手。
近日,非营利组织纽约真菌学会(NYMS)发出警告,表示亚马逊为代表的电商平台上,充斥着各种AI生成的蘑菇觅食科普书籍,其中存在诸多错误。
社交媒体平台𝕏(原推特)新隐私政策提到:“在您同意的情况下,我们可能出于安全、安保和身份识别目的收集和使用您的生物识别信息。”
2023年德国柏林消费电子展上,各大企业都带来了最新的理念和产品,而高端化、本土化的中国产品正在不断吸引欧洲等国际市场的目光。
罗永浩日前在直播中吐槽苹果即将推出的 iPhone 新品,具体内容为:“以我对我‘子公司’的了解,我认为 iPhone 15 跟 iPhone 14 不会有什么区别的,除了序(列)号变了,这个‘不要脸’的东西,这个‘臭厨子’。