c
文章平均质量分 56
zh'blog
嵌入式软件工程师 | 记录点滴,力求精进!
展开
-
踩内存问题定位手段汇总
踩内存问题定位原创 2022-10-16 18:21:15 · 3987 阅读 · 1 评论 -
NUMA架构CPU API变更汇总
NUMA架构CPU API函数变更原创 2022-07-10 18:41:52 · 243 阅读 · 0 评论 -
字节对齐探讨
为什么要字节对齐在一些特定处理器上只能从特定的地址开始存取。从理论上讲似乎对任何类型的变量的访问可以从任何地址开始,但实际情况是在访问特定类型变量的时候经常在特定的内存地址访问,这就需要各种类型数据按照一定的规则在空间上排列需要字节对齐的根本原因在于CPU访问数据的效率问题。假设上面整型变量的地址不是自然对齐,比如为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的原创 2022-04-23 17:56:21 · 393 阅读 · 0 评论 -
CPU | 降低流水线停滞的策略
指令流:流水线的概念,每个状态下都有一条指令在执行。execute单元会出现流水线停滞。降低流水线停滞的策略:1、分支预测2、 超标量:一个指令流里可以同时执行两个或多个指令一个线程里面的两个指令同步执行。3、 乱序执行out of order(ooo)a b c d ec要等到a、b 执行完后在执行,可以让c先停滞,让后续的d 、e继续执行然后执行reorder重新排序成c d e。也就是所谓的乱序执行。最终从fetch到commit实际是保序执行的,只是其中的指令流乱序。4、原创 2022-04-10 11:00:09 · 638 阅读 · 0 评论 -
PCI设备配置空间、BAR空间、BUS总线的理解整理
pcim_iomap bar地址映射,注意不能重复映射!设备在系统的PCI地址空间里申请一段来用,所申请的空间基址和大小保存在BAR寄存器里。BAR里的只是PCI域的地址空间,需要映射到IO地址空间里或者内存空间里之后软件才能使用。映射到IO空间的话,用IO读写指令和函数去访问设备;映射到内存空间的话,首先得到的是物理地址,映射到虚拟地址后就可以像用指针那样访问。IO BAR和MEM BAR分别是映射到IO空间和内存空间的BAR;每个BAR具体干嘛使设备自己定义的,要看手册。一旦BAR的值确原创 2022-04-09 21:52:44 · 13473 阅读 · 1 评论 -
copy_from_user函数的使用
访问用户态内存copy_from_user和copy_to_user这两个函数相信做内核开发的人都非常熟悉,分别是将用户空间的数据拷贝到内核空间以及将内核空间中的数据拷贝到用户空间。copy_from_user函数的功能就不只是从用户空间拷贝数据那样简单了,它还要做一些指针检查以及处理这些问题的方法来自 https://blog.csdn.net/u013750244/article/details/108021600?utm_medium=distribute.pc_relevant.none-ta原创 2022-04-09 21:25:43 · 1915 阅读 · 0 评论 -
DPDK优化技术
DPDK优化技术:一、内存相关优化点:Cache和内存——软件预取函数rte_prefetch0。Cache一致性——DPDK对很多结构体定义会指定对齐;避免多个核访问同一个内存地址或数据结构,采用每个核对应一个数据结构;每个接收和发送ring队列分别对应一个core。TLB和大页——常规页(4KB),如果程序比较大,可以采用大页(比如2MB),这样只需要一个表项就可以命中。以ubuntu系统为例,通过/etc/default/grub文件配置页大小。DDIO——使得外部网卡和CPU通过LLC .原创 2022-03-22 10:30:24 · 2111 阅读 · 0 评论 -
makefile文件
= 是最基本的赋值:= 是覆盖之前的值= 是如果没有被赋值过就赋予等号后面的值+= 是添加等号后面的值$(KBUILD_CFLAGS)是定义在根目录Makefile中的变量,它适用于整个内核树。obj-y += disk1/kernel/把disk1/kernel/目录下的文件编译进内核, -y是编译进内核,-m是编译成模块obj-y:把由foo.c 或者 foo.s 文件编译得到foo.o 并连接进内核.obj-m: 则表示该文件作为模块编译.除了y、m以外的obj-x 形式的目标都不.原创 2022-03-02 18:54:17 · 3196 阅读 · 0 评论 -
硬盘相关知识总结
1、 硬盘挂载https://blog.csdn.net/qq_37403371/article/details/843960992、 硬盘读写检测伪代码:1、 检测硬盘是否在位2、 打开/mnt/hd* 硬盘文件3、 初始化赋值一个CHAR型数组uContextWrite(HDD_CONTEXT_LENGTH=512字节大小,内容形式为5a5a...)4、 执行硬盘写操作,将uContextWrite内容写入硬盘5、 关闭硬盘文件6、 以读方式重新打开硬盘文件7、 读取硬盘内容到一个C原创 2022-02-24 16:19:52 · 122 阅读 · 0 评论 -
va_start和va_end的使用
函数参数的传递原理:函数参数是以数据结构:栈的形式存取,从右至左入栈。首先是参数的内存存放格式:参数存放在内存的堆栈段中,在执行函数的时候,从最后一个开始入栈。因此栈底高地址,栈顶低地址,举个例子如下:void func(int x, float y, char z);那么,调用函数的时候,实参 char z 先进栈,然后是 float y,最后是 int x,因此在内存中变量的存放次序是 x->y->z,因此,从理论上说,我们只要探测到任意一个变量的地址,并且知道其他变量的类型,通过指原创 2022-02-22 20:07:50 · 109 阅读 · 0 评论 -
支持固定硬盘插槽脚本实例
背景:当设备支持2个及两个以上硬盘槽位时(这里举例有两个硬盘槽位C0和C1),用户无法判断哪个硬盘槽位插的是hda,哪个是hdb,因为内核检测机制是哪个硬盘先被扫描到,哪个就认为是hda。通过修改hotplug脚本,可以实现固定硬盘槽位,比如C0对应hda,C1对应hdb。脚本实例:#一个是disk,表示设备本身,对应的$DEVPATH $MAJOR $MINOR分别是/block/hda0: 8 0#一个是partition,表示设备上的分区,对应的$DEVPATH $MAJOR $MINOR分别是原创 2022-02-17 19:40:53 · 520 阅读 · 0 评论 -
物理地址、虚拟地址、总线地址&&常规内存、高端内存、I/O内存、设备内存的理解
(1)物理地址CPU地址总线传来的地址,由硬件电路控制其具体含义。物理地址中很大一部分是留给内存条中内存的,但也常被映射到其他存储器上(如显存、bios等)。在程序指令中的虚拟地址经过段映射和页面映射后,就生成了物理地址,这个物理地址被放到CPU的地址线上。(2)总线地址总线的地址线或在地址周期上产生的信号。外设使用的是地址总线,cpu使用的是物理地址。物理地址和总线地址之间的关系有系统设计决定的。在X86平台上,物理地址就是总线地址,这是因为它们共享相同的地址空间。在其他平台上,可能需要转换/映射原创 2022-02-10 17:58:29 · 382 阅读 · 0 评论 -
list_for_each_entry_rcu的使用方法
遍历带有双向链表结构的结构体变量。它实际上是一个 for 循环,利用传入的 pos 作为循环变量,从表头 head 开始,逐项向后(next 方向)移动 pos,直至又回head(prefetch() 可以不考虑,用于预取以提高遍历速度 )。#define list_for_each_entry_rcu(pos, head, member) \ for (pos = list_entry_rcu((head)->next, typeof(*pos), member); \ prefetch(原创 2022-02-10 10:50:47 · 2690 阅读 · 0 评论 -
RCU锁机制
RCU(Read-Copy Update),是 Linux 中比较重要的一种同步机制。顾名思义就是“读,拷贝更新”,再直白点是“随意读,但更新数据的时候,需要先复制一份副本,在副本上完成修改,再一次性地替换旧数据”。这是 Linux 内核实现的一种针对“读多写少”的共享数据的同步机制。适用的场景:我们前面说过,每种锁都有自己的适用的场景:spin lock不区分reader和writer,对于那些读写强度不对称的是不适合的,RW spin lcok和seq lock解决了这个问题,不过seq lock倾原创 2022-02-09 20:16:01 · 2734 阅读 · 0 评论 -
epoll机制的理解
epoll可以理解为event poll,不同于忙轮询和无差别轮询,epoll之会把哪个流发生了怎样的I/O事件通知我们。此时我们对这些流的操作都是有意义的。(复杂度降低到了O(k),k为产生I/O事件的流的个数,也有认为O(1))epoll是通过后台中断的方式来获得就绪的状态,调用epoll_create创建实例,调用epoll_ctl添加或删除监控的文件描述符,调用epoll_wait阻塞住,直到有就绪的文件描述符,通过epoll_event参数返回就绪状态的文件描述符和事件epoll_create原创 2022-02-09 14:58:18 · 958 阅读 · 0 评论 -
mmap内存映射
常规文件操作为了提高读写效率和保护磁盘,使用了页缓存机制。这样造成读文件时需要先将文件页从磁盘拷贝到页缓存中,由于页缓存处在内核空间,不能被用户进程直接寻址,所以还需要将页缓存中数据页再次拷贝到内存对应的用户空间中。这样,通过了两次数据拷贝过程,才能完成进程对文件内容的获取任务。写操作也是一样,待写入的buffer在内核空间不能直接访问,必须要先拷贝至内核空间对应的主存,再写回磁盘中(延迟写回),也是需要两次数据拷贝。而使用mmap操作文件中,创建新的虚拟内存区域和建立文件磁盘地址和虚拟内存区域映射这.原创 2022-02-09 10:06:30 · 329 阅读 · 0 评论 -
gdb命令汇总
编译程序时需要加上-g,之后才能用gdb进行调试:gcc -g main.c -o maingdb中命令:回车键:重复上一命令(gdb)help:查看命令帮助,具体命令查询在gdb中输入help + 命令,简写h(gdb)run:重新开始运行文件(run-text:加载文本文件,run-bin:加载二进制文件),简写r(gdb)start:单步执行,运行程序,停在第一执行语句(gdb)list:查看原代码(list-n,从第n行开始查看代码。list+ 函数名:查看具体函数),简写l(gdb)原创 2022-02-08 17:09:10 · 689 阅读 · 0 评论 -
list_head
在Linux内核中,提供了一个用来创建双向循环链表的结构 list_head。虽然linux内核是用C语言写的,但是list_head的引入,使得内核数据结构也可以拥有面向对象的特性,通过使用操作list_head 的通用接口很容易实现代码的重用,有点类似于C++的继承机制(希望有机会写篇文章研究一下C语言的面向对象机制)。下面就是kernel中的list_head结构定义:struct list_head {struct list_head *next, *prev;};参考链接:https:/原创 2022-02-08 11:02:16 · 982 阅读 · 0 评论 -
.a文件链接库的使用
.a文件链接库的使用举例库是程序代码的集合,是共享程序代码的一种方式。分类一:开源库和闭源库分类二:静态库和动态库的存在形式静态库: .a 和 .framework动态库: .dylib 和 .framework两者区别:静态库:链接时,静态库会被完整地复制到可执行文件中, 被多次使用就有多份冗余拷贝 (左图所示)动态库:链接时不复制,程序运行时由系统动态加载到内存,供程序调用,系统只加载一次,多个程序共用,节省内存 。参考链接:https://blog.csdn.net/zjwen原创 2022-02-08 10:43:59 · 1345 阅读 · 0 评论 -
嵌入式开发专业术语概念汇总
SDK:概念:软件开发工具包(SDK,全称:Software Development Kit)SDK是Software Development Kit的缩写,中文意思是“软件开发工具包”。这是一个覆盖面相当广泛的名词,可以这么说:辅助开发某一类软件的相关文档、范例和工具的集合都可以叫做“SDK”。SDK是一系列文件的组合,它为软件的开发提供一个平台(它为软件开发使用各种API提供便利)API:概念:API(Application Programming Interface,应用程序编程接口)一般是原创 2022-02-08 10:37:09 · 3083 阅读 · 0 评论 -
scnprintf和snprintf的区别
int snprintf(char *buf, size_t size, const char *fmt, ...)int scnprintf(char *buf, size_t size, const char *fmt, ...)scnprintf()和snprintf()都不会越界,而且都会在最后面加一个结束符’\0’,返回值的大小都不包含最后的结束符,都会截断,不同之处是:scnprintf()返回的是已经被写入到buf的字符数,而snprintf()返回的是格式化之后得到字符的长度(即将要原创 2022-02-08 09:38:36 · 3004 阅读 · 0 评论 -
断言assert()
assert 的作用是现计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运行。1)在函数开始处检验传入参数的合法性2)每个assert只检验一个条件,因为同时检验多个条件时,如果断言失败,无法直观的判断是哪个条件失败3)不能使用改变环境的语句,因为assert只在DEBUG个生效,如果这么做,会使用程序在真正运行时遇到问题错误: assert(i++ < 100)4)assert和后面的语句原创 2022-02-08 09:24:56 · 269 阅读 · 0 评论 -
实用代码、链接、工具汇总
1、 cpu相关:查看CPU的个数https://blog.csdn.net/guowenyan001/article/details/442247592、 Linux中进程的七种状态(1)R运行状态(runing):并不意味着进程一定在运行中,也可以在运行队列里;(2)S睡眠状态(sleeping):进程在等待事件完成;(浅度睡眠,可以被唤醒)(3)D磁盘睡眠状态(Disk sleep):不可中断睡眠(深度睡眠,不可以被唤醒,通常在磁盘写入时发生)(4)T停止状态(stopped):可以通过原创 2021-12-23 14:37:49 · 755 阅读 · 0 评论 -
linux挂载相关命令
mknod我们的linux操作系统跟外部设备(如磁盘、光盘等)的通信都是通过设备文件进行的,应用程序可以打开、关闭、读写这些设备文件,从而对设备进行读写,这种操作就像读写普通的文件一样easy。linux为不同种类的设备文件提供了相同的接口,比如read(),write(),open(),close()。**所以在系统与设备通信之前,系统首先要建立一个设备文件,这个设备文件存放在/dev目录下。**其实系统默认情况下就已经生成了很多设备文件,但有时候我们需要自己手动新建一些设备文件,这个时候就会用到像mk原创 2021-12-09 20:21:35 · 236 阅读 · 0 评论 -
性能优化专题
系统级性能优化通常包括两个阶段:性能剖析(performance profiling)和代码优化。性能剖析的目标是寻找性能瓶颈,查找引发性能问题的原因及热点代码。代码优化的目标是针对具体性能问题而优化代码或编译选项,以改善软件性能。性能剖析:perf工具代码优化:cacheline对齐避免读取的数据跨越2个cacheline,结构体可以cacheline对齐,连续的数组可以尝试首地址cacheline对齐,但可能造成浪费。统计变量cacheline对齐 extern ALIGNE原创 2021-12-03 15:50:37 · 1029 阅读 · 0 评论 -
函数总结(1)
1、rcu_read_lock()背景:CPU的速度与访问内存的速度差距越来越大,而这种锁使用了原子操作指令,它需要原子地访问内存,也就说获得锁的开销与访存速度相关。RCU(Read-Copy Update),是 Linux 中比较重要的一种同步机制。顾名思义就是“读,拷贝更新”,再直白点是“随意读,但更新数据的时候,需要先复制一份副本,在副本上完成修改,再一次性地替换旧数据”。这是 Linux 内核实现的一种针对“读多写少”的共享数据的同步机制。来自 https://www.cnblogs.com/原创 2021-09-23 20:28:19 · 193 阅读 · 0 评论 -
simple_strtoull字符转换相关函数
unsigned long long simple_strtoull(const char *cp, char **endp, unsigned int base)功能:将一个字符串转换成unsigend long long型数据。返回:返回转换后数据。参数:cp指向字符串的开始,endp指向分析的有效字符串末尾的位置,base为要用的基数(进制数),base为0表示通过cp来自动判断基数,函数自动可识别的基数:‘0x’表示16进制,‘0’表示8进制,其它都认定为10进制。函数可转换成数原创 2021-09-11 15:32:44 · 254 阅读 · 0 评论 -
copy_from_user和copy_to_user
copy_from_user和copy_to_user分别是将用户空间的数据拷贝到内核空间以及将内核空间中的数据拷贝到用户空间。注意:copy_from_user还会做一些指针检查以及处理这些问题的方法。copy_from_user失败返回没有被拷贝的字节数,成功返回0.copy_from_user(void *to, const void __user *from, unsigned long n)to :将数据拷贝到内核的地址from :需要拷贝数据的地址n :拷贝数据的长度(字节)就是将原创 2021-09-11 15:18:44 · 952 阅读 · 0 评论 -
IS_ERR()
判断一个指针是否有效如果指针指向了最后一个page,那么说明实际上这不是一个有效的指针。这个指针里保存的实际上是一种错误代码。而通常很常用的方法就是先用IS_ERR()来判断是否是错误,然后如果是,那么就调用PTR_ERR()来返回这个错误代码。来自 https://blog.csdn.net/ce123_zhouwei/article/details/8450618而所谓的错误指针就是指其已经到达了最后一个page,即内核用最后一页捕捉错误。比如对于32bit的系统来说,内核空间最高地址0xffff原创 2021-09-11 14:06:45 · 842 阅读 · 0 评论 -
container_of
讲讲container_of:作用:根据一个结构体变量中的一个域成员变量的指针来获取指向整个结构体变量的指针。container_of()的作用就是通过一个结构变量中一个成员的地址找到这个结构体变量的首地址。来自 https://www.cnblogs.com/Caden-liu8888/p/7693508.htmlhttps://blog.csdn.net/s2603898260/article/details/79371024https://www.cnblogs.com/litifeng/p/原创 2021-09-11 11:16:28 · 225 阅读 · 0 评论 -
Linux文件操作
参考链接:https://blog.csdn.net/yf210yf/article/details/8997007https://www.cnblogs.com/sky-heaven/p/5549357.html原创 2021-09-11 10:49:28 · 94 阅读 · 0 评论 -
proc文件系统
proc文件系统原创 2021-09-10 09:40:27 · 146 阅读 · 0 评论 -
DMA LLC RAM DRAM的理解
DMA LLC RAM DRAM 的理解DMA (Direct Memory Access,直接存储器访问) DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DM原创 2021-09-09 22:02:18 · 1024 阅读 · 0 评论 -
ioremap、phys_to_virt和mmap
知识背景:虚拟内存系统通过将虚拟内存分割为称作虚拟页(Virtual Page,VP)大小固定的块,一般情况下,每个虚拟页的大小默认是4096字节。同样的,物理内存也被分割为物理页(Physical Page,PP),也为4096字节1、ioremapioremap宏定义在asm/io.h内:#define ioremap(cookie,size) __ioremap(cookie,size,0)__ioremap函数原型为(arm/mm/ioremap.c):void __iomem * __原创 2021-09-09 09:19:32 · 1412 阅读 · 0 评论 -
实用函数总结
1、 对于编译时报redeclaration of enumerator "…"重复定义枚举类型或结构体的问题,一般是#include头文件存在嵌套的问题,比较实用的方法是,在结构体声明的XXX.h文件首部加上#ifndef XXX ##ifndef _XXX_#define _XXX_/*实际代码内容*/#endif2、 判断一个指针是否有效IS_ERR()(一般用在创建进程、线程时做判断)struct task_struct *pstTask;pstTask = kthread_原创 2021-08-31 07:49:51 · 1851 阅读 · 0 评论 -
atomic_t原子变量操作
原子类型参数定义的典型使用场景便是多进程中共享资源的计数加减,如信号量semaphores中的资源总数便是经典的使用场景。所以atomic_t原子锁支持的便是声明了一个具有原子操作特性的整数。typedef struct{ volatile int counter; //volatile修饰符高速gcc不要对该类型数据进行优化处理,即对它的访问都是对 //内存的访问,而不是对寄存器的访问。即要读,必须重新找个寄存器载入该参数,而不是直接利用该参数 //此刻转载 2021-08-31 07:46:48 · 247 阅读 · 0 评论 -
数组越界问题总结
(1)char string[10]; // 甚至 string[9]都可以int i;char *str1=“0123456789”; // 这里实际还要添加 ‘\0’,因为 \0是C++中字符串的结尾标志,存储在字符串的结尾。比如char cha[5]表示可以放4个的数组,由于c/c++中规定字符串的结尾标志为’\0’,它虽然不计入串长,但要占内存空间strcpy(string,str1); // 相当于把 0123456789 还有 ‘\0’ 共 11个字符存入 10个中,放原创 2021-07-12 20:44:20 · 171 阅读 · 0 评论 -
创建线程kthread_create
kthread_create():创建线程。struct task_struct *kthread_create(int (*threadfn)(void *data),void *data,const char *namefmt, ...);//注意,第二个参数data用于向线程传递参数#define kthread_run(threadfn, data, namefmt, ...) \({原创 2021-07-12 20:38:49 · 1357 阅读 · 0 评论 -
git工具使用总结
创建版本库git version //查看git版本号git init //到对应目录创建仓库git config --global user.name “wzh”git config --global user.email 1328339874@qq.comgit config --list //查看当前所有配置git status //查看状态文件创建git add +文件 //add文件到stagegit add . //add当前目录所有文件到stagegit c.原创 2021-07-12 19:51:19 · 103 阅读 · 0 评论 -
MSI-X总结
PCIe有三种中断,分别为INTx中断,MSI中断,MSI-X中断,其中INTx是可选的,MSI/MSI-X是必须实现的。MSI, message signal interrupt, 是PCI设备通过写一个特定消息到特定地址,从而触发一个CPU中断。特定消息指的是PCIe总线中的Memory Write TLP, 特定地址一般存放在MSI capability中。1、 MSI-X Capabiliity结构MSI-X中断机制提出目的是扩展PCIe设备使用的中断向量个数(次要),同时解决MSI中断要求使原创 2021-07-06 14:40:26 · 1964 阅读 · 0 评论