diff --git a/vm-beyondphys/Makefile b/vm-beyondphys/Makefile new file mode 100644 index 00000000..0d3f60f8 --- /dev/null +++ b/vm-beyondphys/Makefile @@ -0,0 +1,6 @@ + +all: mem + +mem: mem.c + gcc -o mem mem.c -Wall -O + diff --git a/vm-beyondphys/README.md b/vm-beyondphys/README.md new file mode 100644 index 00000000..a3a5b568 --- /dev/null +++ b/vm-beyondphys/README.md @@ -0,0 +1,97 @@ + +# Overview + +In this homework, you'll be investigating swap performance with a simple +program found in `mem.c`. The program is really simple: it just allocates an +array of integers of a certain size, and then proceeds to loop through it +(repeatedly), incrementing each value in the array. + +Type `make` to build it (and look at the file `Makefile` for details about how +the build works). + +Then, type `./mem` followed by a number to run it. The number is the size (in +MB) of the array. Thus, to run with a small array (size 1 MB): + +```sh +prompt> ./mem 1 +``` + +and to run with a larger array (size 1 GB): + +```sh +prompt> ./mem 1024 +``` + +The program prints out the time it takes to go through each loop as well as +the bandwidth (in MB/s). Bandwidth is particularly interesting to know as it +gives you a sense of how fast the system you're using can move through data; +on modern systems, this is likely in the GB/s range. + +Here is what the output looks like for a typical run: + +```sh +prompt> ./mem 1000 +allocating 1048576000 bytes (1000.00 MB) + number of integers in array: 262144000 +loop 0 in 448.11 ms (bandwidth: 2231.61 MB/s) +loop 1 in 345.38 ms (bandwidth: 2895.38 MB/s) +loop 2 in 345.18 ms (bandwidth: 2897.07 MB/s) +loop 3 in 345.23 ms (bandwidth: 2896.61 MB/s) +^C +prompt> +``` + +The program first tells you how much memory it allocated (in bytes, MB, and in +the number of integers), and then starts looping through the array. The first +loop (in the example above) took 448 milliseconds; because the program +accessed the 1000 MB in just under half a second, the computed bandwidth is +(not surprisingly) just over 2000 MB/s. + +The program continues by doing the same thing over and over, for loops 1, 2, +etc. + +Important: to stop the program, you must kill it. This task is accomplished on +Linux (and all Unix-based systems) by typing control-C (^C) as shown above. + +Note that when you run with small array sizes, each loop's performance numbers +won't be printed. For example: + +```sh +prompt> ./mem 1 +allocating 1048576 bytes (1.00 MB) + number of integers in array: 262144 +loop 0 in 0.71 ms (bandwidth: 1414.61 MB/s) +loop 607 in 0.33 ms (bandwidth: 3039.35 MB/s) +loop 1215 in 0.33 ms (bandwidth: 3030.57 MB/s) +loop 1823 in 0.33 ms (bandwidth: 3039.35 MB/s) +^C +prompt> +``` + +In this case, the program only prints out a sample of outputs, so as not to +flood the screen with too much output. + +The code itself is simple to understand. The first important part is a memory +allocation: + +```c + // the big memory allocation happens here + int *x = malloc(size_in_bytes); +``` + +Then, the main loop begins: + +```c + while (1) { + x[i++] += 1; // main work of loop done here. +``` + + +The rest is just timing and printing out information. See `mem.c` for details. + +Much of the homework revolves around using the tool vmstat to monitor what is +happening with the system. Read the vmstat man page (type `man vmstat`) for +details on how it works, and what each column of output means. + + + diff --git a/vm-beyondphys/mem.c b/vm-beyondphys/mem.c new file mode 100644 index 00000000..b0b2d190 --- /dev/null +++ b/vm-beyondphys/mem.c @@ -0,0 +1,67 @@ +#include +#include +#include +#include +#include + +// Simple routine to return absolute time (in seconds). +double Time_GetSeconds() { + struct timeval t; + int rc = gettimeofday(&t, NULL); + assert(rc == 0); + return (double) ((double)t.tv_sec + (double)t.tv_usec / 1e6); +} + +// Program that allocates an array of ints of certain size, +// and then proceeeds to update each int in a loop, forever. +int main(int argc, char *argv[]) { + if (argc != 2) { + fprintf(stderr, "usage: spin \n"); + exit(1); + } + long long int size = (long long int) atoi(argv[1]); + long long int size_in_bytes = size * 1024 * 1024; + + printf("allocating %lld bytes (%.2f MB)\n", + size_in_bytes, size_in_bytes / (1024 * 1024.0)); + + // the big memory allocation happens here + int *x = malloc(size_in_bytes); + if (x == NULL) { + fprintf(stderr, "memory allocation failed\n"); + exit(1); + } + + long long int num_ints = size_in_bytes / sizeof(int); + printf(" number of integers in array: %lld\n", num_ints); + + // now the main loop: each time through, touch each integer + // (and increment its value by 1). + int i = 0; + double time_since_last_print = 2.0; + double t = Time_GetSeconds(); + int loop_count = 0; + while (1) { + x[i++] += 1; // main work of loop done here. + + // if we've gone through the whole loop, reset a bunch of stuff + // and then (perhaps) print out some statistics. + if (i == num_ints) { + double delta_time = Time_GetSeconds() - t; + time_since_last_print += delta_time; + if (time_since_last_print >= 0.2) { // only print every .2 seconds + printf("loop %d in %.2f ms (bandwidth: %.2f MB/s)\n", + loop_count, 1000 * delta_time, + size_in_bytes / (1024.0*1024.0*delta_time)); + time_since_last_print = 0; + } + + i = 0; + t = Time_GetSeconds(); + loop_count++; + } + } + + return 0; +} +