* Even though our current heap is a temporary solution, the heap size depends

now on the amount of memory installed in the system. Ie. if you have only
  128 MB the kernel heap will be only half in size.
* Minor cleanup in vm_page.c, renamed some variables to match our style guide.


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@16838 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler 2006-03-19 15:02:21 +00:00
parent 93c49610b5
commit db823da57e
5 changed files with 108 additions and 91 deletions

View File

@ -24,7 +24,7 @@ extern "C" {
void *memalign(size_t alignment, size_t size); void *memalign(size_t alignment, size_t size);
status_t heap_init(addr_t heapBase); status_t heap_init(addr_t heapBase, size_t heapSize);
status_t heap_init_post_sem(struct kernel_args *args); status_t heap_init_post_sem(struct kernel_args *args);
status_t heap_init_post_thread(struct kernel_args *args); status_t heap_init_post_thread(struct kernel_args *args);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -19,6 +19,7 @@ struct kernel_args;
extern "C" { extern "C" {
#endif #endif
void vm_page_init_num_pages(kernel_args *args);
status_t vm_page_init(struct kernel_args *args); status_t vm_page_init(struct kernel_args *args);
status_t vm_page_init_post_area(struct kernel_args *args); status_t vm_page_init_post_area(struct kernel_args *args);
status_t vm_page_init_post_thread(struct kernel_args *args); status_t vm_page_init_post_thread(struct kernel_args *args);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Copyright 2001, Travis Geiselbrecht. All rights reserved. * Copyright 2001, Travis Geiselbrecht. All rights reserved.
@ -315,12 +315,12 @@ dump_bin_list(int argc, char **argv)
*/ */
status_t status_t
heap_init(addr_t heapBase) heap_init(addr_t heapBase, size_t heapSize)
{ {
const unsigned int page_entries = B_PAGE_SIZE / sizeof(struct heap_page); const unsigned int page_entries = B_PAGE_SIZE / sizeof(struct heap_page);
// set some global pointers // set some global pointers
heap_alloc_table = (struct heap_page *)heapBase; heap_alloc_table = (struct heap_page *)heapBase;
heap_size = ((uint64)HEAP_SIZE * page_entries / (page_entries + 1)) & ~(B_PAGE_SIZE-1); heap_size = ((uint64)heapSize * page_entries / (page_entries + 1)) & ~(B_PAGE_SIZE-1);
heap_base = (unsigned int)heap_alloc_table + PAGE_ALIGN(heap_size / page_entries); heap_base = (unsigned int)heap_alloc_table + PAGE_ALIGN(heap_size / page_entries);
heap_base_ptr = heap_base; heap_base_ptr = heap_base;
TRACE(("heap_alloc_table = %p, heap_base = 0x%lx, heap_size = 0x%lx\n", TRACE(("heap_alloc_table = %p, heap_base = 0x%lx, heap_size = 0x%lx\n",

View File

@ -2228,7 +2228,6 @@ status_t
vm_init(kernel_args *args) vm_init(kernel_args *args)
{ {
struct preloaded_image *image; struct preloaded_image *image;
addr_t heap_base;
void *address; void *address;
status_t err = 0; status_t err = 0;
uint32 i; uint32 i;
@ -2242,14 +2241,24 @@ vm_init(kernel_args *args)
sAreaHashLock = -1; sAreaHashLock = -1;
sAvailableMemoryLock.sem = -1; sAvailableMemoryLock.sem = -1;
vm_page_init_num_pages(args);
sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE;
// reduce the heap size if we have not so much RAM
size_t heapSize = HEAP_SIZE;
if (sAvailableMemory < 100 * 1024 * 1024)
heapSize /= 4;
else if (sAvailableMemory < 200 * 1024 * 1024)
heapSize /= 2;
// map in the new heap and initialize it // map in the new heap and initialize it
heap_base = vm_alloc_from_kernel_args(args, HEAP_SIZE, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); addr_t heapBase = vm_alloc_from_kernel_args(args, heapSize,
TRACE(("heap at 0x%lx\n", heap_base)); B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
heap_init(heap_base); TRACE(("heap at 0x%lx\n", heapBase));
heap_init(heapBase, heapSize);
// initialize the free page list and physical page mapper // initialize the free page list and physical page mapper
vm_page_init(args); vm_page_init(args);
sAvailableMemory = vm_page_num_pages() * B_PAGE_SIZE;
// initialize the hash table that stores the pages mapped to caches // initialize the hash table that stores the pages mapped to caches
vm_cache_init(args); vm_cache_init(args);
@ -2272,8 +2281,8 @@ vm_init(kernel_args *args)
// allocate areas to represent stuff that already exists // allocate areas to represent stuff that already exists
address = (void *)ROUNDOWN(heap_base, B_PAGE_SIZE); address = (void *)ROUNDOWN(heapBase, B_PAGE_SIZE);
create_area("kernel heap", &address, B_EXACT_ADDRESS, HEAP_SIZE, create_area("kernel heap", &address, B_EXACT_ADDRESS, heapSize,
B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
allocate_kernel_args(args); allocate_kernel_args(args);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2002-2005, Axel Dörfler, axeld@pinc-software.de. * Copyright 2002-2006, Axel Dörfler, axeld@pinc-software.de.
* Distributed under the terms of the MIT License. * Distributed under the terms of the MIT License.
* *
* Copyright 2001-2002, Travis Geiselbrecht. All rights reserved. * Copyright 2001-2002, Travis Geiselbrecht. All rights reserved.
@ -46,11 +46,11 @@ static page_queue page_clear_queue;
static page_queue page_modified_queue; static page_queue page_modified_queue;
static page_queue page_active_queue; static page_queue page_active_queue;
static vm_page *all_pages; static vm_page *sPages;
static addr_t physical_page_offset; static addr_t sPhysicalPageOffset;
static unsigned int num_pages; static size_t sNumPages;
static spinlock page_lock; static spinlock sPageLock;
static sem_id modified_pages_available; static sem_id modified_pages_available;
@ -178,7 +178,7 @@ vm_page_write_modified(vm_cache *cache)
vm_area *area; vm_area *area;
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
if (page->state == PAGE_STATE_MODIFIED) { if (page->state == PAGE_STATE_MODIFIED) {
remove_page_from_queue(&page_modified_queue, page); remove_page_from_queue(&page_modified_queue, page);
@ -186,7 +186,7 @@ vm_page_write_modified(vm_cache *cache)
gotPage = true; gotPage = true;
} }
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
// We may have a modified page - however, while we're writing it back, the page // We may have a modified page - however, while we're writing it back, the page
@ -238,7 +238,7 @@ vm_page_write_modified(vm_cache *cache)
// put it into the active queue // put it into the active queue
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
if (page->ref_count > 0) if (page->ref_count > 0)
page->state = PAGE_STATE_ACTIVE; page->state = PAGE_STATE_ACTIVE;
@ -247,7 +247,7 @@ vm_page_write_modified(vm_cache *cache)
enqueue_page(&page_active_queue, page); enqueue_page(&page_active_queue, page);
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
} }
} else { } else {
@ -277,11 +277,11 @@ static int pageout_daemon()
dprintf("here\n"); dprintf("here\n");
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
page = dequeue_page(&page_modified_queue); page = dequeue_page(&page_modified_queue);
page->state = PAGE_STATE_BUSY; page->state = PAGE_STATE_BUSY;
vm_cache_acquire_ref(page->cache_ref, true); vm_cache_acquire_ref(page->cache_ref, true);
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
dprintf("got page %p\n", page); dprintf("got page %p\n", page);
@ -290,10 +290,10 @@ static int pageout_daemon()
// unless we're in the trimming cycle, dont write out pages // unless we're in the trimming cycle, dont write out pages
// that back anonymous stores // that back anonymous stores
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
enqueue_page(&page_modified_queue, page); enqueue_page(&page_modified_queue, page);
page->state = PAGE_STATE_MODIFIED; page->state = PAGE_STATE_MODIFIED;
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
vm_cache_release_ref(page->cache_ref); vm_cache_release_ref(page->cache_ref);
continue; continue;
@ -323,14 +323,14 @@ static int pageout_daemon()
vm_put_physical_page((addr_t)vecs->vec[0].iov_base); vm_put_physical_page((addr_t)vecs->vec[0].iov_base);
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
if(page->ref_count > 0) { if(page->ref_count > 0) {
page->state = PAGE_STATE_ACTIVE; page->state = PAGE_STATE_ACTIVE;
} else { } else {
page->state = PAGE_STATE_INACTIVE; page->state = PAGE_STATE_INACTIVE;
} }
enqueue_page(&page_active_queue, page); enqueue_page(&page_active_queue, page);
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
vm_cache_release_ref(page->cache_ref); vm_cache_release_ref(page->cache_ref);
@ -339,14 +339,35 @@ static int pageout_daemon()
#endif #endif
status_t void
vm_page_init(kernel_args *ka) vm_page_init_num_pages(kernel_args *args)
{ {
unsigned int i; uint32 i;
// calculate the size of memory by looking at the physical_memory_range array
addr_t physicalPagesEnd = 0;
sPhysicalPageOffset = args->physical_memory_range[0].start / B_PAGE_SIZE;
for (i = 0; i < args->num_physical_memory_ranges; i++) {
physicalPagesEnd = (args->physical_memory_range[i].start
+ args->physical_memory_range[i].size) / B_PAGE_SIZE;
}
TRACE(("first phys page = 0x%lx, end 0x%x\n", sPhysicalPageOffset,
physicalPagesEnd));
sNumPages = physicalPagesEnd - sPhysicalPageOffset;
}
status_t
vm_page_init(kernel_args *args)
{
uint32 i;
TRACE(("vm_page_init: entry\n")); TRACE(("vm_page_init: entry\n"));
page_lock = 0; sPageLock = 0;
// initialize queues // initialize queues
page_free_queue.head = NULL; page_free_queue.head = NULL;
@ -362,42 +383,28 @@ vm_page_init(kernel_args *ka)
page_active_queue.tail = NULL; page_active_queue.tail = NULL;
page_active_queue.count = 0; page_active_queue.count = 0;
// calculate the size of memory by looking at the physical_memory_range array
{
unsigned int physicalPagesEnd = 0;
physical_page_offset = ka->physical_memory_range[0].start / B_PAGE_SIZE;
for (i = 0; i<ka->num_physical_memory_ranges; i++) {
physicalPagesEnd = (ka->physical_memory_range[i].start
+ ka->physical_memory_range[i].size) / B_PAGE_SIZE;
}
TRACE(("first phys page = 0x%lx, end 0x%x\n", physical_page_offset,
physicalPagesEnd));
num_pages = physicalPagesEnd - physical_page_offset;
}
// map in the new free page table // map in the new free page table
all_pages = (vm_page *)vm_alloc_from_kernel_args(ka, num_pages * sizeof(vm_page), sPages = (vm_page *)vm_alloc_from_kernel_args(args, sNumPages * sizeof(vm_page),
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
TRACE(("vm_init: putting free_page_table @ %p, # ents %d (size 0x%x)\n", TRACE(("vm_init: putting free_page_table @ %p, # ents %d (size 0x%x)\n",
all_pages, num_pages, (unsigned int)(num_pages * sizeof(vm_page)))); sPages, sNumPages, (unsigned int)(sNumPages * sizeof(vm_page))));
// initialize the free page table // initialize the free page table
for (i = 0; i < num_pages; i++) { for (i = 0; i < sNumPages; i++) {
all_pages[i].physical_page_number = physical_page_offset + i; sPages[i].physical_page_number = sPhysicalPageOffset + i;
all_pages[i].type = PAGE_TYPE_PHYSICAL; sPages[i].type = PAGE_TYPE_PHYSICAL;
all_pages[i].state = PAGE_STATE_FREE; sPages[i].state = PAGE_STATE_FREE;
all_pages[i].ref_count = 0; sPages[i].ref_count = 0;
enqueue_page(&page_free_queue, &all_pages[i]); enqueue_page(&page_free_queue, &sPages[i]);
} }
TRACE(("initialized table\n")); TRACE(("initialized table\n"));
// mark some of the page ranges inuse // mark some of the page ranges inuse
for (i = 0; i < ka->num_physical_allocated_ranges; i++) { for (i = 0; i < args->num_physical_allocated_ranges; i++) {
vm_mark_page_range_inuse(ka->physical_allocated_range[i].start / B_PAGE_SIZE, vm_mark_page_range_inuse(args->physical_allocated_range[i].start / B_PAGE_SIZE,
ka->physical_allocated_range[i].size / B_PAGE_SIZE); args->physical_allocated_range[i].size / B_PAGE_SIZE);
} }
TRACE(("vm_page_init: exit\n")); TRACE(("vm_page_init: exit\n"));
@ -411,9 +418,9 @@ vm_page_init_post_area(kernel_args *args)
{ {
void *dummy; void *dummy;
dummy = all_pages; dummy = sPages;
create_area("page structures", &dummy, B_EXACT_ADDRESS, create_area("page structures", &dummy, B_EXACT_ADDRESS,
PAGE_ALIGN(num_pages * sizeof(vm_page)), B_ALREADY_WIRED, PAGE_ALIGN(sNumPages * sizeof(vm_page)), B_ALREADY_WIRED,
B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA);
add_debugger_command("page_stats", &dump_page_stats, "Dump statistics about page usage"); add_debugger_command("page_stats", &dump_page_stats, "Dump statistics about page usage");
@ -468,7 +475,7 @@ page_scrubber(void *unused)
// get some pages from the free queue // get some pages from the free queue
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
for (i = 0; i < SCRUB_SIZE; i++) { for (i = 0; i < SCRUB_SIZE; i++) {
page[i] = dequeue_page(&page_free_queue); page[i] = dequeue_page(&page_free_queue);
@ -476,7 +483,7 @@ page_scrubber(void *unused)
break; break;
} }
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
// clear them // clear them
@ -488,7 +495,7 @@ page_scrubber(void *unused)
} }
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
// and put them into the clear queue // and put them into the clear queue
@ -497,7 +504,7 @@ page_scrubber(void *unused)
enqueue_page(&page_clear_queue, page[i]); enqueue_page(&page_clear_queue, page[i]);
} }
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
} }
} }
@ -537,21 +544,21 @@ vm_mark_page_range_inuse(addr_t start_page, addr_t length)
TRACE(("vm_mark_page_range_inuse: start 0x%lx, len 0x%lx\n", start_page, length)); TRACE(("vm_mark_page_range_inuse: start 0x%lx, len 0x%lx\n", start_page, length));
if (physical_page_offset > start_page) { if (sPhysicalPageOffset > start_page) {
dprintf("vm_mark_page_range_inuse: start page %ld is before free list\n", start_page); dprintf("vm_mark_page_range_inuse: start page %ld is before free list\n", start_page);
return B_BAD_VALUE; return B_BAD_VALUE;
} }
start_page -= physical_page_offset; start_page -= sPhysicalPageOffset;
if (start_page + length > num_pages) { if (start_page + length > sNumPages) {
dprintf("vm_mark_page_range_inuse: range would extend past free list\n"); dprintf("vm_mark_page_range_inuse: range would extend past free list\n");
return B_BAD_VALUE; return B_BAD_VALUE;
} }
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
for (i = 0; i < length; i++) { for (i = 0; i < length; i++) {
page = &all_pages[start_page + i]; page = &sPages[start_page + i];
switch (page->state) { switch (page->state) {
case PAGE_STATE_FREE: case PAGE_STATE_FREE:
case PAGE_STATE_CLEAR: case PAGE_STATE_CLEAR:
@ -570,7 +577,7 @@ vm_mark_page_range_inuse(addr_t start_page, addr_t length)
} }
} }
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
return B_OK; return B_OK;
@ -585,7 +592,7 @@ vm_page_allocate_specific_page(addr_t page_num, int page_state)
int state; int state;
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
p = vm_lookup_page(page_num); p = vm_lookup_page(page_num);
if (p == NULL) if (p == NULL)
@ -614,7 +621,7 @@ vm_page_allocate_specific_page(addr_t page_num, int page_state)
enqueue_page(&page_active_queue, p); enqueue_page(&page_active_queue, p);
out: out:
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
if (p != NULL && page_state == PAGE_STATE_CLEAR if (p != NULL && page_state == PAGE_STATE_CLEAR
@ -648,7 +655,7 @@ vm_page_allocate_page(int page_state)
} }
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
p = dequeue_page(q); p = dequeue_page(q);
if (p == NULL) { if (p == NULL) {
@ -676,7 +683,7 @@ vm_page_allocate_page(int page_state)
enqueue_page(&page_active_queue, p); enqueue_page(&page_active_queue, p);
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
// if needed take the page from the free queue and zero it out // if needed take the page from the free queue and zero it out
@ -724,16 +731,16 @@ vm_page_allocate_page_run(int page_state, addr_t len)
start = 0; start = 0;
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
for (;;) { for (;;) {
bool foundit = true; bool foundit = true;
if (start + len > num_pages) if (start + len > sNumPages)
break; break;
for (i = 0; i < len; i++) { for (i = 0; i < len; i++) {
if (all_pages[start + i].state != PAGE_STATE_FREE if (sPages[start + i].state != PAGE_STATE_FREE
&& all_pages[start + i].state != PAGE_STATE_CLEAR) { && sPages[start + i].state != PAGE_STATE_CLEAR) {
foundit = false; foundit = false;
i++; i++;
break; break;
@ -742,14 +749,14 @@ vm_page_allocate_page_run(int page_state, addr_t len)
if (foundit) { if (foundit) {
// pull the pages out of the appropriate queues // pull the pages out of the appropriate queues
for (i = 0; i < len; i++) for (i = 0; i < len; i++)
vm_page_set_state_nolock(&all_pages[start + i], PAGE_STATE_BUSY); vm_page_set_state_nolock(&sPages[start + i], PAGE_STATE_BUSY);
first_page = &all_pages[start]; first_page = &sPages[start];
break; break;
} else { } else {
start += i; start += i;
} }
} }
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
return first_page; return first_page;
@ -759,14 +766,14 @@ vm_page_allocate_page_run(int page_state, addr_t len)
vm_page * vm_page *
vm_lookup_page(addr_t page_num) vm_lookup_page(addr_t page_num)
{ {
if (page_num < physical_page_offset) if (page_num < sPhysicalPageOffset)
return NULL; return NULL;
page_num -= physical_page_offset; page_num -= sPhysicalPageOffset;
if (page_num >= num_pages) if (page_num >= sNumPages)
return NULL; return NULL;
return &all_pages[page_num]; return &sPages[page_num];
} }
@ -830,11 +837,11 @@ vm_page_set_state(vm_page *page, int page_state)
status_t status; status_t status;
cpu_status state = disable_interrupts(); cpu_status state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&sPageLock);
status = vm_page_set_state_nolock(page, page_state); status = vm_page_set_state_nolock(page, page_state);
release_spinlock(&page_lock); release_spinlock(&sPageLock);
restore_interrupts(state); restore_interrupts(state);
return status; return status;
@ -844,7 +851,7 @@ vm_page_set_state(vm_page *page, int page_state)
size_t size_t
vm_page_num_pages(void) vm_page_num_pages(void)
{ {
return num_pages; return sNumPages;
} }
@ -951,11 +958,11 @@ dump_page_stats(int argc, char **argv)
memset(counter, 0, sizeof(counter)); memset(counter, 0, sizeof(counter));
for (i = 0; i < num_pages; i++) { for (i = 0; i < sNumPages; i++) {
if (all_pages[i].state > 7) if (sPages[i].state > 7)
panic("page %i at %p has invalid state!\n", i, &all_pages[i]); panic("page %i at %p has invalid state!\n", i, &sPages[i]);
counter[all_pages[i].state]++; counter[sPages[i].state]++;
} }
kprintf("page stats:\n"); kprintf("page stats:\n");