自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+

  • 博客(29)
  • 资源 (2)
  • 收藏
  • 关注

原创 Linux内核的CFS调度类何以保障进程调度的公平?

比如下面这颗红黑树,如果节点的键值代表的是vruntime的话,那下一次调度选择进程就会选择vruntime为5的这个进程。“照顾弱者”是CFS很重要的一个调度理念,得到运行CPU时间比较短的进程总能在调度器选择下一个执行进程的时候得到青睐。可以看到nice值越小,优先级越高,加权后实际时长就会被更大程度上缩小,起到的直接效果就是vruntime累加的越小,运行队列的红黑树中更容易被排列在左下角的位置,相对其他进程更容易得到调度器更多的调度机会。所以vruntime是理解CFS调度很关键的一个指标。

2025-04-04 15:25:53 141

原创 Linux内核原子操作实现原理几问几答

用锁当然可以实现独占原子性的操作,但是要么引发调度,要么自旋空转,对于简单的内存操作没有必要。cmpxchg在各个平台都有各自的实现,且其实现的方式都以原子性指令实现,比如x86架构的cmpxchg指令,ARM64架构的ldxr和stxr指令。首先,armv8.0架构上可以调用casx指令,但是个人理解应该是伪指令的形式实现的,本质上还是利用ldxr和stxr实现的。高并发访问的时候可以根据需求使用原子操作API,可以使用共用定义基于cmpxchg实现的API也可以使用架构优化的版本。

2025-03-26 15:31:42 731

原创 使用ARM NEON进行矩阵乘法运算

最近想要体验一下ARM Helium (MVE)对SIMD指令的支持,于是到网络上想要购买一款搭载ARMv8-M架构CPU的开发板,然而看中的板子需要较长的交货周期,于是暂时放弃。因为NEON和Helium在设计理念上有诸多相似之处,之前笔者对于NEON也不是非常熟悉,所以尝试用NEON进行一个简单的3x3矩阵乘法运算,以对其有个初步的了解,这里顺带做个记录,分享一下。向量b中的每个标量和向量v中lane作为index下标取出的标量数字相乘,计算结果和向量a中的每个标量相加并将计算结果存储在a中。

2025-03-20 14:12:43 868

原创 ARMv8.x-M架构计算能力概览

ARMv7-M架构完全没有这方面的计算能力,而ARMv8.1-M提供了适用于Cortex-M系列的SIMD计算能力。以Cortex-M33为例,该CPU采用ARMv8-M架构,其DSP拥有下面的拓展计算能力。Cortex M55提供了比较完整的计算能力,其对架构的实现代表了目前ARM对ARMv8.x-M架构的实现方式。首先,IFU,DPU和LSU是传统CPU最基础的组成部分,执行的是取指,译码,执行,访存,写回的经典流水线步骤。其次,ARMv8.x-M架构手册明确列出了更多可选的CPU拓展计算能力。

2025-03-18 09:47:11 437

原创 READ_ONCE和WRITE_ONCE

注意,这三条语句互相之间没有任何赋值依赖关系。在这种情况下,编译器进行顺序优化后可能导致赋值语句的各种先后顺序。关于这个问题,Documentation/memory-barriers.txt中提到的下面这个例子非常典型。所以对于有对编译器顺序优化要严格控制的读写语句,要用READ_ONCE和WRITE_ONCE控制一下。线程A的两条赋值语句可能被顺序优化,这样线程B可能会错误的打印出-1。第一句检查变量x的类型,需要时8,16,32,64位数据类型。主要是防止编译器对代码进行顺序优化从而导致未知的错误。

2024-12-22 15:34:25 239

原创 对axidmatest驱动略作改进

Xilinx的axidmatest驱动程序对axidma这个IP的软件驱动方式做了很基础很清晰的示范。这意味着如果使用者想要反复执行收发的逻辑,首先需要将其单独编译成模块,然后利用动态插入/拔除内核模块的方式执行收发逻辑。其次,该驱动的数据验证方式利用pattern的对比进行确认,执行逻辑稍显繁琐。基于以上背景,笔者在借用axidma部分概念的基础上重写了一个测试驱动程序,命名为axidmatester。笔者的axidmatester驱动程序针对第一部分提到的问题,主要进行两方面的改进。

2024-12-22 15:32:17 245

原创 axidmatest驱动程序的数据验证方式

总的来讲,数据的校验并非是通过校验码等机制实现验证,主要是通过pattern对比进行的。每部分会被填入不同的pattern,传输后对传输后的数据进行pattern的对比,以此来判定axidma传输的成功与否。上图中的代码里面,dmatest_random函数生成一个随机数,计算后的len变量就是传输数据的第二部分的大小。axidmatest驱动程序是Petalinux自带的AXIDMA驱动验证程序,该驱动在初始化的过程中,通过dmaengine机制进行自发自收来验证FPGA设计的成功。

2024-12-08 16:11:03 501

原创 petalinux编译无法找到cracklib的报错

解决方法是到[project dir]/components/yocto/layers/poky/meta/recipes-extended/cracklib/cracklib_2.9.8.bb中把分支信息改为main即可解决问题。petalinux-build命令无法找到cracklib。原因是github上的cracklib主分支并非是Master而是main。

2024-12-01 16:53:21 278

原创 Vivado报错 This design contains one or more cells for which bitstream generation is not permitted.

大致的过程是先生成bit文件,然后导出应急爱你信息到xsa文件中。需要注意的是,在加载license后,需要在tcl console中输入reset_project重新梳理各个ip的状态。这个问题的本质在于tri_mode_eth_mac这个ip没有license许可,只可以综合与实现,不能生成bit文件。经过实践,license重新加载后也不一定能将license状态改过来,重启vivado比较有效。解决的办法在于去xilinx官网申请license文件,加载后即可解决本问题。

2024-11-24 20:48:29 661

原创 蜂鸟e203MCU的CPU定时器管理

同时,因为软硬件同时开源的特性,对于帮助开发者加深软硬件协同的理解或者说计算机底层机制的实现原理很有帮助。作为非CSR寄存器,其内容的读写通过地址访问进行,不同硬件系统的设计可能将这两个寄存器映射到完全不同的物理地址,但是其功能应保持一致。mtime寄存器以恒定的频率进行计数增长,一旦大于等于mtimecmp寄存器中的值,即产生一个定时器中断。MIE字段对应机器模式下的全局中断开关控制,SIE字段对应的是监督模式下的全局中断开关控制。相应的,每种类型的中断其开关控制可以在CSR寄存器MIE中进行配置。

2024-11-17 16:20:54 1417

原创 蜂鸟e203处理器对中断上下文的处理

e203处理器官方提供的SDK中提供了对于中断处理的系统逻辑,使用SDK进行固件开发,尤其是standalone固件,默认无需关心相关的底层实现。大致上中断发生时,操作系统首先需要保存中断上下文,然后切换到中断栈,执行注册的处理函数,切换回内核栈,恢复中断上下文等等。e203作为一款简单的处理器,其软件上对中断的处理非常简单明了,无需像Linux一样考虑中断发生在用户层还是内核层,也无需准备专用的内核栈来供处理函数使用。下面的寄存器是RV32E架构的处理器不必保存而其他架构必须保存的。保存中断发生的原因。

2024-11-10 20:36:07 705

原创 Ubuntu操作系统使用kdump

本文主要记录如何在Ubuntu操作系统上使用自编内核并使用kdump转存系统信息并使用crash工具进行分析。在笔者的计算机上,通过apt命令安装的gdb版本比较旧,无法正确匹配crash的使用。执行后系统重新启动,在/var/crash下面会生成一个以时间戳命名的文件夹,文件夹中包含dump文件。我们知道crash工具需要dump文件和vmlinux文件作为分析的依据,所以本文主要围绕这两个文件的获取展开。这样在编译后不但会有内核镜像的deb包,还会诞生包含debug信息的deb包。

2024-11-02 09:04:33 567

原创 内存屏障

举个例子,比如dsb ish指令,其作用是确保在Inner-shareable,也就是所有CPU的范围内dsb之前的内存读写指令在dsb指令执行之前完成,dsb后面的指令在dsb指令执行之后完成。DMB(Data Memory Barrier)指令能够确保程序中该指令之前的内存访问指令在该指令后面内存访问指令之前执行,所以DMB确保的是一个相对的执行顺序。最后在TLBI指令执行后冲刷流水线,重新从cache或内存预取指令,保证从这时起,所有指令访问MMU的TLB条目均包含最新的内存属性和地址等信息。

2024-10-26 17:30:15 542

原创 /proc/meminfo

上限 = (全部物理内存 - 全部huge tlb 页面) × overcommit_ratio% + 交换分区大小。vmalloc分配器管理的虚拟地址空间大小。可用内存 = 空闲内存 + page cache + 可回收页面大小 - 保留页面大小。映射到用户空间用于page cache的巨页大小。直接映射到虚拟地址空间的4K(pte)页面大小。直接映射到虚拟地址空间的2M(pmd)页面大小。直接映射到虚拟地址空间的1G(pud)页面大小。映射到用户空间的匿名页面大小。映射到用户空间的文件页面大小。

2024-10-20 09:24:55 696

原创 ARMv8架构L3页表属性

置位说明该页表属于某一特定进程(ASID)的TLB。不置位说明所有进程(ASID)的TLB均可缓存并查询该页。表示该页表处于一个连续物理页面集合中,可以用一条TBL条目进行描述,以增强查询效率。基于页面的硬件属性,没有实现ARMv8.2 TTPBHA的话,直接忽略。所有CPU,GPU和DMA设备均可访问。0: EL0不能访问,EL1~EL3可访问。内存属性要区分普通内存属性和设备内存属性。仅一个CPU可以访问。仅所有CPU可以访问。1: EL0~EL3均可访问。UXN:不可以在EL0执行。

2024-10-19 16:22:11 699

原创 Cache伪共享(False Sharing)问题浅析

因为CPU1要写入,写入后CPU1上的Line变为M,而CPU0上该Line同步更新状态为I。如果CPU0上的线程频繁使用变量a,CPU1上的线程频繁使用变量b,那么根军缓存一致性协议MESI,这个Line在不同CPU的Cache上进行同步的代价是很高的。在两颗CPU频繁访问不同变量的情况下,容易出现因为同一Line内容频繁做状态同步导致的性能下降问题,这个问题就称之为Cache伪共享问题。再之后两颗CPU上频繁的对自己需要的变量进行访问和写入,该Line的状态会来回在M和I之间摆动。

2024-10-18 13:22:21 349

原创 在QEMU上开启Extensible Scheduler Class特性

以上操作之后,重新进入Kernel hacking ---》 Compile-time checks and compiler options菜单。进入Kernel hacking ---》 Compile-time checks and compiler options。另外,DEBUG_INFO_BTF还依赖pahole的版本,我的Ubuntu系统没有安装,这里要用apt命令安装一下。启动QEMU后会发现/sys/kernel/目录下出现了sched_ext目录,说明ESC开启了。

2024-10-16 09:19:56 339

原创 ARMv8架构TLB (Transaction Lookaside Buffers)基本信息 (一)

ARMv8的TLB没有固定格式。EL1中虚拟地址指定的所有内部共享TLB无效。ELn中所有虚拟地址指定的内部共享TLB无效。使EL1中ASID包含的内部共享TLB无效。EL1中虚拟地址指定的所有TLB无效。ELn中所有虚拟地址指定的TLB无效。使ELn中所有内部共享的TLB无效。使EL1中ASID包含的TLB无效。虚拟地址对应的page的TLB无效。进程地址空间中一段地址的TLB无效。内核地址空间中一段地址的TLB无效。进程的用户空间全部TLB无效。使ELn中所有TLB无效。CPU上全部TLB无效。

2024-10-15 21:17:24 420

原创 dump_stack函数对SMP的实现(6.12 rc3版本)

首先检查当前CPU上的dump_stack函数有没有嵌套调用,如果是,将printk_cpu_sync_nested变量减一然后返回。最后将printk_cpu_sync_owner重新设置为-1,这样让其他CPU上调用dump_stack的任务可以停止等待得到执行的机会。对SMP特性的支持主要体现在printk_cpu_sync_get_irqsave和printk_cpu_sync_put_irqrestore函数中。这个变量初始化值为-1。之后调用__printk_cpu_sync_try_get。

2024-10-12 13:32:25 344

原创 dump_stack对SMP特性的支持

如果在当前CPU上,dump_stack已经被调用了,还没有恢复为-1,允许在当前CPU上再次调用dump_stack。这种情况应该是前一个调用dump_stack的进程被抢占了。是的,该函数就是这样设计的。最后一种情况是dump_stack已经在一颗CPU上被调用了,其他CPU在这个时候也调用了这个函数,那就只能等待了。原子变量dump_lock在dump_stack没有被调用的时候是-1。在被调用的时候记录当前CPU的ID。如果dump_stack之前没有被调用,was_locked变量置0。

2024-10-11 14:17:56 276

原创 asmlinkage

asmlinkage本身是个宏定义,X86/IA64以外的架构定义在include/linux/linkage.h头文件中。我们用gcc命令进行编译的时候会报undefined reference错误。也就是asmlinkage本身就是extern “C”。主要的目的是让C++程序能够调用到这个C语言定义的函数。这里基于5.15.133版本分析一下这个“修饰符”。如果给hello函数加个extern “C”,

2024-10-11 08:54:39 169

原创 dump_stack在ARM64架构的实现

我们可以用下面这篇博客(https://blog.youkuaiyun.com/weixin_45030965/article/details/136941115)中的插图来说明一下(自己辛苦画的图没有及时Ctrl+S,结果编辑软件crash了,没保存下来)。ARM64架构的栈帧,在caller函数对callee函数调用之前,栈帧入栈的最后两个寄存器按照先后顺序分别是FP和LR。所以在dump_backtrace函数中,主要是通过循环,每次通过当前的fp值获取上一帧的信息,然后不断向上回溯。

2024-10-09 15:59:14 721

原创 stop调度类

因为整体负载比较有限,所以load_balance在完成第一步要进行第二步的负载迁移的时候,常常因为找到的负载最重的CPU核心的运行队列中处于可运行状态(TASK_RUNNING)的进程小于等于1而迁移失败。总体而言,在同一个调度域(sched domain)中,空闲状态的CPU核心会承担起负载均衡的工作,从调度域内最繁忙的CPU核心将负载向自身迁移,从而达到负载均衡的目的。这种情况下,负载重的CPU核心可能真的处于非常繁忙的状态下,对于负载迁移这样的工作的优先级一定要得到充分的保障才行。

2024-10-07 15:11:53 842

原创 空间滤波之均值滤波

空间滤波的过程需要对每个像素一次处理,针对每个像素的计算需要考虑其周边像素的值。本质上来讲,如果对部分或者全部的像素进行滤波,就是根据其周边的像素值计算该像素值。作为最简单的一种滤波方式,均值滤波的思想是将其周围的像素逐个除以参与计算像素的个数,其相加的值就是像素P的值。以像素P为例,像素P原值和和周边像素共有9个像素,则每个像素均乘以九分之一累加得到一个新像素值。以上面的例子来讲,就是像素P或者是其周围的一圈像素值。公式表达的就是计算过程将每一对s和t产生的坐标取出的计算因数和像素值相乘然后累加。

2024-10-06 08:52:00 645

原创 Linux内核中的红黑树可以在Linux以外的编译环境使用吗?

经过简单的测试,将红黑树的实现从Linux内核中迁移出来使用应该是可行的。笔者多年前受另一工程师启发,开始尝试在各种软件开发环境中使用Linux提供的数据结构实现机制,最常用的就是Linux中的链表实现。这样做的优点是可以直接使用各种强大的API对数据结构进行高效操作,因为是Linux的API操作也非常顺手。如果想在自己的工程中实现,需要更精细的修改和更严密的测试。另外,该程序因为没有做树节点的释放存在内存泄漏。注意,container_of的宏定义中是有BUG_ON的判断的,这里为了方便验证被我拿掉了。

2024-10-05 08:35:55 623

原创 使用perf工具观察计算机上中断的分布情况

使用irq_handler_entry跟踪事件记录一段时间内的中断触发情况,使用perf script命令可以得到采样的CPU编号和触发的IRQ编号信息。然后通过python脚本简单的提取这两条信息将分布情况显示出来即可。首先使用perf record命令抓取5秒钟的irq:irq_handler_entry事件。之后编写一个简单(非常粗糙)的python脚本简单分析一下分布情况。可以看到中断134在这段时间内触发最多,比例达到83.8%。可以看到CPU9上的中断触发次数最多。

2024-10-04 08:43:35 1371

原创 Linux内核中本地IRQ开关在ARM64架构上的实现

arch_local_irq_save的第二步就是先检测目前IRQ是否已经屏蔽,如果没有,则调用arch_local_irq_disable进行屏蔽,这一部分和local_irq_disable相同。本地CPU的IRQ关闭一般可以使用local_irq_save或者local_irq_disable,开启IRQ则相应的使用local_irq_restore和local_irq_enable。local_irq_disable/local_irq_enable成对操作,中断开关不保存并恢复中断屏蔽状态。

2024-10-03 09:17:08 1505

原创 如何利用能耗模型计算CPU的功耗?

这里出现一个问题,就是根据以上计算逻辑,计算出的频率值不一定是该CPU支持的,或者说em_perf_domain的table数组所能提供的。em_perf_domain结构体的table字段会指向一个静态数组,数组元素类型是em_perf_state结构体,该结构体的三个字段分别表示一个CPU频率(frequency),功耗(power)和功耗计算因数(cost)。em_cpu_energy函数会传入一个pd参数,该pd参数实质是一个em_perf_domain结构体类型的指针,代表了计算目标的性能域。

2024-10-01 16:43:55 673

原创 util_est结构体的作用

转载原文原文地址:什么是数据结构作者:了不起de狐狸爸爸说到数据结构是什么,我们从这个计算机名词定义来解释,而不是说数据结构这门课程。字面上来看,“数据结构”的意思可以分别通过“数据”和“结构”来阐明。所

2024-09-24 14:43:10 680

VIM中文手册

VIM中文手册.Vim是从vi发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。

2013-03-23

apple app store 销售趋势导航

apple app store 销售趋势导航,英文版!

2011-08-07

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除