CSS 430
FAQ on Program 4: Paging
Instructor: Munehiro Fukuda
Q1: Which version of Kernel.java should I use?
A: Download kernel_org.java or a new version of Kernel.java.
Download Kernel_org.java or a new version of Kernel.java, both of
which include a correct implementation of EXEC, EXIT, and WAIT. You
can download them from uw1-320 machines.
Q2: Is Cache.class a thread?
A: No, it is an ordinary Java class. Kernel instantiates one
Cache.class.
Kernel.java creates an instance of your Cache.java as an ordinary
Java object but not a thread.
cache = new Cache( disk.blockSize, 10 );
It gets to know that the disk block size is 512 bytes and the number
of cached blocks is 10. As you see Kernel.java, Kernel calls read,
write, sync, and flush methods of cache according to each request.
case CREAD: // to be implemented in assignment 4 return
cache.read( param, ( byte[] )args ) ? OK : ERROR;
Where param is a block number. What your Cache.java has to do is if
such a block is cached in Cache.java, it will copy the contents to
args upon a read( ) call, and will copy the contents of args to this
cached block upon a write( ) call.
Q3: How can I find which blocks are cached in Cache.java?
A: You should maintain an array or a Vector of 10 elements, each
including:
frame field: a cached block number
initialized to -1 (this means this frame is invalid.)
reference bit: set whenever this block is accessed and reset by
a second-chance algorithm
dirty bit: set whenever a write request occurs and reset when
this block is written back to the disk
Q4: What is the sequence of a cache read?
A: Here is a big hint:
- When a read( ) is called, first go through the array or the
Vector of 10 elements, each including a different cache block and
its block information, (i.e., frame#, reference and dirty bits.)
- If you find the corresponding block, (i.e., if the read( )'s first
argument matches the frame # of one of those elements,) simply
copies this element's data to the 2nd argument. The reference bit
is set, too. That's it.
- If you don't find the corresponding block, now you have to find
out an invalid element whose frame# is -1.
- If you don't find any invalid elements, then, you have to chose
a victim according to the 2nd-chance algorithm.
- If it is a victim and its dirty bit is 1, then, write back this
contents to the disk using disk.write( ). The dirty bit is reset.
- Now, you have to read the corresponding disk block from disk into
this freed element. Then, update this element's frame# with this
disk block#. The reference bit is set.
- Finally, copies this contents to the 2nd argument. That's it.
Q5: What is the sequence of the write?
A: Think about it by yourself!
Q6: What is the sequence of sync?
A: Write back all cached block to the disk. Clear a dirty bit. But
do not invalidate them.
Q7: What is the sequence of flush?
A: Write back all cached block to the disk. Clear both dirty and
reference bit. Invalidate all the cached blocks.
Q8: How should I check if my Cache is working
A; For all of the test, write meaningless data to the disk or the
cache and then compare what is on the disk or the cache to what I
just wrote.
Q9: How can I generate random accesses?
A: Use the Random class.
It generates a new random number by nextInt( ), which however can be a
negative integer. Use Math.abs( ) to get a positive integer and then
round it up using "% 512".
Q10: How can I round up using "% 512" or "% 10"?
A: See below:
import java.util.*;
Random r = new Random( );
Math.abs( r.nextInt( ) ) % 512;
Q11: How can I generate localized accesses?
A: You may just access only 10 blocks repeatedly.
Perform the following steps:
1. Create a byte array of 512 elements and fill it with meaningless data.
This array acts as a block of data.
2. Write the block of data created in step 1 to several blockIds that
are close together.
3. Read the same blocks that were just written to to see if their
contents are the same as the byte array created in step1.
Q12: How can I generate mixed accesses?
A: Use the Random class. Round it up using "% 10". If it is 0 to
8, you should go to localized accesses. If it is 9, you should go to
random accesses.
Q13: How can I generate adversary accesses?
A: Generate access patterns, each causes a cache miss.
This means that you have to choose a block number which has not been
chosen in the last 10 accesses. Also try to think about a very
pathetic situation where each access moves a disk head a lot for
example from track 0 to track 9. Note that blocks 0 to 99 belong
to track 0, blocks 100 to 199 belong to track 1, and so on.
Q14: My adversary accesses ran a bit faster than the random accesses.
What's wrong?
A: Your adversary accesses didn't move a disk head frequently.
See the answer to Q13.
Q15: How many time should I call cread( ) and cwrite( ) in total.
A: 200 creads and 200 cwrites for each test may be enough to see
differences between cache enabled and disabled.
Q16: Should we track the amount of time each write takes and sum
them together? Then do this again for the reads? Or can we just give
the total amount of time it took to complete both the reads/writes?
A: What you can do is:
measure the total amount of time elapsed for for 200 writes and for
200 reads, and calculate the average time for a write and for a write
by dividing the measured time by 200.
Q17: Why do we need csync?
A: Test4.java should call csync at its very end.
Your disk operation may remain in your Cache.java but not be yet
reflected to Disk.java even after you get finished with
Test4.java. Test4.java should call csync at its very end.
Q18: Why do we need cflush?
A: Every time you start a new test, you have to flush out cached
block.
If you conduct another test before stopping ThreadOS, your Cache may
still cache some Disk blocks. This is unfair for the following
tests. Thus, every time you start a new test, you have to flush out
cached block.
Q19: Should write( ) and read( ) in Cache.java be synchronized?
A: Yes.
Q20: If each method in Cache.java use "synchronized", there appear
some drawback.
Using a "synchronized" method, only one thread could be active in the
Cache at a time. This would be bad when the Cache has to read from the
disk itself, which could take a long time, the running thread would be
put to sleep, letting other threads execute, but they wouldn't be able
to read or write because the lock would still be held.
A: You're right.
Although this synchronization deteriorate the performance, the effect
of cache hits will beat such synchronization drawback. Thus, in total,
performance will be improved.
Q21: Should I run Test4.java from the shell?
A: You don't have to. You may run your Test4.java from the loader.
% java Boot
-->l Test4 arg0 arg1
Q22: I'm running into a methodNotFound exception when I run Test4,
any ideas?
public class TestThread4 extends Thread
{
...
private byte[] buffer = new byte[512];
public void TestThread4(String args[])
{
...
A: The constructor should not return any value.
Your TestThread4 construct should be:
public TestThread4( ) or
public TestThread4( String args[] )
Q23: Why cannot my buffer be passed to SysLib.cwrite( )
byte [] buffer = new byte[512];
String str;
str = "Block Number " + block+"\n";
buffer = str.getBytes();
SysLib.rawwrite(block,buffer);
A: Your buffer[] has been corrupted before passed to SysLib.write
( ).
Be reminded that a Java assignment only substitutes the left-hand-side
variable with a pointer to the right-hand-side variable. In the above
example, buffer was originally assigned a 512-byte data but was
substituted with a pointer to the str variable whose size is much less
than 512 bytes.