Now uses create_area() instead of vm_create_anonymous_region().

The page_stats debugger command now understands queue names as well.
Some minor cleanup, improved error checking.


git-svn-id: file:///srv/svn/repos/haiku/trunk/current@9861 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Axel Dörfler
2004-11-08 14:34:35 +00:00
parent 1c11f7ea8a
commit 13dee31361
+64 -27
View File
@@ -28,6 +28,8 @@
# define TRACE(x) ; # define TRACE(x) ;
#endif #endif
#define SCRUB_SIZE 16
// this many pages will be cleared at once in the page scrubber thread
typedef struct page_queue { typedef struct page_queue {
vm_page *head; vm_page *head;
@@ -272,11 +274,12 @@ vm_page_init(kernel_args *ka)
status_t status_t
vm_page_init_post_area(kernel_args *args) vm_page_init_post_area(kernel_args *args)
{ {
void *null; void *dummy;
null = all_pages; dummy = all_pages;
vm_create_anonymous_region(vm_get_kernel_aspace_id(), "page_structures", &null, B_EXACT_ADDRESS, create_area("page structures", &dummy, B_EXACT_ADDRESS,
PAGE_ALIGN(num_pages * sizeof(vm_page)), B_ALREADY_WIRED, B_KERNEL_READ_AREA | B_KERNEL_WRITE_AREA); PAGE_ALIGN(num_pages * sizeof(vm_page)), B_ALREADY_WIRED,
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");
add_debugger_command("free_pages", &dump_free_page_table, "Dump list of free pages"); add_debugger_command("free_pages", &dump_free_page_table, "Dump list of free pages");
@@ -294,7 +297,7 @@ vm_page_init_post_thread(kernel_args *args)
// create a kernel thread to clear out pages // create a kernel thread to clear out pages
thread = spawn_kernel_thread(&page_scrubber, "page scrubber", B_LOWEST_ACTIVE_PRIORITY, NULL); thread = spawn_kernel_thread(&page_scrubber, "page scrubber", B_LOWEST_ACTIVE_PRIORITY, NULL);
resume_thread(thread); send_signal_etc(thread, SIGCONT, B_DO_NOT_RESCHEDULE);
modified_pages_available = create_sem(0, "modified_pages_avail_sem"); modified_pages_available = create_sem(0, "modified_pages_avail_sem");
#if 0 #if 0
@@ -306,15 +309,15 @@ vm_page_init_post_thread(kernel_args *args)
} }
/** This is a background thread that wakes up every now and then (every 100ms)
* and moves some pages from the free queue over to the clear queue.
* Given enough time, it will clear out all pages from the free queue - we
* could probably slow it down after having reached a certain threshold.
*/
static int32 static int32
page_scrubber(void *unused) page_scrubber(void *unused)
{ {
#define SCRUB_SIZE 16
int state;
vm_page *page[SCRUB_SIZE];
int i;
int scrub_count;
(void)(unused); (void)(unused);
TRACE(("page_scrubber starting...\n")); TRACE(("page_scrubber starting...\n"));
@@ -323,6 +326,12 @@ page_scrubber(void *unused)
snooze(100000); // 100ms snooze(100000); // 100ms
if (page_free_queue.count > 0) { if (page_free_queue.count > 0) {
cpu_status state;
vm_page *page[SCRUB_SIZE];
int32 i, scrubCount;
// get some pages from the free queue
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&page_lock);
@@ -335,16 +344,20 @@ page_scrubber(void *unused)
release_spinlock(&page_lock); release_spinlock(&page_lock);
restore_interrupts(state); restore_interrupts(state);
scrub_count = i; // clear them
for (i = 0; i < scrub_count; i++) { scrubCount = i;
for (i = 0; i < scrubCount; i++) {
clear_page(page[i]->ppn * B_PAGE_SIZE); clear_page(page[i]->ppn * B_PAGE_SIZE);
} }
state = disable_interrupts(); state = disable_interrupts();
acquire_spinlock(&page_lock); acquire_spinlock(&page_lock);
for (i = 0; i < scrub_count; i++) { // and put them into the clear queue
for (i = 0; i < scrubCount; i++) {
page[i]->state = PAGE_STATE_CLEAR; page[i]->state = PAGE_STATE_CLEAR;
enqueue_page(&page_clear_queue, page[i]); enqueue_page(&page_clear_queue, page[i]);
} }
@@ -504,10 +517,20 @@ vm_page_allocate_page(int page_state)
p = dequeue_page(q); p = dequeue_page(q);
if (p == NULL) { if (p == NULL) {
#ifdef DEBUG
if (q->count != 0)
panic("queue %p corrupted, count = %ld\n", q, q->count);
#endif
// if the primary queue was empty, grap the page from the // if the primary queue was empty, grap the page from the
// secondary queue // secondary queue
p = dequeue_page(q_other); p = dequeue_page(q_other);
if (p == NULL) { if (p == NULL) {
#ifdef DEBUG
if (q_other->count != 0)
panic("other queue %p corrupted, count = %ld\n", q_other, q_other->count);
#endif
// ToDo: issue "someone" to free up some pages for us, and go into wait state until that's done // ToDo: issue "someone" to free up some pages for us, and go into wait state until that's done
panic("vm_allocate_page: out of memory! page state = %d\n", page_state); panic("vm_allocate_page: out of memory! page state = %d\n", page_state);
} }
@@ -708,15 +731,25 @@ dump_page_queue(int argc, char **argv)
{ {
struct page_queue *queue; struct page_queue *queue;
if (argc < 2 if (argc < 2) {
|| strlen(argv[1]) <= 2 dprintf("usage: page_queue <address/name> [list]\n");
|| argv[1][0] != '0'
|| argv[1][1] != 'x') {
dprintf("usage: page_queue <address> [list]\n");
return 0; return 0;
} }
queue = (struct page_queue *)(atoul(argv[1])); if (strlen(argv[1]) >= 2 && argv[1][0] == '0' && argv[1][1] == 'x')
queue = (struct page_queue *)strtoul(argv[1], NULL, 16);
if (!strcmp(argv[1], "free"))
queue = &page_free_queue;
else if (!strcmp(argv[1], "clear"))
queue = &page_clear_queue;
else if (!strcmp(argv[1], "modified"))
queue = &page_modified_queue;
else if (!strcmp(argv[1], "active"))
queue = &page_active_queue;
else {
dprintf("page_queue: unknown queue \"%s\".\n", argv[1]);
return 0;
}
dprintf("queue->head = %p, queue->tail = %p, queue->count = %d\n", queue->head, queue->tail, queue->count); dprintf("queue->head = %p, queue->tail = %p, queue->count = %d\n", queue->head, queue->tail, queue->count);
@@ -735,20 +768,24 @@ dump_page_queue(int argc, char **argv)
static int static int
dump_page_stats(int argc, char **argv) dump_page_stats(int argc, char **argv)
{ {
unsigned int page_types[8]; uint32 counter[8];
int32 totalActive;
addr_t i; addr_t i;
memset(page_types, 0, sizeof(page_types)); memset(counter, 0, sizeof(counter));
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
page_types[all_pages[i].state]++; if (all_pages[i].state > 7)
panic("page %i at %p has invalid state!\n", i, &all_pages[i]);
counter[all_pages[i].state]++;
} }
dprintf("page stats:\n"); dprintf("page stats:\n");
dprintf("active: %d\ninactive: %d\nbusy: %d\nunused: %d\n", dprintf("active: %lu\ninactive: %lu\nbusy: %lu\nunused: %lu\n",
page_types[PAGE_STATE_ACTIVE], page_types[PAGE_STATE_INACTIVE], page_types[PAGE_STATE_BUSY], page_types[PAGE_STATE_UNUSED]); counter[PAGE_STATE_ACTIVE], counter[PAGE_STATE_INACTIVE], counter[PAGE_STATE_BUSY], counter[PAGE_STATE_UNUSED]);
dprintf("modified: %d\nfree: %d\nclear: %d\nwired: %d\n", dprintf("wired: %lu\nmodified: %lu\nfree: %lu\nclear: %lu\n",
page_types[PAGE_STATE_MODIFIED], page_types[PAGE_STATE_FREE], page_types[PAGE_STATE_CLEAR], page_types[PAGE_STATE_WIRED]); counter[PAGE_STATE_WIRED], counter[PAGE_STATE_MODIFIED], counter[PAGE_STATE_FREE], counter[PAGE_STATE_CLEAR]);
dprintf("\nfree_queue: %p, count = %d\n", &page_free_queue, page_free_queue.count); dprintf("\nfree_queue: %p, count = %d\n", &page_free_queue, page_free_queue.count);
dprintf("clear_queue: %p, count = %d\n", &page_clear_queue, page_clear_queue.count); dprintf("clear_queue: %p, count = %d\n", &page_clear_queue, page_clear_queue.count);