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).
d->is_ata = false;
d->capacity = 0;
+
+ d->read_cnt = d->write_cnt = 0;
}
/* Register interrupt handler. */
}
}
+/* 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 *
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);
}
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);
}
\f
#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 *);
/* Keyboard buffer. */
static struct intq buffer;
+/* Number of keys pressed. */
+static int64_t key_cnt;
+
static intr_handler_func keyboard_interrupt;
/* Initializes the keyboard. */
return key;
}
+
+/* Prints keyboard statistics. */
+void
+kbd_print_stats (void)
+{
+ printf ("Keyboard: %lld keys pressed\n", key_cnt);
+}
\f
/* Maps a set of contiguous scancodes into characters. */
struct keymap
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
void kbd_init (void);
uint8_t kbd_getc (void);
+void kbd_print_stats (void);
#endif /* devices/kbd.h */
#include "devices/timer.h"
#include <debug.h>
+#include <inttypes.h>
#include <round.h>
+#include <stdio.h>
#include "threads/interrupt.h"
#include "threads/io.h"
#include "threads/thread.h"
{
return DIV_ROUND_UP (ns * TIMER_FREQ, 1000000000);
}
+
+/* Prints timer statistics. */
+void
+timer_print_stats (void)
+{
+ printf ("Timer: %"PRId64" ticks.\n", ticks);
+}
\f
/* Timer interrupt handler. */
static void
timer_interrupt (struct intr_frame *args UNUSED)
{
ticks++;
+ thread_tick ();
if (ticks % TIME_SLICE == 0)
intr_yield_on_return ();
}
int64_t timer_us2ticks (int64_t us);
int64_t timer_ns2ticks (int64_t ns);
+void timer_print_stats (void);
+
#endif /* devices/timer.h */
counter. */
static int console_lock_depth;
+/* Number of characters written to console. */
+static int64_t write_cnt;
+
/* Initializes the console. */
void
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)
static void
putchar_unlocked (uint8_t c)
{
+ write_cnt++;
serial_putc (c);
vga_putc (c);
}
#define __LIB_KERNEL_CONSOLE_H
void console_init (void);
+void console_print_stats (void);
#endif /* lib/kernel/console.h */
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;
filesys_done ();
#endif
+ print_stats ();
+
printf ("Powering off...\n");
serial_flush ();
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
+}
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);
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
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 *);
#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 *);
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)
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;
#define USERPROG_EXCEPTION_H
void exception_init (void);
+void exception_print_stats (void);
#endif /* userprog/exception.h */
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
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 */
}
static void
-syscall_handler (struct intr_frame *f)
+syscall_handler (struct intr_frame *f UNUSED)
{
printf ("system call!\n");
thread_exit ();