diff --git a/include/kernel/stats.h b/include/kernel/stats.h index 77ac0dd2..54c30fe0 100644 --- a/include/kernel/stats.h +++ b/include/kernel/stats.h @@ -5,24 +5,30 @@ #include "kernel/syscall.h" struct system_stats { - uint32_t time; - uint32_t blocks_read[4]; - uint32_t blocks_written[4]; + int time; + int blocks_read[4]; + int blocks_written[4]; }; -struct object_stats { - uint32_t reads; - uint32_t writes; - uint64_t bytes_read; - uint64_t bytes_written; +struct device_driver_stats { + int blocks_written; + int blocks_read; +}; + +struct bcache_stats { + int read_hits; + int read_misses; + int write_hits; + int write_misses; + int writebacks; }; struct process_stats { - uint32_t blocks_read; - uint32_t blocks_written; - uint32_t bytes_read; - uint32_t bytes_written; - uint32_t syscall_count[MAX_SYSCALL]; + int blocks_read; + int blocks_written; + int bytes_read; + int bytes_written; + int syscall_count[MAX_SYSCALL]; }; #endif diff --git a/include/kernel/syscall.h b/include/kernel/syscall.h index 24838d42..6ed9824c 100644 --- a/include/kernel/syscall.h +++ b/include/kernel/syscall.h @@ -49,8 +49,11 @@ typedef enum { SYSCALL_OBJECT_SET_BLOCKING, SYSCALL_OBJECT_MAX, SYSCALL_SYSTEM_STATS, + SYSCALL_BCACHE_STATS, + SYSCALL_BCACHE_FLUSH, SYSCALL_SYSTEM_TIME, SYSCALL_SYSTEM_RTC, + SYSCALL_DEVICE_DRIVER_STATS, SYSCALL_CHDIR, MAX_SYSCALL // must be the last element in the enum } syscall_t; diff --git a/include/library/string.h b/include/library/string.h index 60b5b6f5..f7a7e9a8 100644 --- a/include/library/string.h +++ b/include/library/string.h @@ -14,6 +14,7 @@ void strncpy(char *d, const char *s, unsigned length); char * strdup(const char *s); int strcmp(const char *a, const char *b); int strncmp(const char *a, const char *b, unsigned length); +char *strdup(const char *s); unsigned strlen(const char *s); char *strcat(char *d, const char *s); char *uint_to_string(uint32_t u, char *str); diff --git a/include/library/syscalls.h b/include/library/syscalls.h index 37feca56..b8eac45b 100644 --- a/include/library/syscalls.h +++ b/include/library/syscalls.h @@ -51,7 +51,6 @@ int syscall_object_size(int fd, int * dims, int n); int syscall_object_copy( int src, int dst ); int syscall_object_remove( int fd, const char *name ); int syscall_object_close(int fd); -int syscall_object_stats(int fd, struct object_stats *stats ); int syscall_object_set_tag(int fd, char *tag); int syscall_object_get_tag(int fd, char *buffer, int buffer_size); int syscall_object_set_blocking(int fd, int b); @@ -60,9 +59,15 @@ int syscall_object_max(); /* Syscalls that query or affect the whole system state. */ int syscall_system_stats(struct system_stats *s); +int syscall_bcache_stats(struct bcache_stats *s); + +int syscall_bcache_flush(); + int syscall_system_time( uint32_t *t ); int syscall_system_rtc( struct rtc_time *t ); +int syscall_device_driver_stats(char * name, struct device_driver_stats * stats); + /* These system calls are carryovers from Unix-like thinking and need to be reworked to fit the kernel object model. diff --git a/kernel/bcache.h b/kernel/bcache.h index 9bbe4083..6f4156c9 100644 --- a/kernel/bcache.h +++ b/kernel/bcache.h @@ -8,6 +8,7 @@ See the file LICENSE for details. #define BCACHE_H #include "device.h" +#include "kernel/stats.h" int bcache_read( struct device *d, char *data, int blocks, int offset ); int bcache_write( struct device *d, const char *data, int blocks, int offset ); @@ -19,14 +20,6 @@ void bcache_flush_block( struct device *d, int block ); void bcache_flush_device( struct device *d ); void bcache_flush_all(); -struct bcache_stats { - unsigned read_hits; - unsigned read_misses; - unsigned write_hits; - unsigned write_misses; - unsigned writebacks; -}; - void bcache_get_stats( struct bcache_stats *s ); #endif diff --git a/kernel/device.c b/kernel/device.c index b0c64842..7e2b06f3 100644 --- a/kernel/device.c +++ b/kernel/device.c @@ -3,12 +3,12 @@ Copyright (C) 2016-2019 The University of Notre Dame This software is distributed under the GNU General Public License. See the file LICENSE for details. */ - #include "device.h" #include "string.h" #include "page.h" #include "kmalloc.h" +#include "kernel/stats.h" #include "kernel/types.h" #include "kernel/error.h" @@ -26,6 +26,7 @@ struct device { void device_driver_register( struct device_driver *d ) { d->next = driver_list; + d->stats = (struct device_driver_stats){0}; driver_list = d; } @@ -59,16 +60,9 @@ struct device *device_open( const char *name, int unit ) int nblocks, block_size; char info[64]; - struct device_driver *dd = driver_list; - - for(dd=driver_list;dd;dd=dd->next) { - if(!strcmp(dd->name,name)) { - if(dd->probe(unit,&nblocks,&block_size,info)) { - return device_create(dd,unit,nblocks,block_size); - } else { - return 0; - } - } + struct device_driver *dd = device_driver_lookup(name); + if (dd && dd->probe(unit,&nblocks,&block_size,info)) { + return device_create(dd,unit,nblocks,block_size); } return 0; @@ -99,8 +93,13 @@ void device_close( struct device *d ) int device_read(struct device *d, void *data, int size, int offset) { + int status; if(d->driver->read) { - return d->driver->read(d->unit,data,size*d->multiplier,offset*d->multiplier); + status = d->driver->read(d->unit,data,size*d->multiplier,offset*d->multiplier); + if (status) { + d->driver->stats.blocks_read += size*d->multiplier; // number of blocks + } + return status; } else { return KERROR_NOT_IMPLEMENTED; } @@ -108,8 +107,13 @@ int device_read(struct device *d, void *data, int size, int offset) int device_read_nonblock(struct device *d, void *data, int size, int offset) { + int status; if(d->driver->read_nonblock) { - return d->driver->read_nonblock(d->unit,data,size*d->multiplier,offset*d->multiplier); + status = d->driver->read_nonblock(d->unit,data,size*d->multiplier,offset*d->multiplier); + if (status) { + d->driver->stats.blocks_read += size*d->multiplier; // number of blocks + } + return status; } else { return KERROR_NOT_IMPLEMENTED; } @@ -117,8 +121,13 @@ int device_read_nonblock(struct device *d, void *data, int size, int offset) int device_write(struct device *d, const void *data, int size, int offset) { + int status; if(d->driver->write) { - return d->driver->write(d->unit,data,size*d->multiplier,offset*d->multiplier); + status = d->driver->write(d->unit,data,size*d->multiplier,offset*d->multiplier); + if (!status) { + d->driver->stats.blocks_written += size*d->multiplier; + } + return status; } else { return KERROR_NOT_IMPLEMENTED; } @@ -143,3 +152,25 @@ const char * device_name( struct device *d ) { return d->driver->name; } + +struct device_driver * device_driver_lookup(const char *name) +{ + struct device_driver *dd = driver_list; + for(dd=driver_list; dd; dd=dd->next) { + if(!strcmp(dd->name, name)) { + break; + } + } + return dd; +} + +void device_driver_get_stats(const char * name, struct device_driver_stats * s) +{ + /* Get the device driver */ + struct device_driver *dd = device_driver_lookup(name); + + /* Copy stats into struct */ + if (dd) { + memcpy(s, &(dd->stats), sizeof(*s)); + } +} diff --git a/kernel/device.h b/kernel/device.h index 85fb6dfa..426d2474 100644 --- a/kernel/device.h +++ b/kernel/device.h @@ -7,6 +7,7 @@ See the file LICENSE for details. #ifndef DEVICE_H #define DEVICE_H +#include "kernel/stats.h" #include "kernel/types.h" struct device_driver { @@ -16,6 +17,7 @@ struct device_driver { int (*read_nonblock) ( int unit, void *buffer, int nblocks, int block_offset); int (*write) ( int unit, const void *buffer, int nblocks, int block_offset); int multiplier; + struct device_driver_stats stats; struct device_driver *next; }; @@ -33,4 +35,7 @@ int device_nblocks( struct device *d ); int device_unit( struct device *d ); const char * device_name( struct device *d ); +void device_driver_get_stats(const char * name, struct device_driver_stats * s); +struct device_driver * device_driver_lookup(const char *name); + #endif diff --git a/kernel/syscall_handler.c b/kernel/syscall_handler.c index 5cb3d7fc..9732eb88 100644 --- a/kernel/syscall_handler.c +++ b/kernel/syscall_handler.c @@ -27,6 +27,7 @@ See the file LICENSE for details. #include "ata.h" #include "graphics.h" #include "is_valid.h" +#include "bcache.h" /* syscall_handler() is responsible for decoding system calls @@ -504,11 +505,6 @@ int sys_object_close(int fd) return 0; } -int sys_object_stats( int fd, struct object_stats *stats ) -{ - return KERROR_NOT_IMPLEMENTED; -} - int sys_object_set_tag(int fd, char *tag) { if(!is_valid_object(fd)) return KERROR_INVALID_OBJECT; @@ -570,6 +566,19 @@ int sys_system_stats(struct system_stats *s) return 0; } +int sys_bcache_stats(struct bcache_stats * s) +{ + if(!is_valid_pointer(s,sizeof(*s))) return KERROR_INVALID_ADDRESS; + bcache_get_stats( s ); + return 0; +} + +int sys_bcache_flush() +{ + bcache_flush_all(); + return 0; +} + int sys_system_time( uint32_t *tm ) { if(!is_valid_pointer(tm,sizeof(*tm))) return KERROR_INVALID_ADDRESS; @@ -586,6 +595,15 @@ int sys_system_rtc( struct rtc_time *t ) return 0; } +int sys_device_driver_stats(const char * name, struct device_driver_stats * stats) +{ + if(!is_valid_string(name)) return KERROR_INVALID_ADDRESS; + if(!is_valid_pointer(stats,sizeof(*stats))) return KERROR_INVALID_ADDRESS; + + device_driver_get_stats(name, stats); + return 0; +} + int sys_chdir(const char *path) { if(!is_valid_path(path)) return KERROR_INVALID_PATH; @@ -667,8 +685,6 @@ int32_t syscall_handler(syscall_t n, uint32_t a, uint32_t b, uint32_t c, uint32_ return sys_object_remove(a,(const char*)b); case SYSCALL_OBJECT_CLOSE: return sys_object_close(a); - case SYSCALL_OBJECT_STATS: - return sys_object_stats(a, (struct object_stats *) b); case SYSCALL_OBJECT_SET_TAG: return sys_object_set_tag(a, (char *) b); case SYSCALL_OBJECT_GET_TAG: @@ -683,11 +699,16 @@ int32_t syscall_handler(syscall_t n, uint32_t a, uint32_t b, uint32_t c, uint32_ return sys_object_copy(a,b); case SYSCALL_SYSTEM_STATS: return sys_system_stats((struct system_stats *) a); + case SYSCALL_BCACHE_STATS: + return sys_bcache_stats((struct bcache_stats *) a); + case SYSCALL_BCACHE_FLUSH: + return sys_bcache_flush(); case SYSCALL_SYSTEM_TIME: return sys_system_time((uint32_t*)a); case SYSCALL_SYSTEM_RTC: return sys_system_rtc((struct rtc_time *) a); - + case SYSCALL_DEVICE_DRIVER_STATS: + return sys_device_driver_stats((char *) a, (struct device_driver_stats *) b); case SYSCALL_CHDIR: return sys_chdir((const char *) a); default: diff --git a/library/string.c b/library/string.c index 4ca2ccaa..4f32f5bc 100644 --- a/library/string.c +++ b/library/string.c @@ -6,6 +6,7 @@ See the file LICENSE for details. #include "kernel/types.h" #include "kernel/ascii.h" +#include "library/malloc.h" #include "library/string.h" #include "library/malloc.h" #include "stdarg.h" @@ -28,11 +29,12 @@ void strncpy(char *d, const char *s, unsigned length) char * strdup(const char *s) { - char * d = (char *)malloc(strlen(s) * sizeof(char)); + char * d = (char *)malloc((strlen(s)+1) * sizeof(char)); + char * tmp = d; while(*s) { - *d++ = *s++; + *tmp++ = *s++; } - *d = 0; + *tmp = 0; return d; } diff --git a/library/syscalls.c b/library/syscalls.c index 62dc3712..b281a025 100644 --- a/library/syscalls.c +++ b/library/syscalls.c @@ -193,6 +193,16 @@ int syscall_system_stats(struct system_stats *s) return syscall(SYSCALL_SYSTEM_STATS, (uint32_t) s, 0, 0, 0, 0); } +int syscall_bcache_stats(struct bcache_stats *bstats) +{ + return syscall(SYSCALL_BCACHE_STATS, (uint32_t) bstats, 0, 0, 0, 0); +} + +int syscall_bcache_flush() +{ + return syscall(SYSCALL_BCACHE_FLUSH, 0, 0, 0, 0, 0); +} + int syscall_system_time( uint32_t *t ) { return syscall(SYSCALL_SYSTEM_TIME, (uint32_t)t, 0, 0, 0, 0); @@ -203,6 +213,11 @@ int syscall_system_rtc( struct rtc_time *time ) return syscall(SYSCALL_SYSTEM_RTC, (uint32_t)time, 0, 0, 0, 0); } +int syscall_device_driver_stats(char * name, void * stats) +{ + return syscall(SYSCALL_DEVICE_DRIVER_STATS, (uint32_t) name, (uint32_t) stats, 0, 0, 0); +} + int syscall_chdir(const char *path) { return syscall(SYSCALL_CHDIR, (uint32_t) path, 0, 0, 0, 0); diff --git a/user/Makefile b/user/Makefile index 53a227a6..87efce3f 100644 --- a/user/Makefile +++ b/user/Makefile @@ -1,7 +1,7 @@ include ../Makefile.config -USER_PROGRAMS=test.exe long.exe printer.exe forktest.exe errcodes.exe exectest.exe filedescribetest.exe saver.exe ball.exe write.exe shell.exe pipetest.exe snake.exe sysstat.exe procstat.exe writebig.exe manager.exe clock.exe mandelbrot.exe open.exe copy.exe +USER_PROGRAMS=test.exe long.exe printer.exe forktest.exe errcodes.exe exectest.exe filedescribetest.exe saver.exe ball.exe write.exe shell.exe pipetest.exe snake.exe sysstat.exe procstat.exe writebig.exe manager.exe clock.exe mandelbrot.exe open.exe copy.exe livestat.exe statworkload.exe all: $(USER_PROGRAMS) diff --git a/user/livestat.c b/user/livestat.c new file mode 100644 index 00000000..fc290666 --- /dev/null +++ b/user/livestat.c @@ -0,0 +1,377 @@ +#include "library/malloc.h" +#include "library/syscalls.h" +#include "library/string.h" +#include "library/user-io.h" + +/** + * Livestat is a command line utility to display a graph of operating system + * statistics in realtime + */ + +#define POINTS 60 +#define ARG_MAX 16 +#define ARG_SIZE 32 + +typedef enum STAT_LIVE { + DRIVER_LIVE, + BCACHE_LIVE, + SYSTEM_LIVE, + PROCESS_LIVE +} STAT_LIVE; + +struct stat_args { + /* General */ + STAT_LIVE stat_type; + char * stat_name; + void * statistics; + /* Process */ + char * pid_s; + int pid; + int syscall_index; + /* Driver */ + char * driver_name; + /* System */ + int device_unit; +}; + +void help(); +void stat_live_2_str(STAT_LIVE stat_l, char * str); +void create_graph(STAT_LIVE stat_type, char * stat_name, char * stat_arg, int window_width, int window_height, int plot_width, int plot_height, int thickness, int char_offset); +int extract_statistic(struct stat_args * args); +void plot_bars(int * most_recent_vals, int max, int window_width, int window_height, int plot_width, int plot_height, int thickness, int char_offset); +void run_stats(struct stat_args * args); + +int main(int argc, const char * argv[]) { + /* Setup program parameters */ + int current_arg = 1; + struct stat_args args = { 0 }; + + /* Parse command line options */ + if (argc < 2) { + help(1); return 1; + } + + while(current_arg < argc) { + if (!strcmp(argv[current_arg], "-h") || !strcmp(argv[current_arg], "--help")) { + help(); return 0; + } + else if (!strcmp(argv[current_arg], "-b")) { + args.statistics = malloc(sizeof(struct bcache_stats)); + args.stat_type = BCACHE_LIVE; + } + else if (!strcmp(argv[current_arg], "-dr")) { + args.statistics = malloc(sizeof(struct device_driver_stats)); + args.stat_type = DRIVER_LIVE; + args.driver_name = strdup(argv[++current_arg]); + } + else if (!strcmp(argv[current_arg], "-sys")) { + args.statistics = malloc(sizeof(struct system_stats)); + args.stat_type = SYSTEM_LIVE; + } + else if (!strcmp(argv[current_arg], "-p")) { + args.statistics = malloc(sizeof(struct process_stats)); + args.stat_type = PROCESS_LIVE; + args.pid_s = strdup(argv[++current_arg]); + str2int(args.pid_s, &(args.pid)); + } + else if (!strcmp(argv[current_arg], "-s")) { + args.stat_name = strdup(argv[++current_arg]); + } + else if (!strcmp(argv[current_arg], "-sc")) { + str2int(argv[++current_arg], &(args.syscall_index)); + } + else if (!strcmp(argv[current_arg], "-du")) { + str2int(argv[++current_arg], &(args.device_unit)); + } + else { + help(); return 1; + } + ++current_arg; + } + + if (!args.stat_name) { + help(); return 1; + } + + /* Start tracking stats */ + run_stats(&args); + + return 0; +} + +/** HELPER FUNCTIONS **/ +/* Create graph and continuously update it */ +void run_stats(struct stat_args * args) { + /* Initialize variables for graph and stats collection */ + int window_width = 270; + int window_height = 270; + int plot_width = 180; + int plot_height = 180; + int thickness = 2; + int char_offset = 8; + + /* Generate the graph with correct labels */ + if (args->stat_type == BCACHE_LIVE) { + create_graph(args->stat_type, args->stat_name, 0, window_width, window_height, plot_width, plot_height, thickness, char_offset); + } else if (args->stat_type == PROCESS_LIVE) { + create_graph(args->stat_type, args->stat_name, args->pid_s, window_width, window_height, plot_width, plot_height, thickness, char_offset); + } else if (args->stat_type == DRIVER_LIVE) { + create_graph(args->stat_type, args->stat_name, args->driver_name, window_width, window_height, plot_width, plot_height, thickness, char_offset); + } else if (args->stat_type == SYSTEM_LIVE) { + create_graph(args->stat_type, args->stat_name, 0, window_width, window_height, plot_width, plot_height, thickness, char_offset); + } + + /* Start tracking stats */ + int i, new_val, max; + int most_recent_vals[POINTS]; + int last_value = 0; + int first = 1; + char quit = 0; + + for (size_t i = 0; i < POINTS; i++) + most_recent_vals[i] = -1; + + while(1) { + /* Check to exit */ + syscall_object_read_nonblock(0, &quit, 1); + if (quit == 'q') break; + + /* Get the correct stats */ + if (args->stat_type == BCACHE_LIVE) { + syscall_bcache_stats(args->statistics); + } else if (args->stat_type == PROCESS_LIVE) { + syscall_process_stats(args->statistics, args->pid); + } else if (args->stat_type == DRIVER_LIVE) { + syscall_device_driver_stats(args->driver_name, args->statistics); + } else if (args->stat_type == SYSTEM_LIVE) { + syscall_system_stats(args->statistics); + } + + /* Grab the specified statistic of interest */ + new_val = extract_statistic(args); + + /* Skip first value because it is just a baseline */ + if (first) { + last_value = new_val; + first = 0; + goto sleep; + } + + /* Update points */ + for (i = 1; i < POINTS; i++) + most_recent_vals[i-1] = most_recent_vals[i]; + most_recent_vals[POINTS-1] = new_val - last_value; + last_value = new_val; + + /* Set max to greatest point or 1 */ + max = 1; + for (i = 0; i < POINTS; i++) { + if (most_recent_vals[i] > max) max = most_recent_vals[i]; + } + + /* Replot points */ + plot_bars(most_recent_vals, max, window_width, window_height, plot_width, plot_height, thickness, char_offset); + + /* Sleep for 6 seconds and then continue */ + sleep: + syscall_process_sleep(6000); + } + draw_color(255, 255, 255); + draw_flush(); +} + +/* Return one stat from statistics structure */ +int extract_statistic(struct stat_args * args) { + + if (args->stat_type == BCACHE_LIVE) { + if (!strcmp(args->stat_name, "read_hits")) { + return ((struct bcache_stats *)args->statistics)->read_hits; + } else if (!strcmp(args->stat_name, "read_misses")) { + return ((struct bcache_stats *)args->statistics)->read_misses; + } else if (!strcmp(args->stat_name, "write_hits")) { + return ((struct bcache_stats *)args->statistics)->write_hits; + } else if (!strcmp(args->stat_name, "write_misses")) { + return ((struct bcache_stats *)args->statistics)->write_misses; + } else if (!strcmp(args->stat_name, "writebacks")) { + return ((struct bcache_stats *)args->statistics)->writebacks; + } + } + else if (args->stat_type == PROCESS_LIVE) { + if (!strcmp(args->stat_name, "blocks_read")) { + return ((struct process_stats *)args->statistics)->blocks_read; + } else if (!strcmp(args->stat_name, "blocks_written")) { + return ((struct process_stats *)args->statistics)->blocks_written; + } else if (!strcmp(args->stat_name, "bytes_read")) { + return ((struct process_stats *)args->statistics)->bytes_read; + } else if (!strcmp(args->stat_name, "bytes_written")) { + return ((struct process_stats *)args->statistics)->bytes_written; + } else if (!strcmp(args->stat_name, "syscall_count")) { + return ((struct process_stats *)args->statistics)->syscall_count[args->syscall_index]; + } + } + else if (args->stat_type == DRIVER_LIVE) { + if (!strcmp(args->stat_name, "blocks_read")) { + return ((struct device_driver_stats *)args->statistics)->blocks_read; + } else if (!strcmp(args->stat_name, "blocks_written")) { + return ((struct device_driver_stats *)args->statistics)->blocks_written; + } + } + else if (args->stat_type == SYSTEM_LIVE) { + if (!strcmp(args->stat_name, "time")) { + return ((struct system_stats *)args->statistics)->time; + } else if (!strcmp(args->stat_name, "blocks_read")) { + return ((struct system_stats *)args->statistics)->blocks_read[args->device_unit]; + } else if (!strcmp(args->stat_name, "blocks_written")) { + return ((struct system_stats *)args->statistics)->blocks_written[args->device_unit]; + } + } + + return -1; +} + +/* Create the graph template for the display */ +void create_graph(STAT_LIVE stat_type, char * stat_name, char * stat_arg, int window_width, int window_height, int plot_width, int plot_height, int thickness, int char_offset) { + /* Initialize Parameters */ + int i; + int x_offset = (window_width - plot_width) / 2; + int y_offset = (window_height - plot_height) / 2; + char title[100] = ""; + + stat_live_2_str(stat_type, title); + if (stat_arg != 0) { + strcat(title, ": "); + strcat(title, stat_arg); + } + + /* Draw border around window */ + draw_window(KNO_STDWIN); + draw_clear(0, 0, window_width, window_height); + draw_rect(0, 0, window_width, thickness); + draw_rect(0, 0, thickness, window_height); + draw_rect(window_width - thickness, 0, thickness, window_height); + draw_rect(0, window_height - thickness, window_width, thickness); + + /* Draw X, Y axis in center of window */ + draw_rect(x_offset, y_offset+plot_height, plot_width, thickness); + draw_rect(x_offset, y_offset, thickness, plot_height); + + /* Draw title, x_axis label, y_axis label */ + draw_string(window_width/2 - 70, 8, title); + draw_string(window_width/2 - 34, window_height - 16, "Time (6s)"); + + /* Setup Y axis */ + char y[2] = { 0 }; + for (i = 0; i < strlen(stat_name); i++) { + y[0] = stat_name[i]; + draw_string(10, window_height/2 - 20 + i*char_offset, y); + draw_flush(); + } + + /* For tick marks on x axis -- always keep the most recent minute - 10 ticks */ + int x_tick_width = plot_width/10; + for (i = 0; i < 10+1; i++) { + draw_rect(x_offset+i*x_tick_width, y_offset+plot_height, thickness, 6); + } + + /* For tick marks on y axis -- max will be dynamically set */ + int y_tick_width = plot_height/10; + for (i = 0; i < 10+1; i++) { + draw_rect(x_offset - 4, y_offset + plot_height - i * y_tick_width, 6, thickness); + } + + draw_flush(); +} + +/* Plot all of the points on the graph and print the max */ +void plot_bars(int most_recent_vals[POINTS], int max, int window_width, int window_height, int plot_width, int plot_height, int thickness, int char_offset) { + /* Clear the graph */ + int x_offset = (window_width - plot_width) / 2; + int y_offset = (window_height - plot_height) / 2; + draw_clear(x_offset, y_offset, plot_width+thickness, plot_height); + + /* Redraw the axis */ + draw_rect(x_offset, y_offset+plot_height, plot_width, thickness); + draw_rect(x_offset, y_offset, thickness, plot_height); + + /* Create string of the max */ + char max_str[32]; + uint_to_string((uint32_t) max, max_str); + draw_string(x_offset - 26, y_offset - 10, max_str); + draw_flush(); + + /* Plot the points */ + int i, current_point[2] = { 0 }; + + /* Variables to plot value in correct location on the graph */ + float x_step = (float)plot_width/POINTS; + float y_step = (float)plot_height/max; + + draw_color(0, 255, 0); + + for (i = 0; i < POINTS; i++) { + if (most_recent_vals[i] == -1) + continue; + + current_point[0] = x_offset + (int)(x_step*(i+1)); + current_point[1] = y_offset + plot_height - (int)(y_step*most_recent_vals[i]); + draw_rect(current_point[0], current_point[1], thickness, (int)(y_step*most_recent_vals[i])); + } + draw_flush(); + draw_color(255, 255, 255); +} + +/* Convert stat type to string */ +void stat_live_2_str(STAT_LIVE stat_l, char * str) { + + if (stat_l == BCACHE_LIVE) { + strcpy(str, "Bcache"); + } + else if (stat_l == PROCESS_LIVE) { + strcpy(str, "Process"); + } + else if (stat_l == DRIVER_LIVE) { + strcpy(str, "Driver"); + } + else if (stat_l == SYSTEM_LIVE) { + strcpy(str, "System"); + } +} + +/* Help message */ +void help() { + printf("\nusage\n\n"); + printf("statslive.exe\n"); + printf(" -h | --help # display help\n"); + printf(" -b # buffer cache stats\n"); + printf(" -dr # driver stats\n"); + printf(" -sys # system stats\n"); + printf(" -p # process stats\n"); + printf(" -sc # syscall number\n"); + printf(" -s # name of statistic\n"); + + printf("\nBuffercache STAT_NAME options:\n"); + printf(" read_hits\n"); + printf(" read_misses\n"); + printf(" write_hits\n"); + printf(" write_misses\n"); + printf(" writebacks\n\n"); + + printf("\nProcess STAT_NAME options:\n"); + printf(" blocks_read\n"); + printf(" blocks_written\n"); + printf(" bytes_read\n"); + printf(" bytes_written\n"); + printf(" syscall_count\n\n"); + + printf("\nDriver STAT_NAME options:\n"); + printf(" blocks_read\n"); + printf(" blocks_written\n\n"); + + printf("\nSystem STAT_NAME options:\n"); + printf(" time\n"); + printf(" blocks_read\n"); + printf(" blocks_written\n\n"); + + //TODO memory utilizations (page), kernel malloc + +} diff --git a/user/statworkload.c b/user/statworkload.c new file mode 100644 index 00000000..9b87f747 --- /dev/null +++ b/user/statworkload.c @@ -0,0 +1,55 @@ +#include "library/malloc.h" +#include "library/syscalls.h" +#include "library/string.h" +#include "library/user-io.h" + +/* + Continuously read files at random intervals to generate statistics +*/ + +int filereads() { + int fd[8]; + + char buffer[4096]; + int i, j; + int n, count = 0, mod = 7; + + while (1) { + for (i = 0; i < (count + mod) % mod; i++) { + fd[0] = syscall_open_file("bin/exectest.exe", 0, 0); + fd[1] = syscall_open_file("bin/long.exe", 0, 0); + fd[2] = syscall_open_file("bin/saver.exe", 0, 0); + for (j = 0; j < 3; j++) { + while((n = syscall_object_read(fd[j], buffer, 1024)) > 0) { + } + } + + syscall_object_close(fd[0]); + syscall_object_close(fd[1]); + syscall_object_close(fd[2]); + } + syscall_process_sleep(3000); + count++; + } +} + +int main(int argc, char const *argv[]) { + + if (argc < 2 || !strcmp(argv[1], "bcache")) { + filereads(); + } + else if (!strcmp(argv[1], "process")) { + filereads(); + } + else if (!strcmp(argv[1], "device_driver")) { + filereads(); + } + else if (!strcmp(argv[1], "system")) { + filereads(); + } + else { + filereads(); + } + + return 0; +}