kernel-常见参数或宏

get_online_cpus

get_online_cpus();
get_online_mems();

kstrdup_const 分配内存

    cache_name = kstrdup_const(name, GFP_KERNEL);
if (!cache_name) {
err = -ENOMEM;
goto out_unlock;
}

barrier

http://www.wowotech.net/kernel_synchronization/memory-barrier.html

编译器将符合人类思考的逻辑(c代码)翻译成了符合CPU运算规则的汇编指令,编译器了解底层CPU的思维模式,因此,它可以在将c翻译成汇编的时候进行优化(例如内存访问指令的重新排序),让产出的汇编指令在CPU上运行的时候更快。然而,这种优化产出的结果未必符合程序员原始的逻辑,因此,作为程序员,作为c程序员,必须有能力了解编译器的行为,并在通过内嵌在c代码中的memory barrier来指导编译器的优化行为(这种memory barrier又叫做优化屏障,Optimization barrier),让编译器产出即高效,又逻辑正确的代码。

CPU的核心思想就是取指执行,对于in-order的单核CPU,并且没有cache(这种CPU在现实世界中还存在吗?),汇编指令的取指和执行是严格按照顺序进行的,也就是说,汇编指令就是所见即所得的,汇编指令的逻辑被严格的被CPU执行。然而,随着计算机系统越来越复杂(多核、cache、superscalar、out-of-order),使用汇编指令这样贴近处理器的语言也无法保证其被CPU执行的结果的一致性,从而需要程序员(看,人还是最不可以替代的)告知CPU如何保证逻辑正确。

综上所述,memory barrier是一种保证内存访问顺序的一种方法,让系统中的HW block(各个cpu、DMA controler、device等)对内存有一致性的视角。

linux kernel中的定义和我们的想像一样,除了barrier这个优化屏障。barrier就象是c代码中的一个栅栏,将代码逻辑分成两段,barrier之前的代码和barrier之后的代码在经过编译器编译后顺序不能乱掉。也就是说,barrier之后的c代码对应的汇编,不能跑到barrier之前去,反之亦然。之所以这么做是因为在我们这个场景中,如果编译为了榨取CPU的performace而对汇编指令进行重排,那么临界区的代码就有可能位于preempt_count_inc之外,从而起不到保护作用。


preempt_disable

preempt_disable()

临界区

preempt_enable

cmpxchg

https://blog.csdn.net/zdy0_2004/article/details/48013829

cmpxchg(void *ptr, unsigned long old, unsigned long new);

函数完成的功能是:将old和ptr指向的内容比较,如果相等,则将new写入到ptr中,返回old,如果不相等,则返回ptr指向的内容。

1. cmpxchg(*ptr,old,new)

   如果*ptr==old,  则  把new赋值给*A ,并返回old

   如果*ptr!=old,   则 返回*ptr 

2. cmpxchg_double(p1, p2, o1, o2, n1, n2) 

类似于下面的C语言   

if(p1==o1 && p2==o2){
p1 = n1;
p2 = n2;
return 1;
}else
return 0; 由于是原子操作,避免了使用锁. 3. this_cpu_cmpxchg_double(pcp1, pcp2, oval1, oval2, nval1, nval2) 类似于cmpxchg_double,能够避免禁止中断.

kmem_cache_zalloc

kmem_cache_zalloc

    struct kmem_cache *s;
int err; err = -ENOMEM;
s = kmem_cache_zalloc(kmem_cache, GFP_KERNEL);
if (!s)
goto out; s->name = name;
s->object_size = object_size;
s->size = size;
s->align = align;
s->ctor = ctor;

ilog2

set_min_partial(s, ilog2(s->size) / 2);

for_each_possible_cpu 遍历cpu

static void init_kmem_cache_cpus(struct kmem_cache *s)
{
int cpu; for_each_possible_cpu(cpu)
per_cpu_ptr(s->cpu_slab, cpu)->tid = init_tid(cpu);
}

set_cpu_partial


s->size >= PAGE_SIZE 时: s->cpu_partial = 2; 不懂! static void set_cpu_partial(struct kmem_cache *s)
{
#ifdef CONFIG_SLUB_CPU_PARTIAL
if (!kmem_cache_has_cpu_partial(s))
s->cpu_partial = 0;
else if (s->size >= PAGE_SIZE)
s->cpu_partial = 2;
else if (s->size >= 1024)
s->cpu_partial = 6;
else if (s->size >= 256)
s->cpu_partial = 13;
else
s->cpu_partial = 30;
#endif
}

this_cpu_read

https://lwn.net/Articles/366994/

this_cpu_read: 读cpu的数据
raw_cpu_ptr
IS_ENABLED do {
tid = this_cpu_read(s->cpu_slab->tid);
c = raw_cpu_ptr(s->cpu_slab);
} while (IS_ENABLED(CONFIG_PREEMPT) &&
unlikely(tid != READ_ONCE(c->tid)));

prefetch:

https://www.gnu.org/software/gcc/projects/prefetch.html/

static void prefetch_freepointer(const struct kmem_cache *s, void *object)
{
if (object)
prefetch(freelist_dereference(s, object + s->offset));
}

ALIGN

/* @a is a power of 2 value */
#define ALIGN(x, a) __ALIGN_KERNEL((x), (a))
#define __ALIGN_KERNEL(x, a) __ALIGN_KERNEL_MASK(x, (typeof(x))(a) - 1)
#define __ALIGN_KERNEL_MASK(x, mask) (((x) + (mask)) & ~(mask)) #define ALIGN_DOWN(x, a) __ALIGN_KERNEL((x) - ((a) - 1), (a))
#define __ALIGN_MASK(x, mask) __ALIGN_KERNEL_MASK((x), (mask))
#define PTR_ALIGN(p, a) ((typeof(p))ALIGN((unsigned long)(p), (a)))
#define IS_ALIGNED(x, a) (((x) & ((typeof(x))(a) - 1)) == 0) size = ALIGN(size, s->align); #define ALIGN(x,a) (((x)+(a)-1)&~(a-1))
就是以a為上界對齊的意思。舉個例子4k頁面邊界的例子,即:
a=4096, x = 3888,那麼以上界對齊為4096。
x = 4096, 结果為4096.
x = 4222, 结果為8192. 另外還有一種以下界對齊的方式 #define ALIGN(x,a) ((x)&~(a-1))
a=4096, x = 3888,结果為0.
x = 4095,结果為0
x = 4096,结果為4096
x = 4222,结果為4096. 对于正整数2^n(n>1)来说,存在这样的特性,如果整数X是2^n的整数倍,则X的二进制形式的低n位为0, 如果X不是2^n的整数倍,则X与(~(2^n-1))进行与运算可以得到一个与X相近的是2^n整数倍的正整数。这个特性经常用于内存分配时对齐。如果是上对齐,则需要先加上2^n-1,再进行上述运算。 在linux2.6.30.4中,在include/Linux/kernel.h文件中,ALIGN宏的定义如下: #define ALIGN(x,a) __ALIGN_MASK(x,(typeof(x))(a)-1)
#define __ALIGN_MASK(x,mask) (((x)+(mask))&~(mask)) 上面代码中,typeof(x)表示取x的类型,如果x是int,则typeof(x)为int。(typeof(x))(a)-1,表明把a转化为x的类型,并减1,作为对齐掩码。不考虑类型,上述代码可以简化为如下: #define ALIGN(x,a) (((x)+(a)-1)&~(a-1)) 上面的计算方法在linux等代码中也常常可以看到,下面给出几个例子:
(1) 当分配地址addr时, 要将该地址以size为倍数对齐, 而且要得到是比addr大的值, 则使用_ALIGN宏:
#define _ALIGN(addr,size)(((addr)+(size)-1)&(~((size)-1))) (2) 与页面对齐相关的宏
#define PAGE_SIZE 4096
#definePAGE_MASK (~(PAGE_SIZE-1))
#define PAGE_ALIGN(addr) -(((addr)+PAGE_SIZE-1)& PAGE_MASK) (3) 与skb分配时对齐相关的宏
#define SKB_DATA_ALIGN(X) (((X) + (SMP_CACHE_BYTES -1)) & ~(SMP_CACHE_BYTES - 1))

cmpxchg



in_interrupt()

in_interrupt()是判断当前进程是否处于中断上下文,这个中断上下文包括底半部和硬件中断处理过程

compound_head(page);

 static inline struct page *virt_to_head_page(const void *x)
{
struct page *page = virt_to_page(x); return compound_head(page);
}
  • 复合页(Compound Page)就是将物理上连续的两个或多个页看成一个

    独立的大页,它可以用来创建hugetlbfs中使用的大页(hugepage),

    也可以用来创建透明大页(transparent huge page)子系统。但是

    它不能用在页缓存(page cache)中,这是因为页缓存中管理的都是

    单个页。

  • 分配一个复合页的方式是:使用alloc_pages函数,参数order至少为1,

    且设置__GFP_COMP标记。因为根据复合页的定义,它通常包括2个或多

    个连续的物理内存页,这是由它的实现决定的,因而order参数不可能

    为0。

  • 通常调用alloc_pages的内存分配方式如下:

p = alloc_pages(GFP_KERNEL, 2);

```

但是这种方式和创建一个复合页有什么不同呢?不同点就是在创建复合
页的时候会创建与这个复合页相关的元数据(metadata)。
  • 表示复合页的元数据都存在于Page结构体中,Page页中的flag标记用来

    识别复合页。在复合页中,打头的第一个普通页成为“head page”,用

    PG_head标记,而后面的所有页被称为“tail pages”,用PG_tail标记。

    在64位系统中,可以有多余的标记来表示复合页的页头和页尾;但是在

    32位系统中却没有那么多的标记,因此采用了一种复用其他标记的方案,

    即将复合页中的所有页都用PG_compound标记,然后,对于尾页同时也

    使用PG_reclaim标记,这是因为PG_reclaim只有在页缓存中会用到,而

    复合页根本就不会在页缓存中使用。

  • 可以使用PageCompound函数来检测一个页是否是复合页,另外函数PageHead

    和函数PageTail用来检测一个页是否是页头或者页尾。在每个尾页的page

    结构体中都包含一个指向头页的指针 - first_page,可以使用compound_head

    函数获得。

  • 那么当一个复合页不再被系统使用时,我们如何知道该复合页包含多少

    个普通页,又如何知道该复合页的析构函数(destructor)存在哪里呢?

    首先,人们可能会认为这些信息存在于头页的page结构体中,但是很不

    幸,在这个结构体中已经没有可用的空间了。因此,这些信息全部存储

    在第一个尾页的lru字段中,将该复合页的大小(order)首先强制转换

    为指针类型,然后存储在lru.prev中,将析构函数存储在lru.next中。

    这里就解释了为什么复合页必须至少是两个页。

  • 在内核中生命了两个复合页的析构函数,默认情况下会调用free_compound_page

    来将所有的页返回给系统的页框分配器,而hugetlbfs子系统会调用free_huge_page

    来做一些统计并释放。

  • 使用复合页的最经典的一个例子就是THP(transparent huge page),

    另外一些驱动使用复合页来方便缓存的管理。

  • https://lwn.net/Articles/619514/

_RET_IP_与_THIS_IP_

在 linux-3.4\include\linux\kernel.h中有这两个宏的定义:

This function returns the return address of the current function, or of one of its callers. The level argument is number of frames to scan up the call stack. A value of 0 yields the return address of the current function, a value of 1 yields the return address of the caller of the current function, and so forth.

#define _RET_IP_         (unsigned long)__builtin_return_address(0)

#define _THIS_IP_  ({ __label__ __here; __here: (unsigned long)&&__here; })

可看出 _RET_IP_就是使用 __builtin_return_address来实现的,内核中也有例子:

linux-3.4\mm\memblock.c中:

int __init_memblock memblock_free(phys_addr_t base, phys_addr_t size)

{
memblock_dbg(" memblock_free: [%#016llx-%#016llx] %pF\n", (unsigned long long)base, (unsigned long long)base + size, (void *)_RET_IP_); return __memblock_remove(&memblock.reserved, base, size);
}

调试内核的时候,想打印当前进程的地址可使用 _THIS_IP_

ACCESS_ONCE()/WRITE_ONCE()/READ_ONCE()

http://quant67.com/post/linux/access_once.html

SLUB

struct kmem_cache_node {
spinlock_t list_lock; #ifdef CONFIG_SLUB
// 一个kmem_cache_node n中,所有partial的数量:add_partial()
unsigned long nr_partial;
struct list_head partial;
#ifdef CONFIG_SLUB_DEBUG
// 一个kmem_cache_node n中slab总数量: node_nr_slabs(n);
atomic_long_t nr_slabs;
// 一个kmem_cache_node n中object总数量: node_nr_objs(n);
atomic_long_t total_objects;
struct list_head full;
#endif
#endif };
struct kmem_cache_order_objects oo
int order = oo_order(oo);

kernel-常见参数或宏的更多相关文章

  1. 引用 U-boot给kernel传参数和kernel读取参数—struct tag

    引用 清风徐徐 的 U-boot给kernel传参数和kernel读取参数—struct tag U-boot会给Linux Kernel传递很多参数,如:串口,RAM,videofb等.而Linux ...

  2. gcc的-D和-U参数:宏的设置与取消 _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_"

    _CCFLAGS=" -w -enable-threads=posix -DLINUX -D_REENTRANT -DWORKONGN -Dlinux -D_GN_DETAIL_SDR_&q ...

  3. gcc的-D和-U参数:宏的设置与取消

    http://blog.chinaunix.net/uid-7213338-id-2658068.html  gcc的-D和-U参数:宏的设置与取消 2006-10-08 22:59:06 分类: L ...

  4. C语言可变参数在宏定义中的应用

    在C语言的标准库中,printf.scanf.sscanf.sprintf.sscanf这些标准库的输入输出函数,参数都是可变的.在调试程序时,我们可能希望定义一个参数可变的输出函数来记录日志,那么用 ...

  5. 编译预处理 -- 带参数的宏定义--【sky原创】

    原文:编译预处理 -- 带参数的宏定义--[sky原创] 如有转载请注明出处   编译预处理  --  带参数的宏定义 前面为输出文件,后面为输入文件 gcc -E -o test.i test.c ...

  6. Java虚拟机--------JVM常见参数

    JVM 调优常见参数 Java1.7的jvm参数查看一下官方网站. http://docs.oracle.com/javase/7/docs/technotes/tools/windows/java. ...

  7. 性能测试三十六:内存溢出和JVM常见参数及JVM参数调优

    堆内存溢出: 此种溢出,加内存只能缓解问题,不能根除问题,需优化代码堆内存中存在大量对象,这些对象都有被引用,当所有对象占用空间达到堆内存的最大值,就会出现内存溢出OutOfMemory:Java h ...

  8. C语言中带参数的宏

    带参数的宏定义有如下的格式: [#define 指令----带参数的宏] #define 标识符(x1,x2,……,xn) 其中  x1,x2,……xn是标志符(宏的参数) 注意:在宏的名字和括号之间 ...

  9. Jmeter,常见参数 vars、prev、ctx 、props 类的api--beanshell

    http://www.cnblogs.com/fnng/p/5827577.html---------jmeter 性能测试 jmeter常见参数 vars.prev.ctx .props 类的api ...

随机推荐

  1. android实现跑马灯效果(能够实现两个以上跑马灯)

    本文用了继承自TextView的MarqueeTextView来实现跑马灯效果.原因是,跑马灯效果是须要TextView拥有焦点才会跑动的.而有时候TextView获得焦点会有点耗时,造成要等待一段时 ...

  2. 配置hadoop集群一

    花了1天时间最终把环境搭建好了.整理了一下,希望对想学习hadoop的有所帮助. 资料下载:http://pan.baidu.com/s/1kTupgkn 包括了linux虚拟机.jdk, hadoo ...

  3. go语言笔记——go环境变量goroot是安装了路径和gopath是三方包路径

    Go 环境变量 Go 开发环境依赖于一些操作系统环境变量,你最好在安装 Go 之间就已经设置好他们.如果你使用的是 Windows 的话,你完全不用进行手动设置,Go 将被默认安装在目录 c:/go  ...

  4. 浅谈JVM内存模型

    JAVA虚拟机在执行JAVA程序的时候,会把它管理的内存分成若干不同的数据区域,每个区域都有各自的用途.目前大致把JVM内存模型划分为五个区域:程序计数器,虚拟机栈,本地方法栈,堆和方法区. 程序计数 ...

  5. bzoj1018

    线段树分治+并查集 线段树本身就是分治结构,碰见这种带删除修改的题目是再合适不过的,我们对于每段修改区间在线段树上打标记,每次路过就进行修改,叶子结点表及答案,先把所有修改在线段树上标记,然后dfs就 ...

  6. 47. Ext.form.Field.prototype.msgTarget

    转自:https://blog.csdn.net/a1542aa/article/details/24295791 ExtJS.form中msgTarget Ext表单提示方式:msgTarget:有 ...

  7. java网络编程UDP

    图片来自网络 [发送端] import java.io.IOException; import java.net.DatagramPacket; import java.net.DatagramSoc ...

  8. poj1006生理周期(中国剩余定理)

    生理周期 Time Limit: 1000MS   Memory Limit: 10000K Total Submissions: 139224   Accepted: 44687 Descripti ...

  9. [Apple开发者帐户帮助]八、管理档案(2)创建临时配置文件(iOS,tvOS,watchOS)

    创建临时配置文件以在设备上运行您的应用程序而无需Xcode.在开始之前,您需要一个App ID,一个分发证书和多个注册设备. 有关完整的临时配置文件工作流程,请转到Xcode帮助中的分发到已注册设备( ...

  10. [转]Oracle Client 11g安裝經驗

    本文转自:http://www.dotblogs.com.tw/shadow/archive/2011/11/08/54759.aspx 開發環境:本機(Win XP)的ASP.net 4 WebSi ...