1.什么是伪代码,什么是源代码?
2.一篇讲解CPU性能指标提取及源码分析
3.Linux内核源码解析---万字解析从设计模式推演per-cpu实现原理
4.在离线混部-Koordinator Cpu Burst 特性 源码调研
5.鸿蒙内核源码分析(工作模式篇) | CPU的七种工作模式
什么是伪代码,什么是源代码?
一、作用不同:1、伪代码中常被用于技术文档和科学出版物中来表示算法,也被用于在软件开发的shopnc源码实际编码过程之前表达程序的逻辑。
2、源代码主要功用作用:生成目标代码,即计算机可以识别的代码。对软件进行说明,即对软件的编写进行说明。
二、对编程语言的依赖不同:
1、伪代码不依赖于语言的,用来表示程序执行过程,而不一定能编译运行的代码。在数据结构讲算法的时候用的很多。伪代码用来表达程序员开始编码前的想法。
2、源代码是相对目标代码和可执行代码而言的。 源代码就是用汇编语言和高级语言写出来的地代码。目标代码是指源代码经过编译程序产生的能被cpu直接识别二进制代码。
三、应用领域不同:
1、伪代码中常被用于技术文档和科学出版物中来表示算法。伪代码不是用户和分析师的工具,而是设计师和程序员的工具。计算机科学在教学中通常使用虚拟码,以使得所有的传源码程序员都能理解。
2、计算机源代码最终目的是将人类可读文本翻译成为计算机可执行的二进制指令,这种过程叫编译,它由通过编译器完成。
百度百科-伪代码
百度百科-代码
一篇讲解CPU性能指标提取及源码分析
这篇报告主要根据CPU性能指标——运行队列长度、调度延迟和平均负载,对系统的性能影响进行简单分析。
CPU调度程序运行队列中存放的是那些已经准备好运行、正等待可用CPU的轻量级进程。如果准备运行的轻量级进程数超过系统所能处理的上限,运行队列就会很长,运行队列长表明系统负载可能已经饱和。
代码源于参考资料1中map.c用于获取运行队列长度的部分代码。
在系统压力测试前后,使用压力测试工具stress-ng,可以看到运行队列长度的明显变化,从3左右变化到了左右。
压力测试工具stress-ng可以用来进行压力测试,观察系统在压力下的表现,例如运行队列长度、调度延迟、平均负载等性能指标。
在系统运行队列长度超过虚拟处理器个数的1倍时,需要关注系统性能。当运行队列长度达到虚拟处理器个数的3~4倍或更高时,系统的响应就会非常迟缓。
解决CPU调用程序运行队列过长的方法主要有两个方面:优化调度算法和增加系统资源。
所谓调度延迟,t源码是指一个任务具备运行的条件(进入 CPU 的 runqueue),到真正执行(获得 CPU 的执行权)的这段时间。通常使用runqlat工具进行测量。
在正常情况下使用runqlat工具,可以查看调度延迟分布情况。压力测试后,调度延迟从最大延迟微秒变化到了微秒,可以明显的看到调度延迟的变化。
平均负载是对CPU负载的评估,其值越高,说明其任务队列越长,处于等待执行的任务越多。在系统压力测试前后,通过查看top命令可以看到1分钟、5分钟、分钟的load average分别从0.、1.、1.变化到了4.、3.、1.。
总结:当系统运行队列长度、调度延迟和平均负载达到一定值时,需要关注系统性能并进行优化。运行队列长度、调度延迟和平均负载是衡量系统性能的重要指标,通过监控和分析这些指标,可以及时发现和解决问题,提高系统的鱼源码稳定性和响应速度。
Linux内核源码解析---万字解析从设计模式推演per-cpu实现原理
引子
在如今的大型服务器中,NUMA架构扮演着关键角色。它允许系统拥有多个物理CPU,不同NUMA节点之间通过QPI通信。虽然硬件连接细节在此不作深入讨论,但需明白每个CPU优先访问本节点内存,当本地内存不足时,可向其他节点申请。从传统的SMP架构转向NUMA架构,主要是为了解决随着CPU数量增多而带来的总线压力问题。
分配物理内存时,numa_node_id() 方法用于查询当前CPU所在的NUMA节点。频繁的内存申请操作促使Linux内核采用per-cpu实现,将CPU访问的变量复制到每个CPU中,以减少缓存行竞争和False Sharing,类似于Java中的Thread Local。
分配物理页
尽管我们不必关注底层实现,buddy system负责分配物理页,关键在于使用了numa_node_id方法。接下来,我们将深入探索整个Linux内核的per-cpu体系。
numa_node_id源码分析获取数据
在topology.h中,我们发现使用了raw_cpu_read函数,传入了numa_node参数。接下来,我们来了解numa_node的定义。
在topology.h中定义了numa_node。我们继续跟踪DECLARE_PER_CPU_SECTION的p源码定义,最终揭示numa_node是一个共享全局变量,类型为int,存储在.data..percpu段中。
在percpu-defs.h中,numa_node被放置在ELF文件的.data..percpu段中,这些段在运行阶段即为段。接下来,我们返回raw_cpu_read方法。
在percpu-defs.h中,我们继续跟进__pcpu_size_call_return方法,此方法根据per-cpu变量的大小生成回调函数。对于numa_node的int类型,最终拼接得到的是raw_cpu_read_4方法。
在percpu.h中,调用了一般的read方法。在percpu.h中,获取numa_node的绝对地址,并通过raw_cpu_ptr方法。
在percpu-defs.h中,我们略过验证指针的环节,追踪arch_raw_cpu_ptr方法。接下来,我们来看x架构的实现。
在percpu.h中,使用汇编获取this_cpu_off的地址,代表此CPU内存副本到".data..percpu"的偏移量。加上numa_node相对于原始内存副本的偏移量,最终通过解引用获得真正内存地址内的值。
对于其他架构,实现方式相似,通过获取自己CPU的偏移量,最终通过相对偏移得到pcp变量的地址。
放入数据
讨论Linux内核启动过程时,我们不得不关注per-cpu的值是如何被放入的。
在main.c中,我们以x实现为例进行分析。通过setup_percpu.c文件中的代码,我们将node值赋给每个CPU的numa_node地址处。具体计算方法通过early_cpu_to_node实现,此处不作展开。
在percpu-defs.h中,我们来看看如何获取每个CPU的numa_node地址,最终还是通过简单的偏移获取。需要注意如何获取每个CPU的副本偏移地址。
在percpu.h中,我们发现一个关键数组__per_cpu_offset,其中保存了每个CPU副本的偏移值,通过CPU的索引来查找。
接下来,我们来设计PER CPU模块。
设计一个全面的PER CPU架构,它支持UMA或NUMA架构。我们设计了一个包含NUMA节点的结构体,内部管理所有CPU。为每个CPU创建副本,其中存储所有per-cpu变量。静态数据在编译时放入原始数据段,动态数据在运行时生成。
最后,我们回到setup_per_cpu_areas方法的分析。在setup_percpu.c中,我们详细探讨了关键方法pcpu_embed_first_chunk。此方法管理group、unit、静态、保留、动态区域。
通过percpu.c中的关键变量__per_cpu_load和vmlinux.lds.S的链接脚本,我们了解了per-cpu加载时的地址符号。PERCPU_INPUT宏定义了静态原始数据的起始和结束符号。
接下来,我们关注如何分配per-cpu元数据信息pcpu_alloc_info。percpu.c中的方法执行后,元数据分配如下图所示。
接着,我们分析pcpu_alloc_alloc_info的方法,完成元数据分配。
在pcpu_setup_first_chunk方法中,我们看到分配的smap和dmap在后期将通过slab再次分配。
在main.c的mm_init中,我们关注重点区域,完成map数组的slab分配。
至此,我们探讨了Linux内核中per-cpu实现的原理,从设计到源码分析,全面展现了这一关键机制在现代服务器架构中的作用。
在离线混部-Koordinator Cpu Burst 特性 源码调研
在离线混部场景下,Koordinator引入了Cpu Burst特性来优化CPU资源管理。这个特性源自Linux内核的CPU Burst技术,旨在处理突发的CPU使用需求,减少CPU限流带来的影响。cgroups的参数如cpu.share、cpu.cfs_quota_us和cpu.cfs_burst,分别控制了CPU使用率、配额和突发缓冲效果。在Kubernetes中,资源请求(requests.cpu)和限制(limits.cpu)通过这些参数来实现动态调整,以保证容器间公平的CPU分配。
对于资源调度,Kubernetes的Bandwidth Controller通过时间片限制进程的CPU消耗,针对延迟敏感业务,如抖音视频服务,通过设置合理的CPU limits避免服务质量下降,同时也考虑资源的高效利用。然而,常规的限流策略可能导致容器部署密度降低,因为时间片间隔可能不足以应对突发的CPU需求。CPU Burst技术正是为了解决这个问题,通过收集未使用的CPU资源,允许在突发时使用,从而提高CPU利用率并减少throttled_time。
在Koordinator的配置中,通过configMap可以调整CPU Burst的百分比,以及在负载过高时的调整策略。例如,当CPU利用率低于阈值时,允许动态扩展cfs_quota,以应对突发的CPU使用。源码中,会根据节点负载状态和Pod的QoS策略来调整每个容器的CPU Burst和cfs_quota。
总的来说,Cpu Burst特性适用于资源利用率不高且短作业较多的场景,能有效提升核心业务的CPU资源使用效率,同时对相邻容器的影响较小。在某些情况下,结合cpuset的核绑定和NUMA感知调度可以进一步减少CPU竞争。理解并灵活运用这些技术,有助于优化云计算环境中的资源分配和性能管理。
鸿蒙内核源码分析(工作模式篇) | CPU的七种工作模式
鸿蒙内核源码深入解析工作模式:CPU的七重身份
CPU的工作模式,如同后台管理系统中的权限管理,是其运行的关键要素,它决定着处理器的行为,包括特权级别管理和异常处理等。本文将逐步揭示鸿蒙内核中这些模式的奥秘,从底层汇编代码入手,探索CPU在七种模式中的转换和工作流程。
首先,让我们通过一张图理解在ARM体系中,CPU像韦小宝一样,频繁在七种工作模式间切换,其中用户模式是唯一的非特权模式,其余六种则拥有独立的入口和栈空间,每个特权模式都有自己的独立栈,如异常模式下的栈空间则是由操作系统来管理的。
为了保证模式间的流畅切换,CPU需要解决三个基本问题:异常模式的栈空间申请、入口地址的设置以及异常模式间的切换机制。例如,鸿蒙内核会为异常模式申请栈空间,并定义每个异常的入口地址,比如系统调用通过软中断(swi)处理,其优先级在异常中较低。
在异常模式切换时,CPSR和SPSR寄存器起到了关键作用。CPSR负责记录当前程序的状态,而SPSR则保存了CPSR在异常发生时的状态,确保异常处理后能正确返回到先前的工作状态。理解这些寄存器的工作原理,有助于深入理解鸿蒙内核的异常处理机制。
接下来的文章会更详细地解读这些汇编代码,让你逐步揭开鸿蒙内核的神秘面纱,从开机代码的异常优先级到异常模式的切换过程,逐一剖析。让我们一起探索CPU在这些模式下的工作奥秘吧。