#! /bin/sh
# This is a shell archive.  Remove anything before this line, then unpack
# it by saving it into a file and typing "sh file".  To overwrite existing
# files, type "sh file -c".  You can also feed this as standard input via
# unshar, or by typing "sh <file", e.g..  If this archive is complete, you
# will see the following message at the end:
#		"End of shell archive."
# Contents:  cdiffs.fs convert.c driver.c makefile notes prog.sty
#   random.c sim.h tabulate
# Wrapped by mike@client25.comlab on Thu Jun 11 12:51:46 1992
PATH=/bin:/usr/bin:/usr/ucb ; export PATH
if test -f cdiffs.fs -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"cdiffs.fs\"
else
echo shar: Extracting \"cdiffs.fs\" \(10339 characters\)
sed "s/^X//" >cdiffs.fs <<'END_OF_cdiffs.fs'
X*** /usr/src/fs/buf.h	Wed Jan 22 09:32:16 1992
X--- buf.h	Wed Jan 22 14:18:49 1992
X***************
X*** 31,36 ****
X--- 31,37 ----
X    dev_t b_dev;			/* major | minor device where block resides */
X    char b_dirt;			/* CLEAN or DIRTY */
X    char b_count;			/* number of users of this buffer */
X+   int b_request;	        /* last param to get_block */
X  } buf[NR_BUFS];
X  
X  /* A block is free if b_dev == NO_DEV. */
X*** /usr/src/fs/cache.c	Tue Nov  5 13:42:13 1991
X--- cache.c	Wed Jan 22 14:17:25 1992
X***************
X*** 21,26 ****
X--- 21,28 ----
X  #include "inode.h"
X  #include "super.h"
X  
X+ PRIVATE void trace_block();
X+ 
X  /*===========================================================================*
X   *				get_block				     *
X   *===========================================================================*/
X***************
X*** 55,61 ****
X  			/* Block needed has been found. */
X  			if (bp->b_count == 0) bufs_in_use++;
X  			bp->b_count++;	/* record that block is in use */
X! 			return(bp);
X  		} else {
X  			/* This block is not the one sought. */
X  			bp = bp->b_hash; /* move to next block on hash chain */
X--- 57,63 ----
X  			/* Block needed has been found. */
X  			if (bp->b_count == 0) bufs_in_use++;
X  			bp->b_count++;	/* record that block is in use */
X! 			goto got_bp;
X  		} else {
X  			/* This block is not the one sought. */
X  			bp = bp->b_hash; /* move to next block on hash chain */
X***************
X*** 92,98 ****
X    /* If the block taken is dirty, make it clean by writing it to the disk.
X     * Avoid hysterisis by flushing all other dirty blocks for the same device.
X     */
X!   if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
X  
X    /* Fill in block's parameters and add it to the hash chain where it goes. */
X    bp->b_dev = dev;		/* fill in device number */
X--- 94,100 ----
X    /* If the block taken is dirty, make it clean by writing it to the disk.
X     * Avoid hysterisis by flushing all other dirty blocks for the same device.
X     */
X!   if (bp->b_dev != NO_DEV && bp->b_dirt != CLEAN) flushall(bp->b_dev);
X  
X    /* Fill in block's parameters and add it to the hash chain where it goes. */
X    bp->b_dev = dev;		/* fill in device number */
X***************
X*** 104,109 ****
X--- 106,115 ----
X  
X    /* Go get the requested block unless searching or prefetching. */
X    if (dev != NO_DEV && only_search == NORMAL) rw_block(bp, READING);
X+ 
X+ got_bp:
X+   bp->b_request = only_search;
X+   if (bp->b_dirt == DIRTY) bp->b_dirt = SOILED;
X    return(bp);			/* return the newly acquired block */
X  }
X  
X***************
X*** 128,133 ****
X--- 134,141 ----
X  
X    if (bp == NIL_BUF) return;	/* it is easier to check here than in caller */
X  
X+   trace_block(bp, block_type);
X+ 
X    /* If block is no longer in use, first remove it from LRU chain. */
X    bp->b_count--;		/* there is one use fewer now */
X    if (bp->b_count != 0) return;	/* block is still in use */
X***************
X*** 178,184 ****
X     * should be written to the disk immediately to avoid messing up the file
X     * system in the event of a crash.
X     */
X!   if ((block_type & WRITE_IMMED) && bp->b_dirt==DIRTY && bp->b_dev != NO_DEV)
X  	rw_block(bp, WRITING);
X  
X    /* Super blocks must not be cached, lest mount use cached block. */
X--- 186,192 ----
X     * should be written to the disk immediately to avoid messing up the file
X     * system in the event of a crash.
X     */
X!   if ((block_type & WRITE_IMMED) && bp->b_dirt!=CLEAN && bp->b_dev != NO_DEV)
X  	rw_block(bp, WRITING);
X  
X    /* Super blocks must not be cached, lest mount use cached block. */
X***************
X*** 306,312 ****
X    int ndirty;
X  
X    for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++)
X! 	if (bp->b_dirt == DIRTY && bp->b_dev == dev) dirty[ndirty++] = bp;
X    rw_scattered(dev, dirty, ndirty, WRITING);
X  }
X  
X--- 314,320 ----
X    int ndirty;
X  
X    for (bp = &buf[0], ndirty = 0; bp < &buf[NR_BUFS]; bp++)
X! 	if (bp->b_dirt != CLEAN && bp->b_dev == dev) dirty[ndirty++] = bp;
X    rw_scattered(dev, dirty, ndirty, WRITING);
X  }
X  
X***************
X*** 392,394 ****
X--- 400,439 ----
X    }
X  #endif
X  }
X+ 
X+ #define TRACES_PER_BLOCK 256
X+ #define MAX_TRACE 512 /* Max no of blocks of trace info */
X+ 
X+ static struct {
X+   block_nr bb_blocknr;
X+   unshort  bb_flags;
X+ } trace_buf[TRACES_PER_BLOCK];
X+ static int n_traces, trace_blk;
X+ 
X+ #define TRACE_DEV 0x200 /* fd0 */
X+ 
X+ #define NOREAD_BIT 0400 /* cf. WRITE_IMMED in buf.h */
X+ #define DIRTY_BIT 01000
X+ 
X+ PRIVATE void trace_block(bp, block_type)
X+ struct buf *bp;
X+ int block_type;
X+ {
X+    if (bp->b_request == PREFETCH) return;
X+ 
X+    trace_buf[n_traces].bb_blocknr = bp->b_blocknr;
X+    trace_buf[n_traces].bb_flags =
X+ 	block_type | (bp->b_request == NO_READ) * NOREAD_BIT
X+ 	| (bp->b_dirt == DIRTY) * DIRTY_BIT;
X+    n_traces++;
X+ 
X+    if (n_traces == TRACES_PER_BLOCK) {
X+ 	if (trace_blk < MAX_TRACE) {
X+ 		printf("[%d]%c", trace_blk, 0);
X+ 		dev_io(WRITING, FALSE, TRACE_DEV,
X+ 		       (off_t) trace_blk++ * BLOCK_SIZE,
X+ 		       BLOCK_SIZE, FS_PROC_NR, trace_buf);
X+ 	}
X+ 	n_traces = 0;
X+    }
X+ }
X*** /usr/src/fs/const.h	Tue Nov  5 13:42:14 1991
X--- const.h	Wed Jan 22 14:19:44 1992
X***************
X*** 30,35 ****
X--- 30,36 ----
X  
X  #define CLEAN              0	/* disk and memory copies identical */
X  #define DIRTY              1	/* disk and memory copies differ */
X+ #define SOILED		   2    /* was dirty, not yet cleaned */
X  #define ATIME            002	/* set if atime field needs updating */
X  #define CTIME            004	/* set if ctime field needs updating */
X  #define MTIME            010	/* set if mtime field needs updating */
X*** /usr/src/fs/misc.c	Tue Nov  5 13:42:17 1991
X--- misc.c	Wed Jan 22 14:17:26 1992
X***************
X*** 141,147 ****
X  
X    /* Write all the dirty blocks to the disk, one drive at a time. */
X    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
X! 	if (bp->b_dev != NO_DEV && bp->b_dirt == DIRTY) flushall(bp->b_dev);
X  
X    return(OK);		/* sync() can't fail */
X  }
X--- 141,147 ----
X  
X    /* Write all the dirty blocks to the disk, one drive at a time. */
X    for (bp = &buf[0]; bp < &buf[NR_BUFS]; bp++)
X! 	if (bp->b_dev != NO_DEV && bp->b_dirt != CLEAN) flushall(bp->b_dev);
X  
X    return(OK);		/* sync() can't fail */
X  }
X*** /usr/src/fs/read.c	Tue Nov  5 13:42:20 1991
X--- read.c	Wed Jan 22 14:17:27 1992
X***************
X*** 374,481 ****
X   * Rw_scattered() puts an optional flag on all reads to allow this.
X   */
X  
X!   block_nr block;
X!   unsigned blocks_ahead;
X!   unsigned blocks_per_track;
X!   register struct buf *bp;
X!   int block_spec;
X!   dev_t dev;
X!   off_t dev_size;
X!   off_t file_size;
X!   unsigned fragment;
X!   unsigned limit_bufs_in_use;
X!   unsigned max_track;
X!   int reading_ahead;
X!   static struct buf *read_q[NR_BUFS];	/* static so it isn't on stack */
X!   int read_q_size;
X!   unsigned track;
X  
X    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
X    if (block_spec)
X  	dev = (dev_t) rip->i_zone[0];
X    else
X  	dev = rip->i_dev;
X!   bp = get_block(dev, baseblock, PREFETCH);
X!   if (bp->b_dev != NO_DEV) return(bp);
X! 
X!   /* Guesstimate blocks_per_track.  A bad guess will work but be sub-optimal.
X!    * Dev_open may eventually do it properly.
X!    */
X!   if (block_spec)
X! 	dev_size = rip->i_size;
X!   else
X! #if (MACHINE == ATARI)
X! 	dev_size =  80L * 2 * 9 * 512;	/* can be 80L*1*9*512 as well */
X! #else
X! 	dev_size =  80L * 2 * 15 * 512;	/* change to your usual floppy size */
X! #endif
X!   if (dev_size == 0)
X! 	blocks_per_track = 17;	/* hard disk (17 * nr_heads / 2 is too many) */
X!   if (dev_size < 80L * 2 * 15 * 512)
X! 	blocks_per_track = 9;	/* low-density floppy */
X!   else if (dev_size < 80L * 2 * 18 * 512)
X! 	blocks_per_track = 15;	/* high-density floppy */
X!   else
X! 	blocks_per_track = 18;	/* higher-density floppy */
X! 
X!   file_size = rip->i_size;
X!   if (block_spec && file_size == 0) file_size = MAX_P_LONG;
X!   fragment = (unsigned) (position % BLOCK_SIZE);
X!   position = position - fragment + BLOCK_SIZE;
X!   blocks_ahead = (fragment + bytes_ahead + BLOCK_SIZE - 1) / BLOCK_SIZE - 1;
X! 
X!   /* Set the limit (max + 1) on buffers used. Avoid taking the last 2 buffers
X!    * for ordinary files, because the cache will thrash if these are needed
X!    * for indirect blocks.  There is no point in stopping earlier for the
X!    * immediately-needed part of the read.  Large reads will evict from the
X!    * cache all blocks except those for the read and the indirect blocks, no
X!    * matter what is done here.
X!    */
X!   limit_bufs_in_use = block_spec ? NR_BUFS : NR_BUFS - 2;
X! 
X!   max_track = bp->b_blocknr / blocks_per_track;
X!   reading_ahead = FALSE;
X!   read_q[0] = bp;		/* first buffer must be read */
X!   read_q_size = 1;
X! 
X!   /* The next loop has 2 phases, controlled by 'reading_ahead'. */
X!   while (TRUE) {
X! 	if (position >= file_size || bufs_in_use >= limit_bufs_in_use) break;
X!   	if (blocks_ahead != 0)
X! 		--blocks_ahead;
X! 	else {
X! 		/* All the immediately-needed blocks have been read.  Give
X! 		 * up after seeks and partial reads.
X! 		 */
X! 		if (reading_ahead || rip->i_seek == ISEEK ||
X! 		    (fragment + bytes_ahead) % BLOCK_SIZE != 0) break;
X! 
X! 		/* Try for more blocks on the last "track".  Try a few more
X! 		 * than 'blocks_per_track' to allow for blocks out of order.
X! 		 * Reducing 'limit_bufs_in_use' here might reduce thrashing.
X! 		 */
X! 		blocks_ahead = blocks_per_track + 6;
X! 		reading_ahead = TRUE;
X!   	}
X! 	if (block_spec)
X! 		block = position / BLOCK_SIZE;
X! 	else
X! 		block = read_map(rip, position);
X! 	position += BLOCK_SIZE;
X! 	track = block / blocks_per_track;
X! 	if (reading_ahead) {
X! 		if (track != max_track) continue;
X! 	} else {
X! 		if (track > max_track) max_track = track;
X! 	}
X! 	if (block_spec || block != NO_BLOCK) {
X! 		bp = get_block(dev, block, PREFETCH);
X! 		if (bp->b_dev == NO_DEV)
X! 			read_q[read_q_size++] = bp;
X! 		else
X! 			put_block(bp, FULL_DATA_BLOCK);
X! 	}
X!   }
X!   rw_scattered(dev, read_q, read_q_size, READING);
X!   return(get_block(dev, baseblock, NORMAL));
X! }
X--- 374,386 ----
X   * Rw_scattered() puts an optional flag on all reads to allow this.
X   */
X  
X!   int block_spec;
X!   dev_t dev;
X  
X    block_spec = (rip->i_mode & I_TYPE) == I_BLOCK_SPECIAL;
X    if (block_spec)
X  	dev = (dev_t) rip->i_zone[0];
X    else
X  	dev = rip->i_dev;
X!   return(get_block(dev, baseblock, NORMAL));
X! }
END_OF_cdiffs.fs
if test 10339 -ne `wc -c <cdiffs.fs`; then
    echo shar: \"cdiffs.fs\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f convert.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"convert.c\"
else
echo shar: Extracting \"convert.c\" \(1560 characters\)
sed "s/^X//" >convert.c <<'END_OF_convert.c'
X/* convert -- convert cache trace to readable form */
X
X#include <stdio.h>
X#include <minix/type.h>
X
X/* From buf.h: */
X
X#define WRITE_IMMED        0100	/* block should be written to disk now */
X#define ONE_SHOT           0200	/* set if block not likely to be needed soon */
X
X#define INODE_BLOCK       (0 + MAYBE_WRITE_IMMED)	 /* inode block */
X#define DIRECTORY_BLOCK   (1 + MAYBE_WRITE_IMMED)	 /* directory block */
X#define INDIRECT_BLOCK    (2 + MAYBE_WRITE_IMMED)	 /* pointer block */
X#define I_MAP_BLOCK       (3 + WRITE_IMMED + ONE_SHOT)	 /* inode bit map */
X#define ZMAP_BLOCK        (4 + WRITE_IMMED + ONE_SHOT)	 /* free zone map */
X#define ZUPER_BLOCK       (5 + WRITE_IMMED + ONE_SHOT)	 /* super block */
X#define FULL_DATA_BLOCK    6		 	 	 /* data, fully used */
X#define PARTIAL_DATA_BLOCK 7 				 /* data, partly used*/
X
X#define NOREAD_BIT 0400 /* cf. WRITE_IMMED in buf.h */
X#define DIRTY_BIT 01000
X
X#define BLOCK_SIZE 1024
X#define TRACES_PER_BLOCK 256
X
Xstatic struct trace {
X  block_nr bb_blocknr;
X  unshort  bb_flags;
X} trace_buf;
X
Xmain(argc, argv)
Xint argc;
Xchar **argv;
X{
X     unshort flags;
X     FILE *fp;
X
X     if (argc != 2) {
X	  fprintf(stderr, "usage: convert file\n");
X	  exit(2);
X     }
X
X     fp = fopen(argv[1], "r");
X     if (fp == NULL) {
X	  perror(argv[1]);
X	  exit(1);
X     }
X
X     for (;;) {
X	  if (fread(&trace_buf, sizeof(struct trace), 1, fp) == 0)
X	       break;
X	  flags = trace_buf.bb_flags;
X	  printf("%c %u\n",
X		 ((flags & DIRTY_BIT) == 0 ? 'R'
X		  : (flags & NOREAD_BIT) == 0 ? 'W' : 'Z'),
X		 trace_buf.bb_blocknr);
X     }
X}
END_OF_convert.c
if test 1560 -ne `wc -c <convert.c`; then
    echo shar: \"convert.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f driver.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"driver.c\"
else
echo shar: Extracting \"driver.c\" \(1512 characters\)
sed "s/^X//" >driver.c <<'END_OF_driver.c'
X/* driver.c -- buffer cache simulation driver */
X
X#include "sim.h"
X#include <stdio.h>
X#include <ctype.h>
X
XPUBLIC int nbuffs, nreads, nwrites, nactions;
X
X/* simulation -- do the simulation */
XPRIVATE void simulation(fp)
XFILE *fp;
X{
X     char act;
X     int block;
X     int action;
X
X     init_cache();
X
X     while (TRUE) {
X	  if (fscanf(fp, "%1s %u", &act, &block) < 2) 
X	       break;
X	  
X	  switch (act) {
X	  case 'R':
X	       action = READ; 
X	       break;
X
X	  case 'W': 
X	       action = WRITE; 
X	       break;
X
X	  case 'Z': 
X	       action = NEW; 
X	       break;
X
X	  default:  
X	       panic("bad action char");
X	  }
X	  
X	  nactions++;
X	  use_block(action, block);
X     }
X
X     do_sync();
X}
X
X
X/* print_results -- print one line of statistics */
XPUBLIC void print_results()
X{
X     printf("%8s%8d%8d%8d%8d%8d\n",
X	    policy, nbuffs, nactions, nreads,
X	    nwrites, nreads+nwrites);
X}
X
XPUBLIC int main(argc, argv)
Xint argc;
Xchar **argv;
X{
X     FILE *fp;
X
X     if (argc != 3 || ! isdigit(*argv[1])) {
X	  fprintf(stderr, "Usage: %s cache-size data-file\n", argv[0]);
X	  exit(2);
X     }
X
X     nbuffs = atoi(argv[1]);
X     if (nbuffs <= 0) 
X	  nbuffs = 1;
X     if (nbuffs > MAXBUFS) 
X	  panic("too many buffers");
X
X     fp = fopen(argv[2], "r");
X     if (fp == NULL) {
X	  perror(argv[2]);
X	  exit(1);
X     }
X
X     simulation(fp);
X     print_results();
X     return 0;
X}
X
X/* panic -- print a message and exit */
XPUBLIC void panic(message)
Xchar *message;
X{
X     fprintf(stderr, "Panic: %s\n", message);
X     exit(3);
X}
END_OF_driver.c
if test 1512 -ne `wc -c <driver.c`; then
    echo shar: \"driver.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f makefile -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"makefile\"
else
echo shar: Extracting \"makefile\" \(239 characters\)
sed "s/^X//" >makefile <<'END_OF_makefile'
XRANDOM = random.o driver.o
Xrandom: $(RANDOM)
X	cc -o random $(RANDOM)
Xrandom.o: sim.h
X
XFIFO = fifo.o driver.o
Xfifo: $(FIFO)
X	cc -o fifo $(FIFO)
Xfifo.o: sim.h
X
XLRU = lru.o driver.o
Xlru: $(LRU)
X	cc -o lru $(LRU)
Xlru.o: sim.h
X
Xdriver.o: sim.h
END_OF_makefile
if test 239 -ne `wc -c <makefile`; then
    echo shar: \"makefile\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f notes -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"notes\"
else
echo shar: Extracting \"notes\" \(2377 characters\)
sed "s/^X//" >notes <<'END_OF_notes'
XThis practical requires a file "data" of block requests that is
Xobtained as follows:
X
X1.  Apply the patches from "cdiff.fs" to a copy of the file system
X    code, and build a boot disk with this file system on it.
X
X    (The cdiffs were made w.r.t. a slightly modified Minix-386 file
X    system.  Your mileage may vary, but I hope not by much).
X
X2.  Boot Minix from the boot disk you have just made.  The system
X    will operate as normal, except that it will occasionally write a
X    block of trace information on floppy drive 0.
X
X    This will overwrite the boot disk, if you have left it there,
X    and that is what I usually let it do.  But it will also
X    overwrite any other disk you put in the drive, so be careful!
X    It's best to avoid loading a RAM image from floppy, in case you
X    accidentally overwrite your image disk.  If you're nervous, you
X    could back up everything before starting.  If no disk is present
X    in drive 0, the system will probably hang.
X
X    When block n of trace info is written to the floppy, "[n]" is
X    displayed on the screen.  Make sure you give the system a good
X    work-out to get plenty of trace info: try re-compiling the OS,
X    for example.  Keep a note of the number of 1K blocks of trace
X    info written; the OS will stop writing them after 512, but you
X    can stop before then if you wish.  If you're using a 360K boot
X    disk, it would be best to change the constant MAX_TRACE in
X    cache.c to 360, say.
X
X    Sync and reboot the system with the normal fs.
X
X3.  Use dd to extract the trace info from the floppy: for example,
X    if at least 100 blocks of trace info were written, you can say
X
X	dd if=/dev/fd0 of=rawdata bs=1k count=100
X
X    to fetch 100K of data (= 25K block requests, each occupying 2
X    shorts).
X
X4.  Build the program "convert" and use it to convert the file of
X    raw data to the textual form expected by the simulation:
X
X	cc -o convert convert.c
X	convert rawdata >data
X
X    The file "data" can now be used to run the simulations, for
X    example:
X
X	random 100 data
X
X    The results will be different from the ones in the
X    documentation, of course, because your data is different.
X
X(I refuse to waste net bandwidth posting a file of 38,000 stupid
Xnumbers; note, however that these numbers are far from random, so
Xdon't be tempted to substitute 38,000 calls to rand() for all the
Xabove work!)
END_OF_notes
if test 2377 -ne `wc -c <notes`; then
    echo shar: \"notes\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f prog.sty -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"prog.sty\"
else
echo shar: Extracting \"prog.sty\" \(391 characters\)
sed "s/^X//" >prog.sty <<'END_OF_prog.sty'
X% LaTeX style for a special verbatim program environment
X
X\begingroup \catcode `|=0 \catcode `[= 1
X\catcode`]=2 \catcode `\{=12 \catcode `\}=12
X\catcode`\\=12 |gdef|@xprog#1\end{program}[#1|end[program]]
X|endgroup
X
X\def\program{\quote\begingroup
X	\@verbatim \frenchspacing\@vobeyspaces \@xprog}
X\def\endprogram{\endtrivlist\endgroup\endquote}
X
X% Make tab characters illegal
X\catcode`\^^I=15
END_OF_prog.sty
if test 391 -ne `wc -c <prog.sty`; then
    echo shar: \"prog.sty\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f random.c -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"random.c\"
else
echo shar: Extracting \"random.c\" \(1537 characters\)
sed "s/^X//" >random.c <<'END_OF_random.c'
X/* random.c -- simulate cache with random replacement */
X
X#include "sim.h"
X#include <stdlib.h>
X
XPUBLIC char *policy = "RANDOM";
X
XPRIVATE struct buffer {
X     int b_block;		   /* Block number */
X     int b_dirt;		   /* CLEAN or DIRTY */
X} buf[MAXBUFS];
X
X#define CLEAN 1
X#define DIRTY 2
X
X/* init_cache -- set up cache data structures */
XPUBLIC void init_cache()
X{
X     struct buffer *b;
X
X     for (b = &buf[0]; b < &buf[nbuffs]; b++) {
X	  b->b_block = NO_BLOCK;
X	  b->b_dirt = CLEAN;
X     }
X}
X
X/* randint -- generate random number in range 0 .. N-1 (N <= 32768) */
XPRIVATE int randint(n)
Xint n;
X{
X     static long seed = 1L;
X     seed = 1103515245L * seed + 12345;
X     return ((int) ((seed >> 16) & 0x7fff) % n);
X}
X     
X/* use_block -- perform a read or write action */
XPUBLIC void use_block(action, block)
Xint action;
Xint block;
X{
X     struct buffer *b;
X
X     /* search for a buffer containing block */
X     for (b = &buf[0]; b < &buf[nbuffs]; b++)
X	  if (b->b_block == block) 
X	       goto found;
X
X     /* not found: evict a random buffer */
X     b = &buf[randint(nbuffs)];
X     if (b->b_dirt == DIRTY) 
X	  nwrites++;
X     if (action != NEW) 
X	  nreads++;
X     b->b_dirt = CLEAN;
X     b->b_block = block;
X
Xfound:
X     /* mark the buffer dirty unless only reading */
X     if (action != READ)
X	  b->b_dirt = DIRTY;
X}
X
X/* do_sync -- write back all dirty blocks */
XPUBLIC void do_sync()
X{
X     struct buffer *b;
X
X     for (b = &buf[0]; b < &buf[nbuffs]; b++) {
X	  if (b->b_dirt == DIRTY) 
X	       nwrites++;
X	  b->b_dirt = CLEAN;
X     }
X}
END_OF_random.c
if test 1537 -ne `wc -c <random.c`; then
    echo shar: \"random.c\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f sim.h -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"sim.h\"
else
echo shar: Extracting \"sim.h\" \(922 characters\)
sed "s/^X//" >sim.h <<'END_OF_sim.h'
X/* sim.h -- global defs for buffer cache simulation */
X
X#define PUBLIC
X#define PRIVATE static
X#define EXTERN extern
X
X#define TRUE 1
X#define FALSE 0
X
X#define MAXBUFS 4096		   /* Maximum no. of buffers */
X#define NO_BLOCK 0		   /* Fictitious block number */
X
X/* Actions arguments to use_block() */
X#define READ 1
X#define WRITE 2
X#define NEW 3
X
X/* Defined for each simulation: */
XEXTERN char *policy;		   /* Name of the policy */
X
X/* init_cache -- set up cache data structures */
XPUBLIC void init_cache(/* void */);
X
X/* use_block -- perform a read or write action */
XPUBLIC void use_block(/* int action, int block */);
X
X/* do_sync -- write back all dirty blocks */
XPUBLIC void do_sync(/* void */);
X
X/* Defined by driver: */
XEXTERN int nbuffs;		   /* No. of buffers to use */
XEXTERN int nreads, nwrites;	   /* No. of read and write transfers */
X
X/* panic -- print a message and exit */
XPUBLIC void panic(/* char *message */);
END_OF_sim.h
if test 922 -ne `wc -c <sim.h`; then
    echo shar: \"sim.h\" unpacked with wrong size!
fi
# end of overwriting check
fi
if test -f tabulate -a "${1}" != "-c" ; then 
  echo shar: Will not over-write existing file \"tabulate\"
else
echo shar: Extracting \"tabulate\" \(176 characters\)
sed "s/^X//" >tabulate <<'END_OF_tabulate'
Xecho "  Method    Bufs    Reqs   Reads  Writes   Total"
Xecho
Xfor n in 1 2 5 10 100 200 300 400 500 700 1000 1300 1600; do
X	for m in random fifo lru; do
X		$m $n data
X	done
Xdone
END_OF_tabulate
if test 176 -ne `wc -c <tabulate`; then
    echo shar: \"tabulate\" unpacked with wrong size!
fi
# end of overwriting check
fi
echo shar: End of shell archive.
exit 0
