[RFC] buddy optimizations.

From: Manfred Spraul (manfreds@colorfullife.com)
Date: Wed May 24 2000 - 12:00:52 EST


I'm still testing our memory allocators, and I added a per-cpu linked
list for order==0 to page_alloc:

back-to-back __get_free_pages()+free_pages() are 48% faster [AMD K6/200
with a SMP kernel]
from 747 to 388. [hot caches]

But I really don't know how long these lists should be:
* if they are too long, memory fragmentation increases.
* if they are too short, we access the global buddy too often.

Any ideas how the tests such a patch?

--
	Manfred

// $Header$ // Kernel Version: // VERSION = 2 // PATCHLEVEL = 3 // SUBLEVEL = 99 // EXTRAVERSION = -pre8 --- 2.3/include/linux/mmzone.h Thu Apr 27 11:27:24 2000 +++ build-2.3/include/linux/mmzone.h Wed May 24 16:07:32 2000 @@ -20,6 +20,11 @@ } free_area_t; struct pglist_data; +struct zone_cpu_cache { + struct page* pg; + unsigned int count; +}; + typedef struct zone_struct { /* @@ -36,6 +41,12 @@ * free areas of different sizes */ free_area_t free_area[MAX_ORDER]; + + /* + * per-cpu cache, only order 0 + */ + unsigned long p_limit; + struct zone_cpu_cache p_cache[NR_CPUS]; /* * rarely used fields: --- 2.3/mm/page_alloc.c Sat May 13 11:21:00 2000 +++ build-2.3/mm/page_alloc.c Wed May 24 17:08:03 2000 @@ -96,6 +96,23 @@ zone = page->zone; + if(order==0 && + zone->free_pages > zone->pages_low) { + struct zone_cpu_cache* pc = &zone->p_cache[smp_processor_id()]; + local_irq_save(flags); + if(pc->count < zone->p_limit) { + page->list.next = (struct list_head*)pc->pg; + pc->pg = page; + pc->count++; + local_irq_restore(flags); + return; + } + /* FIXME: benchmark this: + * perhaps merge the local_irq_restore with the + * spin_lock_irqsave() below? + */ + local_irq_restore(flags); + } mask = (~0UL) << order; base = mem_map + zone->offset; page_idx = page - base; @@ -178,7 +195,21 @@ unsigned long flags; struct page *page; - spin_lock_irqsave(&zone->lock, flags); + if(order==0) { + struct zone_cpu_cache* pc = &zone->p_cache[smp_processor_id()]; + local_irq_save(flags); + if(pc->count != 0) { + page = pc->pg; + pc->pg = (struct page*)page->list.next; + pc->count--; + local_irq_restore(flags); + set_page_count(page, 1); + return page; + } + } else { + local_irq_save(flags); + } + spin_lock(&zone->lock); do { head = &area->free_list; curr = memlist_next(head); @@ -232,6 +263,7 @@ if (!z->size) BUG(); + /* Are we supposed to free memory? Don't make it worse.. */ if (!z->zone_wake_kswapd) { struct page *page = rmqueue(z, order); @@ -561,6 +593,17 @@ zone->zone_mem_map = mem_map + offset; zone->zone_start_mapnr = offset; zone->zone_start_paddr = zone_start_paddr; + memset(zone->p_cache,0,sizeof(zone->p_cache)); + if (size <= 2048) + zone->p_limit = 0; + else if (size <= 8192) + zone->p_limit = 2; + else if (size <= 32768) + zone->p_limit = 4; + else if (size <= 131072) + zone->p_limit = 8; + else + zone->p_limit = 16; for (i = 0; i < size; i++) { struct page *page = mem_map + offset + i;

- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.rutgers.edu Please read the FAQ at http://www.tux.org/lkml/



This archive was generated by hypermail 2b29 : Wed May 31 2000 - 21:00:12 EST