Sure. I have provided the file refstats.txt, (also linked on the main assignments page), which gives the output of the "vm" menu command for sort and matmult using random and LRU replacement.
If you cannot run your own experiments, you can discuss the data given here in your lab notebook, referring to the memory reference behavior of these two programs, and the clock and random replacement algorithms.
For your own experiments, you should try varying other parameters, such as the amount of physical memory and the data set size used by the test programs. (If you cannot run your own experiments, discuss what you would expect to happen as the amount of physical memory, and the data set of these programs increases, and why).
You need to (at minimum) provide a proper writeup of your performance experiments. It is a good idea to put this in context by explaining how you implemented random page replacement and your approximation of LRU page replacement.
The most likely cause is that your swap disk isn't large enough for some of these test programs. If you look around, you will see that a process now gets 512 pages for its user-level stack (USERSTACKSIZE in arch/mips/include/vm.h), swap space for all of them must be reserved when the address space is created (see as_define_stack and trace it down to vm_object_create). However, the default 5 MB disk only has room to store 1280 pages, so any time you try to create more than 2 processes you will have trouble.
To fix this:
2 disk rpm=7200 sectors=10240 file=DISK1.img
to:
2 disk rpm=7200 sectors=102400 file=DISK1.img
If you look at what coremap_alloc_one_page (called by coremap_allocuser) does when there are no free pages to allocate, you will see that it calls do_page_replace. That function is the start of the page replacement code. There are two things that do_page_replace should do: (1) select a victim, and (2) evict it. The first will be handled by one of your two implementations of page_replace (either random or LRU-like), the second will be handled by do_evict. So the argument "where" to do_evict is the index of the coremap entry for the physical page to evict. In other words, the value returned by page_replace. The do_evict function is responsible for actually evicting the selected page, and lpage_evict will help with that.
If the page being evicted has an entry in the tlb, you will have to invalidate that entry. But, you are right, you do not have the information that mmu_unmap needs to do this. When you choose a physical page to evict using the coremap, you can get a pointer to the lpage that maps it, but you cannot recover the address space that lpage is part of, or the virtual address it corresponds to, so you cannot use mmu_unmap from lpage_evict to do this. I made a mistake yesterday when I told you to use only the mmu_* functions and not use the tlb functions directly.
You should use tlb_invalidate when you need to remove an entry from the tlb due to eviction. You should still use mmu_map to add an entry to the TLB when you handle a page fault.
The interface to physical structures (RAM or Memory Management Unit and the TLB) is all in coremap.c -- the things you can call from other files are all defined in coremap.h. The functions that begin "mmu_" in coremap.h are the interface to the MMU that you should be using (remember, the TLB is a part of the MMU). These functions call the internal "tlb_" functions in coremap.c. Make sure you understand what each of the mmu functions is for.
Updating TLB entries in dumbvm.c is pretty bad - a process cannot have more than 64 pages since there is no TLB replacement strategy - once the TLB entries are all filled, dumbvm can't handle the page fault. All of this TLB handling is now provided in coremap.c through the mmu_ functions.
#define LP_SET(am, bit) ((lp)->lp_paddr |= (bit))
#define LP_CLEAR(am, bit) ((lp)->lp_paddr &= ~(paddr_t)(bit))
Yes, it should be 'lp' instead of 'am' in the macro. These macros are very poorly-written (oddly, no one has flagged them before!). The first argument is ignored (not used) and the macro is always applied to the variable named "lp" in the enclosing scope. It works, as long as you really do want to set/clear bits in the lp_paddr field of a variable named lp (as in, for example the lpage_lock function in lpage.c). If you had two lpages, say lp and lp2 and you did LP_SET(lp2, LPF_DIRTY), it would not work properly -- it would set the bit in lp, even though you wanted lp2. Yuck.
You should change these to:
#define LP_SET(lp, bit) ((lp)->lp_paddr |= (bit))
#define LP_CLEAR(lp, bit) ((lp)->lp_paddr &= ~(paddr_t)(bit))
OS/161 kernel [? for menu]: p sbin/reboot
sleep: Dropping thread
panic: Assertion failed: lock != NULL, at ../../thread/synch.c:139 (lock_acquire)
...
What gives? You have to modify main.c to bootstrap the swap system. The new vm_bootstrap function now returns the size of main memory, which you need to pass to swap_bootstrap. Also, swap relies on the disk device, and the vfs layer, so both these things need to be bootstrapped first. Use this in your main.c file:
int memsize = vm_bootstrap();
scheduler_bootstrap();
pid_bootstrap(); // DEMKE: initialize pid management before threads
thread_bootstrap();
vfs_bootstrap();
dev_bootstrap();
swap_bootstrap(memsize);
Sorry... that was a mistake. The assignment page has been updated with more information. Briefly, you would need to unpack the sys161 simulator code, but it isn't critical that you look at how the simulated hardware generates TLB exceptions.
Start with the tutorial notes from last week (they are posted on the Tutorials page). Remember when you look at the code that anything between "#if DUMBVM" ... "#endif" is NOT included when you build the kernel now.
There are three things you need to understand (very broadly speaking).
I think the best way to start is to compile the kernel and run it with the debugger. Set a breakpoint at vm_fault, and then try to run a user program with the "p" command - any user program will do, but for simplicity, try just using the "sbin/reboot" program. Use the debugger to step through what happens as vm_fault calls as_fault, and as_fault calls other functions. (You might also want to stop earlier and look at as_create, as_define_region, etc. to see how the address space is initialized in preparation for loading a program). For the first access to a page, when there are free memory pages still available (without needing to evict anything), most of the work is already done. At the end of as_fault, however, is a call to lpage_fault, which is not implemented. Think about what still has to be done to finish handling the page fault.