This is an individual or group project, at your choice. You may collaborate with anybody else and search the web, as long as all the code and results you turn in are authored by you personally. You may use any libraries that are part of the standard Minix distribution.
The project is due Monday, October 18th 2004, any time. Submission is by email. Please send me the following:
Please send in your project on time -- late submissions will not be accepted, and I prefer to have partially-working projects rather than no project at all.
As usual, you are welcome to study any materials on the web.
I want you to start with the stock kernel distributed with Minix, i.e. not your enhanced Minix from project 3. I want you to measure how long it takes to:
These times will, of course, depend on the architecture that you are running, so in your status file be sure to summarize your architecture (simulation, if so on what system (processor/speed), or real hardware, and if so what hardware (processor/speed)).
I want you to write a simple test program to call time(2) repeatedly, with a NULL argument, until 10 seconds have passed from the first transition (a transition is when the result of the call to time(2) changes). You should run this program on an unloaded system and report how many calls/second you can make (you can have your program print out the number of calls per second, but your program should run for at least 10 seconds to average out any temporary variations). Result 1: system calls/second and seconds/system call. Your instructor's result, on a Pentium II/233MHz, is 64,730 system calls/second, so about 15us (15 microseconds) per system call.
Then, insert a loop which simply counts up from zero to 999 immediately after each call to time(2). If you have multiple calls to time(2), create a new function (my_time is a good name) that calls time(2), then loops 1000 times. Print out the number of system calls per second, and perform a little math (which you have to figure out exactly) to compute how long it takes to loop 1000 times. Result 2: time to loop 1000 times. Your instructor's result is 30us (30 microseconds) to loop 1000 times.
Then, benchmark how long it takes to make the kernel. Simply type "make clean" in your tools directory, followed by "time make". Many people use compilation of a large program as a benchmark for the performance of an overall hardware/system/compiler combination, since it requires good performance from the CPU, the disk subsystem, the operating system, and the compiler, and it captures tradeoffs between compilation time (which is better when the compiler is simpler) and execution time (which is usually better when the compiler is more advanced). Result 3: time (real, user, and sys) to recompile your kernel. Your instructor's result is 1:16 (1 minute, 16s) real time, 10.16s user time, 5.55 system time (for your pondering: where did the rest of the real time go? 5.55s+10.16s = 16.71s < 76s of real time).
Now artificially slow down your kernel by adding to the beginning of your sys_call (in kernel/proc.c) a loop which loops 1000 times. Result 4: results 1, 2, and 3 after adding this delay, and your best explanation of the difference between result 1 and the result after slowing down the kernel. Undo this kernel slowdown code after recording your results and before continuing your tests.
Finally, measure how long it takes to open a file, write 1,000,000 bytes to it, and close it (use open(2), write(2), and close(2)). There should be 1,000 write operations, each writing 1,000 bytes. Write the file to the RAM disk first (mount the RAM disk, then choose a file in /mnt -- you may have to mkfs /dev/ram first), then the hard disk (choose a file in /usr), finally to the floppy disk (you may have to insert an empty floppy disk so there is plenty of room, and you will have to mount it under /mnt). Results 5, 6, and 7: time to write 1,000,000 bytes to RAM disk, hard disk, and floppy disk.
Remember to run all these tests on an otherwise unloaded system.
It may be a good idea to automatically remove (unlink(2)) the 1-megabyte files you have created as soon as you have measured the time to open/write/close the file.
If you are interested, you can also benchmark the time to read a file. However, if you read immediately after writing, many of the file contents may still be in memory buffers, so you may have to read a file other than the one you just wrote.
As another variant, you could try running two copies of your test program in parallel, and see if you get approximately half the performance for each or if the performance is dramatically different for the two. Notice that most floppies are not big enought to store two 1,000,000 files.
If you have another OS running on your same hardware, you could try running the same or similar tests to see how much difference the compiler/OS makes. If you have completed the required parts of this project, you should feel free to post results of this last test to the mailing list (e.g. "minix (or: minix system call) is twice as fast/slow as X running on the same hardware"). A particularly interesting comparison might be writing to floppy disk, since floppy disk drives are likely to be essentially equivalent across systems, so performance should be comparable (but probably isn't). Again, the mailing list might be a good place for results of this kind.
You can also compare your code to itself. For example, does the time to perform any of the above change when you compile your benchmarking program with an optimization flag (-O) to the compiler? Is the file writing any faster (or slower) when you write the same amount of data in blocks of 1,024 rather than 1,000 bytes?