Linux Slub分配器(二)--初始化

水平有限,描述不當之處還請之處,轉載請註明出處http://blog.csdn.net/vanbreaker/article/details/7695264

 

      和slab分配器一樣,分配器的初始化工作主要是初始化用於kmalloc的gerneral cache,Slub分配器的gerneral cache定義如下:

struct kmem_cache kmalloc_caches[SLUB_PAGE_SHIFT] __cacheline_aligned;
#define SLUB_PAGE_SHIFT (PAGE_SHIFT + 2)


SLUB_PAGE_SHIFT的值爲14,也就是說Slub分配器擁有14個gerneral cache,這14個gerneral cache的作用分別是什麼呢?在NUMA架構下,下標爲0的gc是用來存節點slab信息描述符的,也就是struct kmem_cache_node,UMA架構下,下標爲0的gc被廢棄。然後從下標爲3的gc開始,緩存的對象大小從KMALLOC_MIN_SIZE開始按2的指數冪增長。那麼下標爲1和2的gc是用來做什麼的呢?這兩個gc是用來增加緩存的粒度的,下標爲1的gc對應的緩存大小爲96,下標爲2的gc對應的緩存大小爲192。當用kmalloc分配192字節以下的對象時,size_index數組用來選擇在哪個gc中進行分配。

static s8 size_index[24] = {
	3,	/* 8 */
	4,	/* 16 */
	5,	/* 24 */
	5,	/* 32 */
	6,	/* 40 */
	6,	/* 48 */
	6,	/* 56 */
	6,	/* 64 */
	1,	/* 72 */
	1,	/* 80 */
	1,	/* 88 */
	1,	/* 96 */
	7,	/* 104 */
	7,	/* 112 */
	7,	/* 120 */
	7,	/* 128 */
	2,	/* 136 */
	2,	/* 144 */
	2,	/* 152 */
	2,	/* 160 */
	2,	/* 168 */
	2,	/* 176 */
	2,	/* 184 */
	2	/* 192 */
};


size_index數組中存儲的是gc的編號,要根據對象大小來定位gc的方法很簡單,直接用size/8 - 1即可。如要分配大小爲48的對象,那麼48/8 - 1=5,而size_index數組中下標5對應的偏移爲6,在kmalloc_caches數組中,下標6對應的gc的對象大小爲64,因此就找到了一個合理的gc,當然,以上的討論都是基於KMALLOC_MIN_SIZES爲8的情況下的。那麼可想而知,gc的初始化工作主要就是創建gc以及建立size_index數組到gc之間的映射。

 

void __init kmem_cache_init(void)
{
	int i;
	int caches = 0;

	init_alloc_cpu();

#ifdef CONFIG_NUMA 
	/*
	 * Must first have the slab cache available for the allocations of the
	 * struct kmem_cache_node's. There is special bootstrap code in
	 * kmem_cache_open for slab_state == DOWN.
	 */
	 /*創建kmalloc_caches的第0個緩存用來存儲struct kmem_cache_node*/
	create_kmalloc_cache(&kmalloc_caches[0], "kmem_cache_node",
		sizeof(struct kmem_cache_node), GFP_NOWAIT);
	kmalloc_caches[0].refcount = -1;
	caches++;

	hotplug_memory_notifier(slab_memory_callback, SLAB_CALLBACK_PRI);
#endif

	/* Able to allocate the per node structures */
	slab_state = PARTIAL;//將初始化進度改爲PARTIAL,表示已經可以分配struct kmem_cache_node

	/* Caches that are not of the two-to-the-power-of size */
	/*如果kmalloc的最小對象大小不大於32則創建第1個緩存,對象大小爲96字節*/
	if (KMALLOC_MIN_SIZE <= 32) {
		create_kmalloc_cache(&kmalloc_caches[1],
				"kmalloc-96", 96, GFP_NOWAIT);
		caches++;
	}
	/*如果kmalloc的最小對象大小不大於64則創建第2個緩存,對象大小爲192字節*/
	if (KMALLOC_MIN_SIZE <= 64) {
		create_kmalloc_cache(&kmalloc_caches[2],
				"kmalloc-192", 192, GFP_NOWAIT);
		caches++;
	}

	/*創建後續的普通緩存*/
	for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++) {
		create_kmalloc_cache(&kmalloc_caches[i],
			"kmalloc", 1 << i, GFP_NOWAIT);
		caches++;
	}


	/*
	 * Patch up the size_index table if we have strange large alignment
	 * requirements for the kmalloc array. This is only the case for
	 * MIPS it seems. The standard arches will not generate any code here.
	 *
	 * Largest permitted alignment is 256 bytes due to the way we
	 * handle the index determination for the smaller caches.
	 *
	 * Make sure that nothing crazy happens if someone starts tinkering
	 * around with ARCH_KMALLOC_MINALIGN
	 */
	 /*這裏做一些必要的檢查,保證kmalloc允許的最小對象的大小不能大於256
	   並且該值必須是2的整數冪*/
	BUILD_BUG_ON(KMALLOC_MIN_SIZE > 256 ||
		(KMALLOC_MIN_SIZE & (KMALLOC_MIN_SIZE - 1)));

	/*對於大小在8字節與KMALLOC_MIN_SIZE之間的對象,將其在size_index數組中的索引
	  設置爲KMALLOC_SHIFT_LOW,也就是log(KMALLOC_MIN_SIZE),這些對象都將以KMALLOC_MIN_SIZE
	  大小進行分配*/
	for (i = 8; i < KMALLOC_MIN_SIZE; i += 8) {
		int elem = size_index_elem(i);
		if (elem >= ARRAY_SIZE(size_index))
			break;
		size_index[elem] = KMALLOC_SHIFT_LOW;
	}

	/*如果KMALLOC_MIN_SIZE爲64,則棄用96字節的緩存*/
	if (KMALLOC_MIN_SIZE == 64) {
		/*
		 * The 96 byte size cache is not used if the alignment
		 * is 64 byte.
		 */
		 /*將72字節與96字節之間的對象子size_index數組中的索引設爲7,
		   這些對象將以128字節進行分配*/
		for (i = 64 + 8; i <= 96; i += 8)
			size_index[size_index_elem(i)] = 7;
	} else if (KMALLOC_MIN_SIZE == 128) {/*如果最小對象大小爲128字節,則棄用192字節的緩存*/
		/*
		 * The 192 byte sized cache is not used if the alignment
		 * is 128 byte. Redirect kmalloc to use the 256 byte cache
		 * instead.
		 */
		for (i = 128 + 8; i <= 192; i += 8)
			size_index[size_index_elem(i)] = 8;
	}

	slab_state = UP;//更新初始化進度

	/* Provide the correct kmalloc names now that the caches are up */
	for (i = KMALLOC_SHIFT_LOW; i < SLUB_PAGE_SHIFT; i++)
		kmalloc_caches[i]. name =
			kasprintf(GFP_NOWAIT, "kmalloc-%d", 1 << i);

#ifdef CONFIG_SMP
	register_cpu_notifier(&slab_notifier);
        /*計算kmem_cache的大小*/
	kmem_size = offsetof(struct kmem_cache, cpu_slab) +
				nr_cpu_ids * sizeof(struct kmem_cache_cpu *);
#else
	kmem_size = sizeof(struct kmem_cache);
#endif

	printk(KERN_INFO
		"SLUB: Genslabs=%d, HWalign=%d, Order=%d-%d, MinObjects=%d,"
		" CPUs=%d, Nodes=%d\n",
		caches, cache_line_size(),
		slub_min_order, slub_max_order, slub_min_objects,
		nr_cpu_ids, nr_node_ids);
}


 


 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章