From 838c30d0075a3ee0413ba4909944b37f4970a10d Mon Sep 17 00:00:00 2001 From: Ben Pfaff Date: Sun, 26 Sep 2004 21:15:17 +0000 Subject: [PATCH] Print statistics at power off. --- src/devices/disk.c | 29 ++++++++++++++++++++++++++++- src/devices/disk.h | 2 ++ src/devices/kbd.c | 17 +++++++++++++++-- src/devices/kbd.h | 1 + src/devices/timer.c | 10 ++++++++++ src/devices/timer.h | 2 ++ src/lib/kernel/console.c | 11 +++++++++++ src/lib/kernel/console.h | 1 + src/threads/init.c | 19 +++++++++++++++++++ src/threads/thread.c | 29 +++++++++++++++++++++++++++++ src/threads/thread.h | 2 ++ src/userprog/exception.c | 13 +++++++++++++ src/userprog/exception.h | 1 + src/userprog/pagedir.c | 19 +++++-------------- src/userprog/pagedir.h | 2 +- src/userprog/syscall.c | 2 +- 16 files changed, 141 insertions(+), 19 deletions(-) diff --git a/src/devices/disk.c b/src/devices/disk.c index 5867caa..baf1208 100644 --- a/src/devices/disk.c +++ b/src/devices/disk.c @@ -52,7 +52,10 @@ struct disk int dev_no; /* Device 0 or 1 for master or slave. */ bool is_ata; /* 1=This device is an ATA disk. */ - disk_sector_t capacity; /* Capacity in sectors (if is_ata is true). */ + disk_sector_t capacity; /* Capacity in sectors (if is_ata). */ + + long long read_cnt; /* Number of sectors read. */ + long long write_cnt; /* Number of sectors written. */ }; /* An ATA channel (aka controller). @@ -131,6 +134,8 @@ disk_init (void) d->is_ata = false; d->capacity = 0; + + d->read_cnt = d->write_cnt = 0; } /* Register interrupt handler. */ @@ -150,6 +155,26 @@ disk_init (void) } } +/* Prints disk statistics. */ +void +disk_print_stats (void) +{ + int chan_no; + + for (chan_no = 0; chan_no < CHANNEL_CNT; chan_no++) + { + int dev_no; + + for (dev_no = 0; dev_no < 2; dev_no++) + { + struct disk *d = disk_get (chan_no, dev_no); + if (d != NULL && d->is_ata) + printf ("%s: %lld reads, %lld writes\n", + d->name, d->read_cnt, d->write_cnt); + } + } +} + /* Returns the disk numbered DEV_NO--either 0 or 1 for master or slave, respectively--within the channel numbered CHAN_NO. */ struct disk * @@ -194,6 +219,7 @@ disk_read (struct disk *d, disk_sector_t sec_no, void *buffer) if (!wait_while_busy (d)) PANIC ("%s: disk read failed, sector=%"PRDSNu, d->name, sec_no); input_sector (c, buffer); + d->read_cnt++; lock_release (&c->lock); } @@ -216,6 +242,7 @@ disk_write (struct disk *d, disk_sector_t sec_no, const void *buffer) PANIC ("%s: disk write failed, sector=%"PRDSNu, d->name, sec_no); output_sector (c, buffer); sema_down (&c->completion_wait); + d->write_cnt++; lock_release (&c->lock); } diff --git a/src/devices/disk.h b/src/devices/disk.h index 539c4b0..3bcbb9a 100644 --- a/src/devices/disk.h +++ b/src/devices/disk.h @@ -16,6 +16,8 @@ typedef uint32_t disk_sector_t; #define PRDSNu PRIu32 void disk_init (void); +void disk_print_stats (void); + struct disk *disk_get (int chan_no, int dev_no); disk_sector_t disk_size (struct disk *); void disk_read (struct disk *, disk_sector_t, void *); diff --git a/src/devices/kbd.c b/src/devices/kbd.c index 9cd2840..a264984 100644 --- a/src/devices/kbd.c +++ b/src/devices/kbd.c @@ -25,6 +25,9 @@ static unsigned shift_state; /* Keyboard buffer. */ static struct intq buffer; +/* Number of keys pressed. */ +static int64_t key_cnt; + static intr_handler_func keyboard_interrupt; /* Initializes the keyboard. */ @@ -49,6 +52,13 @@ kbd_getc (void) return key; } + +/* Prints keyboard statistics. */ +void +kbd_print_stats (void) +{ + printf ("Keyboard: %lld keys pressed\n", key_cnt); +} /* Maps a set of contiguous scancodes into characters. */ struct keymap @@ -160,8 +170,11 @@ keyboard_interrupt (struct intr_frame *args UNUSED) c += 0x80; /* Append to keyboard buffer. */ - if (!intq_full (&buffer)) - intq_putc (&buffer, c); + if (!intq_full (&buffer)) + { + key_cnt++; + intq_putc (&buffer, c); + } } } else diff --git a/src/devices/kbd.h b/src/devices/kbd.h index 1720d36..ecf477f 100644 --- a/src/devices/kbd.h +++ b/src/devices/kbd.h @@ -5,5 +5,6 @@ void kbd_init (void); uint8_t kbd_getc (void); +void kbd_print_stats (void); #endif /* devices/kbd.h */ diff --git a/src/devices/timer.c b/src/devices/timer.c index 9c611a1..8f47c81 100644 --- a/src/devices/timer.c +++ b/src/devices/timer.c @@ -1,6 +1,8 @@ #include "devices/timer.h" #include +#include #include +#include #include "threads/interrupt.h" #include "threads/io.h" #include "threads/thread.h" @@ -91,12 +93,20 @@ timer_ns2ticks (int64_t ns) { return DIV_ROUND_UP (ns * TIMER_FREQ, 1000000000); } + +/* Prints timer statistics. */ +void +timer_print_stats (void) +{ + printf ("Timer: %"PRId64" ticks.\n", ticks); +} /* Timer interrupt handler. */ static void timer_interrupt (struct intr_frame *args UNUSED) { ticks++; + thread_tick (); if (ticks % TIME_SLICE == 0) intr_yield_on_return (); } diff --git a/src/devices/timer.h b/src/devices/timer.h index db76f6d..59f7c9a 100644 --- a/src/devices/timer.h +++ b/src/devices/timer.h @@ -17,4 +17,6 @@ int64_t timer_ms2ticks (int64_t ms); int64_t timer_us2ticks (int64_t us); int64_t timer_ns2ticks (int64_t ns); +void timer_print_stats (void); + #endif /* devices/timer.h */ diff --git a/src/lib/kernel/console.c b/src/lib/kernel/console.c index 14c707a..d09801d 100644 --- a/src/lib/kernel/console.c +++ b/src/lib/kernel/console.c @@ -42,6 +42,9 @@ static struct lock console_lock; counter. */ static int console_lock_depth; +/* Number of characters written to console. */ +static int64_t write_cnt; + /* Initializes the console. */ void console_init (void) @@ -49,6 +52,13 @@ console_init (void) lock_init (&console_lock, "console"); } +/* Prints console statistics. */ +void +console_print_stats (void) +{ + printf ("Console: %lld characters output\n", write_cnt); +} + /* Acquires the console lock. */ static void acquire_console (void) @@ -140,6 +150,7 @@ vprintf_helper (char c, void *char_cnt_) static void putchar_unlocked (uint8_t c) { + write_cnt++; serial_putc (c); vga_putc (c); } diff --git a/src/lib/kernel/console.h b/src/lib/kernel/console.h index 6e5b41b..788edf2 100644 --- a/src/lib/kernel/console.h +++ b/src/lib/kernel/console.h @@ -2,5 +2,6 @@ #define __LIB_KERNEL_CONSOLE_H void console_init (void); +void console_print_stats (void); #endif /* lib/kernel/console.h */ diff --git a/src/threads/init.c b/src/threads/init.c index 1afa865..9774493 100644 --- a/src/threads/init.c +++ b/src/threads/init.c @@ -55,6 +55,7 @@ static bool do_power_off; static void ram_init (void); static void paging_init (void); static void argv_init (void); +static void print_stats (void); int main (void) NO_RETURN; @@ -282,6 +283,8 @@ power_off (void) filesys_done (); #endif + print_stats (); + printf ("Powering off...\n"); serial_flush (); @@ -289,3 +292,19 @@ power_off (void) outb (0x8900, *p); for (;;); } + +/* Print statistics about Pintos execution. */ +static void +print_stats (void) +{ + timer_print_stats (); + thread_print_stats (); +#ifdef FILESYS + disk_print_stats (); +#endif + console_print_stats (); + kbd_print_stats (); +#ifdef USERPROG + exception_print_stats (); +#endif +} diff --git a/src/threads/thread.c b/src/threads/thread.c index e85bc16..afb2006 100644 --- a/src/threads/thread.c +++ b/src/threads/thread.c @@ -41,6 +41,11 @@ struct kernel_thread_frame void *aux; /* Auxiliary data for function. */ }; +/* Statistics. */ +static long long idle_ticks; /* # of timer ticks spent idle. */ +static long long kernel_ticks; /* # of timer ticks in kernel threads. */ +static long long user_ticks; /* # of timer ticks in user programs. */ + static void kernel_thread (thread_func *, void *aux); static void idle (void *aux UNUSED); @@ -86,6 +91,30 @@ thread_start (void) intr_enable (); } +/* Called by the timer interrupt handler at each timer tick to + update statistics. */ +void +thread_tick (void) +{ + struct thread *t = thread_current (); + if (t == idle_thread) + idle_ticks++; +#ifdef USERPROG + else if (t->pagedir != NULL) + user_ticks++; +#endif + else + kernel_ticks++; +} + +/* Prints thread statistics. */ +void +thread_print_stats (void) +{ + printf ("Thread: %lld idle ticks, %lld kernel ticks, %lld user ticks\n", + idle_ticks, kernel_ticks, user_ticks); +} + /* Creates a new kernel thread named NAME with the given initial PRIORITY, which executes FUNCTION passing AUX as the argument, and adds it to the ready queue. If thread_start() has been diff --git a/src/threads/thread.h b/src/threads/thread.h index 9b55700..c055127 100644 --- a/src/threads/thread.h +++ b/src/threads/thread.h @@ -103,6 +103,8 @@ struct thread void thread_init (void); void thread_start (void); +void thread_tick (void); +void thread_print_stats (void); typedef void thread_func (void *aux); tid_t thread_create (const char *name, int priority, thread_func *, void *); diff --git a/src/userprog/exception.c b/src/userprog/exception.c index f31f7a8..8b2e8b6 100644 --- a/src/userprog/exception.c +++ b/src/userprog/exception.c @@ -5,6 +5,9 @@ #include "threads/interrupt.h" #include "threads/thread.h" +/* Number of page faults processed. */ +static long long page_fault_cnt; + static void kill (struct intr_frame *); static void page_fault (struct intr_frame *); @@ -54,6 +57,13 @@ exception_init (void) intr_register (14, 0, INTR_OFF, page_fault, "#PF Page-Fault Exception"); } +/* Prints exception statistics. */ +void +exception_print_stats (void) +{ + printf ("Exception: %lld page faults\n", page_fault_cnt); +} + /* Handler for an exception (probably) caused by a user process. */ static void kill (struct intr_frame *f) @@ -129,6 +139,9 @@ page_fault (struct intr_frame *f) be assured of reading CR2 before it changed). */ intr_enable (); + /* Count page faults. */ + page_fault_cnt++; + /* Determine cause. */ not_present = (f->error_code & PF_P) == 0; write = (f->error_code & PF_W) != 0; diff --git a/src/userprog/exception.h b/src/userprog/exception.h index e378410..f1a1537 100644 --- a/src/userprog/exception.h +++ b/src/userprog/exception.h @@ -2,5 +2,6 @@ #define USERPROG_EXCEPTION_H void exception_init (void); +void exception_print_stats (void); #endif /* userprog/exception.h */ diff --git a/src/userprog/pagedir.c b/src/userprog/pagedir.c index 7c392e6..fa8f244 100644 --- a/src/userprog/pagedir.c +++ b/src/userprog/pagedir.c @@ -168,23 +168,14 @@ pagedir_test_accessed (uint32_t *pd, const void *upage) return pte != NULL && (*pte & PG_A) != 0; } -/* Returns true if the PTE for user virtual page UPAGE in PD has - been accessed recently, and then resets the accessed bit for - that page. - Returns false and has no effect if PD contains no PDE for - UPAGE. */ -bool -pagedir_test_accessed_and_clear (uint32_t *pd, const void *upage) +/* Resets the accessed bit in the PTE for user virtual page UPAGE + in PD. */ +void +pagedir_clear_accessed (uint32_t *pd, const void *upage) { uint32_t *pte = lookup_page (pd, (void *) upage, false); if (pte != NULL) - { - bool accessed = (*pte & PG_A) != 0; - *pte &= ~(uint32_t) PG_A; - return accessed; - } - else - return false; + *pte &= ~(uint32_t) PG_A; } /* Loads page directory PD into the CPU's page directory base diff --git a/src/userprog/pagedir.h b/src/userprog/pagedir.h index bb84856..f1ddace 100644 --- a/src/userprog/pagedir.h +++ b/src/userprog/pagedir.h @@ -11,7 +11,7 @@ void *pagedir_get_page (uint32_t *pd, const void *upage); void pagedir_clear_page (uint32_t *pd, void *upage); bool pagedir_test_dirty (uint32_t *pd, const void *upage); bool pagedir_test_accessed (uint32_t *pd, const void *upage); -bool pagedir_test_accessed_and_clear (uint32_t *pd, const void *upage); +void pagedir_clear_accessed (uint32_t *pd, const void *upage); void pagedir_activate (uint32_t *pd); #endif /* userprog/pagedir.h */ diff --git a/src/userprog/syscall.c b/src/userprog/syscall.c index 7f758c6..db67593 100644 --- a/src/userprog/syscall.c +++ b/src/userprog/syscall.c @@ -13,7 +13,7 @@ syscall_init (void) } static void -syscall_handler (struct intr_frame *f) +syscall_handler (struct intr_frame *f UNUSED) { printf ("system call!\n"); thread_exit (); -- 2.30.2