assign4-2/.DS_Store
assign4-2/assign4_part2/mymem.h
#include <stddef.h>
typedef enum strategies_enum
{
NotSet = 0,
Best = 1,
Worst = 2,
First = 3,
Next = 4
} strategies;
char *strategy_name(strategies strategy);
strategies strategyFromString(char * strategy);
void initmem(strategies strategy, size_t sz);
void *mymalloc(size_t requested);
void myfree(void* block);
int mem_holes();
int mem_allocated();
int mem_free();
int mem_total();
int mem_largest_free();
int mem_small_free(int size);
char mem_is_alloc(void *ptr);
void* mem_pool();
void print_memory();
void print_memory_status();
void try_mymem(int argc, char **argv);
assign4-2/assign4_part2/memorytests.c
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <unistd.h>
#include "mymem.h"
#include "testrunner.h"
/* performs a randomized test:
totalSize == the total size of the memory pool, as passed to initmem2
totalSize must be less than 10,000 * minBlockSize
fillRatio == when the allocated memory is >= fillRatio * totalSize, a block is freed;
otherwise, a new block is allocated.
If a block cannot be allocated, this is tallied and a random block is freed immediately thereafter in the next iteration
minBlockSize, maxBlockSize == size for allocated blocks is picked uniformly at random between these two numbers, inclusive
*/
void do_randomized_test(int strategyToUse, int totalSize, float fillRatio, int minBlockSize, int maxBlockSize, int iterations)
{
void * pointers[10000];
int storedPointers = 0;
int strategy;
int lbound = 1;
int ubound = 4;
int smallBlockSize = maxBlockSize/10;
if (strategyToUse>0)
lbound=ubound=strategyToUse;
FILE *log;
log = fopen("tests.log","a");
if(log == NULL) {
perror("Can't append to log file.\n");
return;
}
fprintf(log,"Running randomized tests: pool size == %d, fill ratio == %f, block size is from %d to %d, %d iterations\n",totalSize,fillRatio,minBlockSize,maxBlockSize,iterations);
fclose(log);
for (strategy = lbound; strategy <= ubound; strategy++)
{
double sum_largest_free = 0;
double sum_hole_size = 0;
double sum_allocated = 0;
int failed_allocations = 0;
double sum_small = 0;
struct timespec execstart, execend;
int force_free = 0;
int i;
storedPointers = 0;
initmem(strategy,totalSize);
clock_gettime(CLOCK_REALTIME, &execstart);
for (i = 0; i < iterations; i++)
{
if ( (i % 10000)==0 )
srand ( time(NULL) );
if (!force_free && (mem_free() > (totalSize * (1-fillRatio))))
{
int newBlockSize = (rand()%(maxBlockSize-minBlockSize+1))+minBlockSize;
/* allocate */
void * pointer = mymalloc(newBlockSize);
if (pointer != NULL)
pointers[storedPointers++] = pointer;
else
{
failed_allocations++;
force_free = 1;
}
}
else
{
int chosen;
void * pointe ...
2. void initmem(strategies strategy, size_t sz);
void *mymalloc(size_t requested);
void myfree(void* block);
int mem_holes();
int mem_allocated();
int mem_free();
int mem_total();
int mem_largest_free();
int mem_small_free(int size);
char mem_is_alloc(void *ptr);
void* mem_pool();
void print_memory();
void print_memory_status();
void try_mymem(int argc, char **argv);
assign4-2/assign4_part2/memorytests.c
#include <errno.h>
#include <stdlib.h>
3. #include <string.h>
#include <stdio.h>
#include <assert.h>
#include <time.h>
#include <unistd.h>
#include "mymem.h"
#include "testrunner.h"
/* performs a randomized test:
totalSize == the total size of the memory pool, as passed to
initmem2
totalSize must be less than 10,000 * minBlockSize
fillRatio == when the allocated memory is >= fillRatio *
totalSize, a block is freed;
otherwise, a new block is allocated.
If a block cannot be allocated, this is tallied and a
random block is freed immediately thereafter in the next
iteration
minBlockSize, maxBlockSize == size for allocated blocks
4. is picked uniformly at random between these two numbers,
inclusive
*/
void do_randomized_test(int strategyToUse, int totalSize, float
fillRatio, int minBlockSize, int maxBlockSize, int iterations)
{
void * pointers[10000];
int storedPointers = 0;
int strategy;
int lbound = 1;
int ubound = 4;
int smallBlockSize = maxBlockSize/10;
if (strategyToUse>0)
lbound=ubound=strategyToUse;
FILE *log;
log = fopen("tests.log","a");
if(log == NULL) {
5. perror("Can't append to log file.n");
return;
}
fprintf(log,"Running randomized tests: pool size == %d,
fill ratio == %f, block size is from %d to %d, %d
iterationsn",totalSize,fillRatio,minBlockSize,maxBlockSize,iter
ations);
fclose(log);
for (strategy = lbound; strategy <= ubound; strategy++)
{
double sum_largest_free = 0;
double sum_hole_size = 0;
double sum_allocated = 0;
int failed_allocations = 0;
double sum_small = 0;
struct timespec execstart, execend;
int force_free = 0;
6. int i;
storedPointers = 0;
initmem(strategy,totalSize);
clock_gettime(CLOCK_REALTIME, &execstart);
for (i = 0; i < iterations; i++)
{
if ( (i % 10000)==0 )
srand ( time(NULL) );
if (!force_free && (mem_free() > (totalSize *
(1-fillRatio))))
{
int newBlockSize =
(rand()%(maxBlockSize-minBlockSize+1))+minBlockSize;
/* allocate */
void * pointer = mymalloc(newBlockSize);
if (pointer != NULL)
9. log = fopen("tests.log","a");
if(log == NULL) {
perror("Can't append to log file.n");
return;
}
fprintf(log,"t=== %s
===n",strategy_name(strategy));
fprintf(log,"tTest took %.2fms.n", (execend.tv_sec -
execstart.tv_sec) * 1000 + (execend.tv_nsec - execstart.tv_nsec)
/ 1000000.0);
fprintf(log,"tAverage hole size:
%fn",sum_hole_size/iterations);
fprintf(log,"tAverage largest free block:
%fn",sum_largest_free/iterations);
fprintf(log,"tAverage allocated bytes:
%fn",sum_allocated/iterations);
fprintf(log,"tAverage number of small blocks:
%fn",sum_small/iterations);
fprintf(log,"tFailed allocations:
%dn",failed_allocations);
fclose(log);
10. }
}
/* run randomized tests against the various strategies with
various parameters */
int do_stress_tests(int argc, char **argv)
{
int strategy = strategyFromString(*(argv+1));
unlink("tests.log"); // We want a new log file
do_randomized_test(strategy,10000,0.25,1,1000,10000);
do_randomized_test(strategy,10000,0.25,1,2000,10000);
do_randomized_test(strategy,10000,0.25,1000,2000,10000)
;
do_randomized_test(strategy,10000,0.25,1,3000,10000);
do_randomized_test(strategy,10000,0.25,1,4000,10000);
12. segfaulting */
}
/* basic sequential allocation of single byte blocks */
int test_alloc_1(int argc, char **argv) {
strategies strategy;
int lbound = 1;
int ubound = 4;
if (strategyFromString(*(argv+1))>0)
lbound=ubound=strategyFromString(*(argv+1));
for (strategy = lbound; strategy <= ubound; strategy++)
{
int correct_holes = 0;
int correct_alloc = 100;
int correct_largest_free = 0;
int i;
13. void* lastPointer = NULL;
initmem(strategy,100);
for (i = 0; i < 100; i++)
{
void* pointer = mymalloc(1);
if ( i > 0 && pointer != (lastPointer+1) )
{
printf("Allocation with %s was not
sequential at %i; expected %p, actual %pn",
strategy_name(strategy), i,lastPointer+1,pointer);
return 1;
}
lastPointer = pointer;
}
if (mem_holes() != correct_holes)
{
printf("Holes not counted as %d with %sn",
correct_holes, strategy_name(strategy));
14. return 1;
}
if (mem_allocated() != correct_alloc)
{
printf("Allocated memory not reported as %d
with %sn", correct_alloc, strategy_name(strategy));
return 1;
}
if (mem_largest_free() != correct_largest_free)
{
printf("Largest memory block free not reported
as %d with %sn", correct_largest_free,
strategy_name(strategy));
return 1;
}
}
15. return 0;
}
/* alloc, alloc, free, alloc */
int test_alloc_2(int argc, char **argv) {
strategies strategy;
int lbound = 1;
int ubound = 4;
if (strategyFromString(*(argv+1))>0)
lbound=ubound=strategyFromString(*(argv+1));
for (strategy = lbound; strategy <= ubound; strategy++)
{
int correct_holes;
int correct_alloc;
16. int correct_largest_free;
int correct_small;
void* first;
void* second;
void* third;
int correctThird;
initmem(strategy,100);
first = mymalloc(10);
second = mymalloc(1);
myfree(first);
third = mymalloc(1);
if (second != (first+10))
{
printf("Second allocation failed; allocated at
incorrect offset with strategy %s", strategy_name(strategy));
return 1;
18. correctThird = (third == first);
correct_holes = 2;
correct_largest_free = 89;
break;
case Next:
correctThird = (third == second+1);
correct_holes = 2;
correct_largest_free = 88;
break;
case NotSet:
break;
}
if (!correctThird)
{
printf("Third allocation failed; allocated at
incorrect offset with %s", strategy_name(strategy));
return 1;
19. }
if (mem_holes() != correct_holes)
{
printf("Holes counted as %d, should be %d with
%sn", mem_holes(), correct_holes, strategy_name(strategy));
return 1;
}
if (mem_small_free(9) != correct_small)
{
printf("Small holes counted as %d, should be %d
with %sn", mem_small_free(9), correct_small,
strategy_name(strategy));
return 1;
}
if (mem_allocated() != correct_alloc)
{
printf("Memory reported as %d, should be %d
20. with %sn", mem_allocated(0), correct_alloc,
strategy_name(strategy));
return 1;
}
if (mem_largest_free() != correct_largest_free)
{
printf("Largest memory block free reported as
%d, should be %d with %sn", mem_largest_free(),
correct_largest_free, strategy_name(strategy));
return 1;
}
}
return 0;
}
/* basic sequential allocation followed by 50 frees */
21. int test_alloc_3(int argc, char **argv) {
strategies strategy;
int lbound = 1;
int ubound = 4;
if (strategyFromString(*(argv+1))>0)
lbound=ubound=strategyFromString(*(argv+1));
for (strategy = lbound; strategy <= ubound; strategy++)
{
int correct_holes = 50;
int correct_alloc = 50;
int correct_largest_free = 1;
int i;
void* lastPointer = NULL;
initmem(strategy,100);
for (i = 0; i < 100; i++)
22. {
void* pointer = mymalloc(1);
if ( i > 0 && pointer != (lastPointer+1) )
{
printf("Allocation with %s was not
sequential at %i; expected %p, actual %pn",
strategy_name(strategy), i,lastPointer+1,pointer);
return 1;
}
lastPointer = pointer;
}
for (i = 1; i < 100; i+= 2)
{
myfree(mem_pool() + i);
}
if (mem_holes() != correct_holes)
{
23. printf("Holes not counted as %d with %sn",
correct_holes, strategy_name(strategy));
return 1;
}
if (mem_allocated() != correct_alloc)
{
printf("Memory not reported as %d with %sn",
correct_alloc, strategy_name(strategy));
return 1;
}
if (mem_largest_free() != correct_largest_free)
{
printf("Largest memory block free not reported
as %d with %sn", correct_largest_free,
strategy_name(strategy));
return 1;
}
24. for(i=0;i<100;i++) {
if(mem_is_alloc(mem_pool()+i) == i%2) {
printf("Byte %d in memory claims to ",i);
if(i%2)
printf("not ");
printf("be allocated. It should ");
if(!i%2)
printf("not ");
printf("be allocated.n");
return 1;
}
}
}
return 0;
}
25. /* basic sequential allocation followed by 50 frees, then another
50 allocs */
int test_alloc_4(int argc, char **argv) {
strategies strategy;
int lbound = 1;
int ubound = 4;
if (strategyFromString(*(argv+1))>0)
lbound=ubound=strategyFromString(*(argv+1));
for (strategy = lbound; strategy <= ubound; strategy++)
{
int correct_holes = 0;
int correct_alloc = 100;
int correct_largest_free = 0;
int i;
void* lastPointer = NULL;
26. initmem(strategy,100);
for (i = 0; i < 100; i++)
{
void* pointer = mymalloc(1);
if ( i > 0 && pointer != (lastPointer+1) )
{
printf("Allocation with %s was not
sequential at %i; expected %p, actual %pn",
strategy_name(strategy), i,lastPointer+1,pointer);
return 1;
}
lastPointer = pointer;
}
for (i = 1; i < 100; i+= 2)
{
myfree(mem_pool() + i);
}
27. for (i = 1; i < 100; i+=2)
{
void* pointer = mymalloc(1);
if ( i > 1 && pointer != (lastPointer+2) )
{
printf("Second allocation with %s was not
sequential at %i; expected %p, actual %pn",
strategy_name(strategy), i,lastPointer+1,pointer);
return 1;
}
lastPointer = pointer;
}
if (mem_holes() != correct_holes)
{
printf("Holes not counted as %d with %sn",
correct_holes, strategy_name(strategy));
return 1;
}
28. if (mem_allocated() != correct_alloc)
{
printf("Memory not reported as %d with %sn",
correct_alloc, strategy_name(strategy));
return 1;
}
if (mem_largest_free() != correct_largest_free)
{
printf("Largest memory block free not reported
as %d with %sn", correct_largest_free,
strategy_name(strategy));
return 1;
}
}
return 0;
}
29. int run_memory_tests(int argc, char **argv)
{
if (argc < 3)
{
printf("Usage: mem -test <test> <strategy> n");
return 0;
}
set_testrunner_default_timeout(20);
/* Tests can be invoked by matching their name or their
suite name or 'all'*/
testentry_t tests[] = {
{"alloc1","suite1",test_alloc_1},
{"alloc2","suite2",test_alloc_2},
{"alloc3","suite1",test_alloc_3},
{"alloc4","suite2",test_alloc_4},
{"stress","suite3",do_stress_tests},
};
30. return
run_testrunner(argc,argv,tests,sizeof(tests)/sizeof(testentry_t));
}
int main(int argc, char **argv)
{
if( argc < 2) {
printf("Usage: mem -test <test> <strategy> | mem -try <arg1>
<arg2> ... n");
exit(-1);
}
else if (!strcmp(argv[1],"-test"))
return run_memory_tests(argc-1,argv+1);
else if (!strcmp(argv[1],"-try")) {
try_mymem(argc-1,argv+1);
return 0;
} else {
printf("Usage: mem -test <test> <strategy> | mem -try <arg1>
31. <arg2> ... n");
exit(-1);
}
}
assign4-2/assign4_part2/testrunner.h
typedef int (*test_fp) (int, char **);
typedef struct
{
char *name;
char *suite;
test_fp test_function;
} testentry_t;
int run_testrunner(int argc, char **argv, testentry_t *entries,int
entry_count);
void set_testrunner_default_timeout(int s);
void set_testrunner_timeout(int s);
assign4-2/assign4_part2/README.txt
LMP2: Memory Management
=======================
This machine problem will focus on memory. You will
implement your own
32. version of malloc() and free(), using a variety of allocation
strategies.
You will be implementing a memory manager for a block of
memory. You will
implement routines for allocating and deallocating memory, and
keeping track of
what memory is in use. You will implement four strategies for
selecting in
which block to place a new requested memory black:
1) First-fit: select the first suitable block with smallest
address.
2) Best-fit: select the smallest suitable block.
3) Worst-fit: select the largest suitable block.
4) Next-fit: select the first suitable block after
the last block allocated (with wraparound
from end to beginning).
Here, "suitable" means "free, and large enough to fit the new
data".
Here are the functions you will need to implement:
initmem():
Initialize memory structures.
mymalloc():
Like malloc(), this allocates a new block of memory.
myfree():
Like free(), this deallocates a block of memory.
mem_holes():
How many free blocks are in memory?
33. mem_allocated():
How much memory is currently allocated?
mem_free():
How much memory is NOT allocated?
mem_largest_free():
How large is the largest free block?
mem_small_free():
How many small unallocated blocks are currently in memory?
mem_is_alloc():
Is a particular byte allocated or not?
We have given you a structure to use to implement these
functions. It is a
doubly-linked list of blocks in memory (both allocated and free
blocks). Every
malloc and free can create new blocks, or combine existing
blocks. You may
modify this structure, or even use a different one entirely.
However, do not
change function prototypes or files other than mymem.c.
IMPORTANT NOTE: Regardless of how you implement
memory management, make sure
that there are no adjacent free blocks. Any such blocks should
be merged into
one large block.
We have also given you a few functions to help you monitor
what happens when you
call your functions. Most important is the try_mymem()
function. If you run
34. your code with "mem -try <args>", it will call this function,
which you can use
to demonstrate the effects of your memory operations. These
functions have no
effect on test code, so use them to your advantage.
Running your code:
After running "make", run
1) "mem" to see the available tests and strategies.
2) "mem -test <test> <strategy>" to test your code with our
tests.
3) "mem -try <args>" to run your code with your own tests
(the try_mymem function).
You can also use "make test" and "make stage1-test" for testing.
"make
stage1-test" only runs the tests relevant to stage 1.
As in previous MPs, running "mem -test -f0 ..." will allow tests
to run even
after previous tests have failed. Similarly, using "all" for a test
or strategy
name runs all of the tests or strategies. Note that if "all" is
selected as the
strategy, the 4 tests are shown as one.
One of the tests, "stress", runs an assortment of randomized
tests on each
strategy. The results of the tests are placed in "tests.out" . You
may want to
view this file to see the relative performance of each strategy.
Stage 1
35. -------
Implement all the above functions, for the first-fit strategy. Use
"mem -test
all first" to test your implementation.
Stage 2
-------
A) Implement the other three strategies: worst-fit, best-fit, and
next-fit. The
strategy is passed to initmem(), and stored in the global variable
"myStrategy".
Some of your functions will need to check this variable to
implement the
correct strategy.
You can test your code with "mem -test all worst", etc., or test
all 4 together
with "mem -test all all". The latter command does not test the
strategies
separately; your code passes the test only if all four strategies
pass.
Questions
=========
1) Why is it so important that adjacent free blocks not be left as
such? What
would happen if they were permitted?
2) Which function(s) need to be concerned about adjacent free
blocks?
36. 3) Name one advantage of each strategy.
4) Run the stress test on all strategies, and look at the results
(tests.out).
What is the significance of "Average largest free block"?
Which strategy
generally has the best performance in this metric? Why do you
think this is?
5) In the stress test results (see Question 4), what is the
significance of
"Average number of small blocks"? Which strategy generally
has the best
performance in this metric? Why do you think this is?
6) Eventually, the many mallocs and frees produces many small
blocks scattered
across the memory pool. There may be enough space to allocate
a new block, but
not in one place. It is possible to compact the memory, so all
the free blocks
are moved to one large free block. How would you implement
this in the system
you have built?
7) If you did implement memory compaction, what changes
would you need to make
in how such a system is invoked (i.e. from a user's perspective)?
8) How would you use the system you have built to implement
realloc? (Brief
explanation; no code)
9) Which function(s) need to know which strategy is being
used? Briefly explain
why this/these and not others.
37. 10) Give one advantage of implementing memory management
using a linked list
over a bit array, where every bit tells whether its corresponding
byte is
allocated.
assign4-2/assign4_part2/mymem.c
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <assert.h>
#include "mymem.h"
#include <time.h>
/* The main structure for implementing memory allocation.
* You may change this to fit your implementation.
*/
struct memoryList
38. {
// doubly-linked list
struct memoryList *last;
struct memoryList *next;
int size; // How many bytes in this block?
char alloc; // 1 if this block is allocated,
// 0 if this block is free.
void *ptr; // location of block in memory pool.
};
strategies myStrategy = NotSet; // Current strategy
size_t mySize;
void *myMemory = NULL;
static struct memoryList *head;
39. static struct memoryList *next;
/* initmem must be called prior to mymalloc and myfree.
initmem may be called more than once in a given exeuction;
when this occurs, all memory you previously malloc'ed
*must* be freed,
including any existing bookkeeping data.
strategy must be one of the following:
- "best" (best-fit)
- "worst" (worst-fit)
- "first" (first-fit)
- "next" (next-fit)
sz specifies the number of bytes that will be available, in
total, for all mymalloc requests.
*/
40. void initmem(strategies strategy, size_t sz)
{
myStrategy = strategy;
/* all implementations will need an actual block of
memory to use */
mySize = sz;
if (myMemory != NULL) free(myMemory); /* in case this
is not the first time initmem2 is called */
/* TODO: release any other memory you were using for
bookkeeping when doing a re-initialization! */
myMemory = malloc(sz);
/* TODO: Initialize memory management structure. */
41. }
/* Allocate a block of memory with the requested size.
* If the requested block is not available, mymalloc returns
NULL.
* Otherwise, it returns a pointer to the newly allocated block.
* Restriction: requested >= 1
*/
void *mymalloc(size_t requested)
{
assert((int)myStrategy > 0);
switch (myStrategy)
{
case NotSet:
return NULL;
case First:
42. return NULL;
case Best:
return NULL;
case Worst:
return NULL;
case Next:
return NULL;
}
return NULL;
}
/* Frees a block of memory previously allocated by mymalloc.
*/
void myfree(void* block)
{
return;
}
43. /****** Memory status/property functions ******
* Implement these functions.
* Note that when we refer to "memory" here, we mean the
* memory pool this module manages via
initmem/mymalloc/myfree.
*/
/* Get the number of contiguous areas of free space in memory.
*/
int mem_holes()
{
return 0;
}
/* Get the number of bytes allocated */
int mem_allocated()
{
return 0;
}
44. /* Number of non-allocated bytes */
int mem_free()
{
return 0;
}
/* Number of bytes in the largest contiguous area of unallocated
memory */
int mem_largest_free()
{
return 0;
}
/* Number of free blocks smaller than "size" bytes. */
int mem_small_free(int size)
{
return 0;
45. }
char mem_is_alloc(void *ptr)
{
return 0;
}
/*
* Feel free to use these functions, but do not modify them.
* The test code uses them, but you may ind them useful.
*/
//Returns a pointer to the memory pool.
void *mem_pool()
{
return myMemory;
}
46. // Returns the total number of bytes in the memory pool. */
int mem_total()
{
return mySize;
}
// Get string name for a strategy.
char *strategy_name(strategies strategy)
{
switch (strategy)
{
case Best:
return "best";
case Worst:
return "worst";
case First:
47. return "first";
case Next:
return "next";
default:
return "unknown";
}
}
// Get strategy from name.
strategies strategyFromString(char * strategy)
{
if (!strcmp(strategy,"best"))
{
return Best;
}
else if (!strcmp(strategy,"worst"))
{
return Worst;
48. }
else if (!strcmp(strategy,"first"))
{
return First;
}
else if (!strcmp(strategy,"next"))
{
return Next;
}
else
{
return 0;
}
}
/*
* These functions are for you to modify however you see fit.
These will not
49. * be used in tests, but you may find them useful for debugging.
*/
/* Use this function to print out the current contents of memory.
*/
void print_memory()
{
return;
}
/* Use this function to track memory allocation performance.
* This function does not depend on your implementation,
* but on the functions you wrote above.
*/
void print_memory_status()
{
printf("%d out of %d bytes
allocated.n",mem_allocated(),mem_total());
printf("%d bytes are free in %d holes; maximum
50. allocatable block is %d
bytes.n",mem_free(),mem_holes(),mem_largest_free());
printf("Average hole size is
%f.nn",((float)mem_free())/mem_holes());
}
/* Use this function to see what happens when your malloc and
free
* implementations are called. Run "mem -try <args>" to call
this function.
* We have given you a simple example to start.
*/
void try_mymem(int argc, char **argv) {
strategies strat;
void *a, *b, *c, *d, *e;
if(argc > 1)
strat = strategyFromString(argv[1]);
else
strat = First;
51. /* A simple example.
Each algorithm should produce a different layout. */
initmem(strat,500);
a = mymalloc(100);
b = mymalloc(100);
c = mymalloc(100);
myfree(b);
d = mymalloc(50);
myfree(a);
e = mymalloc(25);
print_memory();
print_memory_status();
}
54. /* --- Helper macros and functions --- */
#define DIE(mesg)
{fprintf(stderr,"n%s(%d):%sn",__fname__,__LINE__,mesg);
exit(1);}
static int eql( char*s1, char*s2) {return
s1&&s2&&!strcmp(s1,s2);}
/* Callback function for qsort on strings */
static int mystrcmp( const void *p1, const void *p2) {
return eql( ( char*)p1, ( char*)p2);
}
/* Stats of all tests run so far */
typedef struct
{
int ran, passed, failed;
} stats_t;
55. /* -- Signal handlers -- */
static pid_t child_pid;
static int sent_child_timeout_kill_signal;
static void kill_child_signal_handler(intsigno) {
if(!child_pid) return;
char m[]="-Timeout(Killing test process)-";
write(0,m,sizeof(m)-1);
kill(child_pid,SIGKILL);
sent_child_timeout_kill_signal=1;
}
/* Internal function to run a test as a forked child. The child
process is terminated if it runs for more than a few seconds */
static int invoke_test_with_timelimit(testentry_t* test, int
redirect_stdouterr,int argc, char **argv)
{
56. char fname[255];
int wait_status;
pid_t wait_val;
struct sigaction action;
assert(!child_pid);
assert(test && test->test_function && test->name);
set_testrunner_timeout(default_timeout_seconds);
errno=0;
child_pid = fork ();
if (child_pid == -1) {
fprintf(stderr,"-fork failed so running test inline-");
return test->test_function (argc, argv);
}
58. sent_child_timeout_kill_signal=0;
alarm(timeout_seconds);
wait_val = waitpid (child_pid, &wait_status, 0);
int child_exited_normally= WIFEXITED
(wait_status);
int child_exit_value=WEXITSTATUS (wait_status);
int
child_term_by_signal=WIFSIGNALED(wait_status);
int child_term_signal=WTERMSIG(wait_status);
if(child_term_by_signal) {
fprintf(stderr,"testrunner:Test terminated by
signal %dn",child_term_signal);
fprintf(stderr,"testrunner:waitpid returned %d
(child_pid=%d,wait_status=%d)",wait_val,child_pid,wait_status
);
}
if(child_pid != wait_val)
59. fprintf(stderr,"testrunner: strange... wait_val !=
child_pidn");
int passed= (child_pid == wait_val) &&
(child_exit_value==0) && (child_exited_normally!=0);
alarm(0);
kill(child_pid,SIGKILL);
child_pid=0;
return sent_child_timeout_kill_signal ? test_killed :
passed ? 0 : 1;
}
}
/*
* run a test and update the stats. The main guts of this
functionality is provided by invoke_test_with_timelimit
* This outer wrapper updates thes output and statistics before
and after running the test.
68. test: mem
./mem -test -f0 all all
stage1-test: mem
./mem -test -f0 all first
pretty:
indent *.c *.h -kr
assign4-2/assign4_part2/tests.log
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1 to 1000, 10000 iterations
=== best ===
Test took 0.18ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.16ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
69. Failed allocations: 0
=== first ===
Test took 0.15ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.15ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1 to 2000, 10000 iterations
=== best ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.15ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.14ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
70. Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.18ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1000 to 2000, 10000 iterations
=== best ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.17ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.17ms.
Average hole size: 0.000000
Average largest free block: 0.000000
71. Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1 to 3000, 10000 iterations
=== best ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.17ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.17ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.17ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1 to 4000, 10000 iterations
=== best ===
72. Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.18ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.19ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.250000, block size is from 1 to 5000, 10000 iterations
=== best ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
73. === worst ===
Test took 0.21ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1 to 1000, 10000 iterations
=== best ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
74. Failed allocations: 0
=== first ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.20ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1 to 2000, 10000 iterations
=== best ===
Test took 0.13ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
75. Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1000 to 2000, 10000 iterations
=== best ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.11ms.
Average hole size: 0.000000
Average largest free block: 0.000000
76. Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1 to 3000, 10000 iterations
=== best ===
Test took 0.11ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1 to 4000, 10000 iterations
=== best ===
77. Test took 0.11ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.13ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.12ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1 to 5000, 10000 iterations
=== best ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
78. === worst ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.500000, block size is from 1000 to 1000, 10000 iterations
=== best ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
79. Failed allocations: 0
=== first ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.750000, block size is from 1 to 1000, 10000 iterations
=== best ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
80. Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.750000, block size is from 500 to 1000, 10000 iterations
=== best ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
81. Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.750000, block size is from 1 to 2000, 10000 iterations
=== best ===
Test took 0.10ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
Running randomized tests: pool size == 10000, fill ratio ==
0.900000, block size is from 1 to 500, 10000 iterations
=== best ===
82. Test took 0.09ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== worst ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== first ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
=== next ===
Test took 0.08ms.
Average hole size: 0.000000
Average largest free block: 0.000000
Average allocated bytes: 0.000000
Average number of small blocks: 0.000000
Failed allocations: 0
assign4-2/assign4_part1/setup.sh
#!/bin/sh
#*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************
rm -rf ./testdata
mkdir -p
83. ./testdata/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20
echo -n "Hello" > ./testdata/hello.txt
echo -n "OldFile" > ./testdata/oldfile.txt
cp ./testdata/hello.txt ./testdata/1/2/3/4/5/6/7/8/9/10/
cp ./testdata/oldfile.txt ./testdata/1/2/3/4/5/6/7/8/9/
touch -m -d 20050101 ./testdata/oldfile.txt
touch -a -d 20050103 ./testdata/oldfile.txt
if [ ! -f /tmp/bigtestscratchfile2forLMP1 ] ; then
echo "Creating large file (first time only)"
cat /usr/lib/*.so >/tmp/bigtestscratchfile2forLMP1
chmod 644 /tmp/bigtestscratchfile2forLMP1
fi
ln -s /tmp/bigtestscratchfile2forLMP1 ./testdata/bigfile
exit 0
assign4-2/assign4_part1/restart.c
/*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************/
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#include "restart.h"
#define BLKSIZE PIPE_BUF
#define MILLION 1000000L
#define D_MILLION 1000000.0
84. /* Private functions */
static int gettimeout(struct timeval end, struct timeval
*timeoutp)
{
gettimeofday(timeoutp, NULL);
timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec;
timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec;
if (timeoutp->tv_usec >= MILLION) {
timeoutp->tv_sec++;
timeoutp->tv_usec -= MILLION;
}
if (timeoutp->tv_usec < 0) {
timeoutp->tv_sec--;
timeoutp->tv_usec += MILLION;
}
if ((timeoutp->tv_sec < 0) ||
((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
errno = ETIME;
return -1;
}
return 0;
}
/* Restart versions of traditional functions */
int r_close(int fildes)
{
int retval;
while (retval = close(fildes), retval == -1 && errno ==
EINTR);
return retval;
}
int r_dup2(int fildes, int fildes2)
85. {
int retval;
while (retval = dup2(fildes, fildes2), retval == -1 && errno
== EINTR);
return retval;
}
int r_open2(const char *path, int oflag)
{
int retval;
while (retval = open(path, oflag), retval == -1 && errno ==
EINTR);
return retval;
}
int r_open3(const char *path, int oflag, mode_t mode)
{
int retval;
while (retval = open(path, oflag, mode), retval == -1
&& errno == EINTR);
return retval;
}
ssize_t r_read(int fd, void *buf, size_t size)
{
ssize_t retval;
while (retval = read(fd, buf, size), retval == -1 && errno ==
EINTR);
return retval;
}
pid_t r_wait(int *stat_loc)
{
pid_t retval;
while (((retval = wait(stat_loc)) == -1) && (errno ==
97. strcat(names_found, name);
strcat(names_found, "|");
next_line = strtok_r(NULL, "n", &last);
}
quit_if(!strstr(names_found, "|1|"));
quit_if(!strstr(names_found, "|.|"));
quit_if(!strstr(names_found, "|..|"));
quit_if(!strstr(names_found, "|hello.txt|"));
quit_if(!strstr(names_found, "|oldfile.txt|"));
quit_if(!strstr(names_found, "|bigfile|"));
quit_if(entries != 6);
return 0;
}
/* ---------- Suite 4 Tests --------------- */
/* Test file_checksum */
int test_file_checksum(int argc, const char **argv)
{
setup();
char hello[] = "Hello";
unsigned short cksum = checksum(hello, strlen(hello), 0);
quit_if(IOERR_INVALID_ARGS != file_checksum(NULL));
quit_if(cksum != file_checksum(HELLO_FILE));
return 0;
}
/* in setup.sh()
mkdir -p
./testdata/1/2/3/4/5/6/7/8/9/10/11/12/13/14/15/16/17/18/19/20
cp ./testdata/hello.txt ./testdata/1/2/3/4/5/6/7/8/9/10/
cp ./testdata/oldfile.txt ./testdata/1/2/3/4/5/6/7/8/9/
This checksum algorithm commutes so we can calculate the the
final checksum as follows...
*/
98. /* Test dir_checksum */
int test_dir_checksum(int argc, const char **argv)
{
setup();
char dname[10];
int i;
unsigned short cksum;
int cksum2;
quit_if(IOERR_INVALID_ARGS != dir_checksum(NULL));
cksum = checksum("OldFile", 7, checksum("Hello", 5, 0));
for (i = 2; i <= 20; i++) {
sprintf(dname, "%d", i);
cksum = checksum(dname, strlen(dname), cksum);
}
cksum2 = dir_checksum(SUBDIR1_DIR);
quit_if(0 > cksum2);
quit_if(cksum != cksum2);
return 0;
}
/*
* Main entry point for test harness
*/
int run_lmp1_tests(int argc, const char **argv)
{
/* Tests can be invoked by matching their name or their suite
name or 'all' */
testentry_t tests[] = {
{"read", "suite1", test_file_read},
{"info", "suite1", test_file_info},
{"write", "suite1", test_file_write},
100. #if 1
#define VERBOSE(p) (p)
#else
#define VERBOSE(p) (0)
#endif
int file_read(char *path, int offset, void *buffer, size_t
bufbytes)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int file_info(char *path, void *buffer, size_t bufbytes)
{
if (!path || !buffer || bufbytes < 1)
return IOERR_INVALID_ARGS;
return IOERR_NOT_YET_IMPLEMENTED;
}
int file_write(char *path, int offset, void *buffer, size_t
bufbytes)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int file_create(char *path, char *pattern, int repeatcount)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int file_remove(char *path)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int dir_create(char *path)
101. {
return IOERR_NOT_YET_IMPLEMENTED;
}
int dir_list(char *path, void *buffer, size_t bufbytes)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int file_checksum(char *path)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
int dir_checksum(char *path)
{
return IOERR_NOT_YET_IMPLEMENTED;
}
assign4-2/assign4_part1/util.c
/*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************/
/* execl*/
#include <unistd.h>
/* errno */
#include <errno.h>
/* waitpid,WEXITSTATUS*/
#include <sys/types.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <wait.h>
/* fprintf*/
#include <stdio.h>
#include <string.h>
102. #include "util.h"
/* Print a detailed error message to the given file descriptor.
The pointers f,mesg,src can be null. */
void print_error(FILE * f, int errn, char *mesg, char *src, int
line)
{
char errmesg[255];
*errmesg = '0';
if (strerror_r(errn, errmesg, sizeof(errmesg)))
strcpy(errmesg, "Unknown");
fprintf(f ? f : stderr, "nFAILED AT %s(%d); %s%s.
errno=%d(%s)n",
src ? src : "notset", line, mesg ? "because " : "",
mesg ? mesg : "", errn, errmesg);
}
/* Print a detailed error message and then exit with a status
value of 1.*/
void quit_with_message(int errn, char *mesg, char *src, int
line)
{
print_error(stderr, errn, mesg, src, line);
exit(1);
}
/* Calculate a very simple checksum for a character buffer.*/
unsigned short checksum(char *buffer, size_t sz, unsigned short
val)
{
if ((!buffer) || (!sz))
return val;
while ((sz--) > 0) {
val += *(buffer++);
}
104. /*
* This is a file system benchmark which attempts to study
bottlenecks -
* it is named 'Bonnie' after Bonnie Raitt, who knows how to
use one.
*
* Commentary on Bonnie's operations may be found at
* http://www.textuality.com/bonnie/intro.html
*
* COPYRIGHT NOTICE:
* Copyright (c) Tim Bray, 1990-1996.
*
*/
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <stdio.h>
#include <errno.h>
#include <fcntl.h>
#include <time.h>
#include <sys/time.h>
#include <sys/types.h>
#include <sys/wait.h>
#if defined(SysV)
#include <limits.h>
#include <sys/times.h>
#else
#include <sys/resource.h>
#endif
#define IntSize (sizeof(int))
/*
* N.B. in seeker_reports, CPU appears and Start/End time, but
not Elapsed,
105. * so position 1 is re-used; icky data coupling.
*/
#define CPU (0)
#define Elapsed (1)
#define StartTime (1)
#define EndTime (2)
#define Seeks (4000)
#define UpdateSeek (10)
#define SeekProcCount (3)
#define Chunk (16384)
/* labels for the tests, used as an array index */
typedef enum {
Putc, ReWrite, FastWrite, Getc, FastRead, Lseek, TestCount
} tests_t;
static double cpu_so_far();
static void doseek(off_t where, int fd, int update);
static void get_delta_t(tests_t test);
static void io_error(char *message);
static void newfile(char *name, int *fd, FILE * *stream, int
create);
static void fill_file_char();
static void fill_file_block();
static void file_read_rewrite_block();
static void file_read_getc();
static void file_read_chunk();
#if defined(SysV)
/* System V wrappers for randomizers */
static long random();
static void srandom(int seed);
#endif
static void report(char *machine, off_t size);
106. static double time_so_far();
static void timestamp();
static void usage();
/*
* Housekeeping variables to build up timestamps for the tests;
* global to make it easy to keep track of the progress of time.
* all of this could have been done with non-global variables,
* but the code is easier to read this way and I don't anticipate
* much software engineering down the road
*/
static int basetime; /* when we started */
static double delta[(int) TestCount][2]; /* array of DeltaT
values */
static double last_cpustamp = 0.0; /* for computing delta-t */
static double last_timestamp = 0.0; /* for computing delta-t */
char name[Chunk];
FILE *stream;
int fd;
off_t words;
off_t size;
int buf[Chunk / IntSize];
int bufindex;
int chars[256];
int next;
/* entry point for LMP1 */
int bonnie_main(int argc, char **argv)
{
int child;
char *dir;
double first_start;
double last_stop;
int lseek_count = 0;
char *machine;
107. int seek_control[2];
int seek_feedback[2];
char seek_tickets[Seeks + SeekProcCount];
double seeker_report[3];
fd = -1;
basetime = (int) time((time_t *) NULL);
size = 100;
dir = ".";
machine = "";
/* parse the argument sent from the command line */
for (next = 1; next < argc; next++) {
if (strcmp(argv[next], "-s") == 0)
size = atol(argv[++next]);
else if (strcmp(argv[next], "-m") == 0)
machine = argv[++next];
else
usage();
}
if (size < 1) {
usage();
}
/*
CHECK SYSTEM CAPABILITY:
We proceed to check the size of files because 32-bit
machines has a limit
*/
if (sizeof(off_t) <= 4 && size > 2047) {
fprintf(stderr, "File too large for 32-bit machine, sorryn");
exit(1);
}
sprintf(name, "%s/LMP1.%d", dir, getpid());
108. /* The size is in Megabytes, and is rounded down to
multiples of Chunk */
size *= (1024 * 1024);
size = Chunk * (size / Chunk);
fprintf(stderr, "File '%s', size: %ldn", name, size);
fill_file_char(name, &fd, &stream); /* For specific details
please go down to the body of this function */
file_read_rewrite_block(name, &fd, &stream); /* For
specific details please go down to the body of this function */
fill_file_block(name, &fd, &stream); /* For specific details
please go down to the body of this function */
file_read_getc(name, &fd, &stream); /* For specific details
please go down to the body of this function */
/* use the frequency count */
for (words = 0; words < 256; words++)
sprintf((char *) buf, "%d", chars[words]);
file_read_chunk(name, &fd, &stream); /* For specific
details please go down to the body of this function */
/* use the frequency count */
for (words = 0; words < 256; words++)
sprintf((char *) buf, "%d", chars[words]);
/*
* Now test random seeks; first, set up for communicating
with children.
* The object of this e game is to do "Seeks" lseek() calls as
quickly
* as possible. So we'll farm them out among
SeekProcCount processes.
* We'll control them by writing 1-byte tickets down a pipe
which
* the children all read. We write "Seeks" bytes with val 1,
109. whichever
* child happens to get them does it and the right number of
seeks get
* done.
* The idea is that since the write() of the tickets is probably
* atomic, the parent process likely won't get scheduled
while the
* children are seeking away. If you draw a picture of the
likely
* timelines for three children, it seems likely that the seeks
will
* overlap very nicely with the process scheduling with the
effect
* that there will *always* be a seek() outstanding on the
file.
* Question: should the file be opened *before* the fork, so
that
* all the children are lseeking on the same underlying file
object?
*/
if (pipe(seek_feedback) == -1 || pipe(seek_control) == -1)
io_error("pipe");
for (next = 0; next < Seeks; next++)
seek_tickets[next] = 1;
for (; next < (Seeks + SeekProcCount); next++)
seek_tickets[next] = 0;
/* launch some parallel seek processes */
for (next = 0; next < SeekProcCount; next++) { /* for each
seek proc */
if ((child = fork()) == -1)
io_error("fork");
else if (child == 0) { /* child process */
/* set up and wait for the go-ahead */
close(seek_feedback[0]);
close(seek_control[1]);
110. newfile(name, &fd, &stream, 0);
srandom(getpid());
fprintf(stderr, "Seeker %d...", next + 1);
/* wait for the go-ahead */
if (read(seek_control[0], seek_tickets, 1) != 1)
io_error("read ticket");
timestamp();
seeker_report[StartTime] = time_so_far();
/* loop until we read a 0 ticket back from our parent */
while (seek_tickets[0]) { /* until Mom says stop */
doseek((long) (random() % (size / Chunk)), fd,
((lseek_count++ % UpdateSeek) == 0));
if (read(seek_control[0], seek_tickets, 1) != 1)
io_error("read ticket");
} /* until Mom says stop */
if (close(fd) == -1)
io_error("close after seek");
/* report to parent */
get_delta_t(Lseek);
seeker_report[EndTime] = time_so_far();
seeker_report[CPU] = delta[(int) Lseek][CPU];
if (write
(seek_feedback[1], seeker_report,
sizeof(seeker_report)) != sizeof(seeker_report))
io_error("pipe write");
exit(0);
} /* child process */
} /* for each seek proc */
/*
* Back in the parent; in an effort to ensure the children get
an even
* start, wait a few seconds for them to get scheduled, open
111. their
* files & so on.
*/
close(seek_feedback[1]);
close(seek_control[0]);
sleep(5);
fprintf(stderr, "start 'em...");
if (write(seek_control[1], seek_tickets, sizeof(seek_tickets))
!=
sizeof(seek_tickets))
io_error("write tickets");
/* read back from children */
for (next = 0; next < SeekProcCount; next++) { /* for each
child */
if (read
(seek_feedback[0], (char *) seeker_report,
sizeof(seeker_report)) != sizeof(seeker_report))
io_error("pipe read");
/*
* each child writes back its CPU, start & end times. The
elapsed time
* to do all the seeks is the time the first child started
until the
* time the last child stopped
*/
delta[(int) Lseek][CPU] += seeker_report[CPU];
if (next == 0) {/* first time */
first_start = seeker_report[StartTime];
last_stop = seeker_report[EndTime];
} /* first time */
else { /* not first time */
first_start = (first_start < seeker_report[StartTime]) ?
first_start : seeker_report[StartTime];
last_stop = (last_stop > seeker_report[EndTime]) ?
112. last_stop : seeker_report[EndTime];
} /* not first time */
if (wait(&child) == -1)
io_error("wait");
fprintf(stderr, "done...");
} /* for each child */
fprintf(stderr, "n");
delta[(int) Lseek][Elapsed] = last_stop - first_start;
report(machine, size);
unlink(name);
return EXIT_SUCCESS;
}
/****************************************************
*****************/
/* FUNCTION report */
/****************************************************
*****************/
/* INPUT: Machine description and size of file
*/
/****************************************************
*****************/
/* PROCESS: */
/* 1. Print in the monitor the results from the */
/* operations the program supports. */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void report(char *machine, off_t size)
{
printf(" ");
114. delta[(int) FastRead][CPU] / delta[(int)
FastRead][Elapsed] *
100.0);
printf("%5.1f %4.1fn",
((double) Seeks) / delta[(int) Lseek][Elapsed],
delta[(int) Lseek][CPU] / delta[(int) Lseek][Elapsed] *
100.0);
}
/****************************************************
*****************/
/* FUNCTION newfile */
/****************************************************
*****************/
/* INPUT: Name of the file, File Descriptor, Buffer, Create Flag
*/
/****************************************************
*****************/
/* PROCESS: */
/* 1. If Create Flag is one */
/* i) Checks if the file is unlinked */
/* a) If it is not returns error */
/* ii) Obatain File Descriptor with proper parameters
*/
/* and flags.NOTE: Use man pages to view the specific
*/
/* parameters open uses. Make sure you understand
*/
/* the return values, and see the errors the function */
/* returns) */
/* Else Create flag is not equal to zero */
/* Obtain file descriptor with proper parameters and
*/
/* flags.(NOTE: Use man pages to view the specific
*/
115. /* parameters open uses. Make sure you understand
*/
/* the return values, and see the errors the function */
/* returns) */
/* 2. Fill buffer when calling fdopen with proper */
/* parameters and flags.(NOTE: Use man pages to view
the */
/* specific parameters open uses. Make sure you
understand */
/* the return values, and see the errors the function */
/* returns) */
/* 3. Check stream */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void newfile(char *name, int *fd, FILE ** stream, int
create)
{
if (create) {
if (unlink(name) == -1 && *fd != -1)
io_error("unlink");
*fd = open(name, O_RDWR | O_CREAT | O_EXCL,
0777);
} else
*fd = open(name, O_RDWR, 0777);
if (*fd == -1)
io_error(name);
*stream = fdopen(*fd, "r+");
if (*stream == NULL)
io_error("fdopen");
}
116. /****************************************************
*****************/
/* FUNCTION fill_file_char */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Open file */
/* 2. Record timestamp */
/* 3. For cycle to fill the file one character at a time*/
/* until it reaches the EndOfFile(EOF) */
/* 4. Close file */
/* 5. Call get_delta_t to find the performance of putc */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void fill_file_char()
{
fprintf(stderr, "FUNCTION fill_file_char() start...");
newfile(name, &fd, &stream, 1);
timestamp();
for (words = 0; words < size; words++)
if (putc(words & 0x7f, stream) == EOF)
io_error("putc");
if (fclose(stream) == -1)
io_error("fclose after putc");
get_delta_t(Putc);
fprintf(stderr, "...done FUNCTION file_fill_char()n");
}
117. /****************************************************
*****************/
/* FUNCTION fill_file_block */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Open file */
/* 2. Initialize every position of the buffer */
/* 3. Record timestamp */
/* 4. FOR cycle so for each word you need to: */
/* i) properly set the buffer index so that it points */
/* at the correct position. */
/* ii) Call write.(NOTE: Use man pages to view the
*/
/* specific parameters write uses. Make sure you */
/* understand the return values, and see the errors */
/* the function returns) */
/* 4. Close file */
/* 5. Call get_delta_t to find the performance of putc */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void fill_file_block()
{
fprintf(stderr, "FUNCTION fill_file_block() start...");
newfile(name, &fd, &stream, 1);
for (words = 0; words < Chunk / IntSize; words++)
buf[words] = 0;
timestamp();
118. for (words = bufindex = 0; words < (size / Chunk); words++)
{
if (bufindex == (Chunk / IntSize))
bufindex = 0;
buf[bufindex++]++;
if (write(fd, (char *) buf, Chunk) == -1)
io_error("write(2)");
}
if (close(fd) == -1)
io_error("close after fast write");
get_delta_t(FastWrite);
fprintf(stderr, "...done FUNCTION fill_file_block()n");
}
/****************************************************
*****************/
/* FUNCTION file_read_rewrite_block */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Open file */
/* 2. Call lseek. (NOTE: Use man pages to view the
*/
/* specific parameters lseek uses. Make sure you
*/
/* understand the return values, and see the errors the
*/
/* function returns) */
/* 3. Record timestamp */
/* 4. Make sure the buffer index point to zero */
/* 5. Call read. (NOTE: Use man pages to view the
*/
/* specific parameters read uses. Make sure you
119. */
/* understand the return values, and see the errors the
*/
/* function returns) */
/* 6. While we can read a block, increment the index to
*/
/* point to the the next position. Call lseek and call */
/* write.(NOTE: Use man pages to view the specific
*/
/* parameters write uses. Make sure you understand the
*/
/* return values,and see the errors the function */
/* returns) */
/* Call read until the while condition is false. */
/* 7. Close file */
/* 8. Call get_delta_t to find the performance of putc */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void file_read_rewrite_block()
{
fprintf(stderr, "FUNCTION file_read_rewrite() start...");
newfile(name, &fd, &stream, 0);
if (lseek(fd, (off_t) 0, 0) == (off_t) - 1)
io_error("lseek(2) before rewrite");
fprintf(stderr, "Rewriting");
timestamp();
bufindex = 0;
if ((words = read(fd, (char *) buf, Chunk)) == -1)
io_error("rewrite read");
while (words == Chunk) {
120. if (bufindex == Chunk / IntSize)
bufindex = 0;
buf[bufindex++]++;
if (lseek(fd, (off_t) - words, 1) == -1)
io_error("relative lseek(2)");
if (write(fd, (char *) buf, words) == -1)
io_error("re write(2)");
if ((words = read(fd, (char *) buf, Chunk)) == -1)
io_error("rwrite read");
}
if (close(fd) == -1)
io_error("close after rewrite");
get_delta_t(ReWrite);
fprintf(stderr, "...done FUNCTION
file_read_rewrite_block()n");
}
/****************************************************
*****************/
/* FUNCTION file_read_getc */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Open file */
/* 2. Initialize every position of the buffer words */
/* 3. Record timestamp */
/* 4. FOR cycle to fill the file 1 byte at a time until */
/* it reaches the EndOfFile(EOF).Make sure you notice
*/
/* the increment of the index pointing at chars */
/* 7. Close file */
121. /* 8. Call get_delta_t to find the performance of getc */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void file_read_getc()
{
fprintf(stderr, "FUNCTION fill_read_getc() start...");
newfile(name, &fd, &stream, 0);
for (words = 0; words < 256; words++)
chars[words] = 0;
timestamp();
for (words = 0; words < size; words++) {
if ((next = getc(stream)) == EOF)
io_error("getc(3)");
chars[next]++;
}
if (fclose(stream) == -1)
io_error("fclose after getc");
get_delta_t(Getc);
fprintf(stderr, "...done FUNCTION file_read_getc()n");
}
/****************************************************
*****************/
/* FUNCTION file_read_chunk */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
122. /* 1. Open file */
/* 2. Call lseek().(NOTE:Use man pages to view the
*/
/* specific */
/* parameters write uses. Make sure you understand the
*/
/* return values,and see the errors the function */
/* returns) */
/* 3. Record timestamp */
/* 6. DO cycle read a block.(NOTE: Use man pages to
view*/
/* the specific parameters read uses. Make sure you
*/
/* understand the return values, and see the errors the
*/
/* function returns) Call read until the while condition is
*/
/* false. */
/* 7. Close file */
/* 8. Call get_delta_t to find the performance of getc */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void file_read_chunk()
{
fprintf(stderr, "FUNCTION file_read_chunk() start...");
newfile(name, &fd, &stream, 0);
if (lseek(fd, (off_t) 0, 0) == -1)
io_error("lseek before read");
timestamp();
do {
if ((words = read(fd, (char *) buf, Chunk)) == -1)
123. io_error("read(2)");
chars[buf[abs(buf[0]) % (Chunk / IntSize)] & 0x7f]++;
} while (words);
if (close(fd) == -1)
io_error("close after read");
get_delta_t(FastRead);
fprintf(stderr, "...done FUNCTION file_read_chunk()n");
}
/****************************************************
*****************/
/* FUNCTION usage */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Presents all the options the program has */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void usage()
{
fprintf(stderr, "usage: ./lmp1 [-s size-in-Mb] [-m machine-
label]n");
exit(1);
}
/****************************************************
*****************/
/* FUNCTION timestamp */
124. /****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Call time_so_far() and store it in last_timestamp */
/* 2. Call cpu_so_far() and store it in last_cpustamp */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void timestamp()
{
last_timestamp = time_so_far();
last_cpustamp = cpu_so_far();
}
/****************************************************
*****************/
/* FUNCTION get_delta_t */
/****************************************************
*****************/
/* INPUT: Receives the structure tests_t */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Identifies the procedure that was executed */
/* 2. Calls time_so_far() and deletes the value of */
/* of the global variable last_timestamp obtaining the
time */
/* the procedure spent. */
/* 3. Calls cpu_so_far() and substracts the value of */
125. /* of the global variable last_cpustamp obtaining the
*/
/* amount of CPU procedure spent. */
/****************************************************
*****************/
/* OUTPUT: doesn´t return any value because it is void
*/
/****************************************************
*****************/
static void get_delta_t(test)
tests_t test;
{
int which = (int) test;
delta[which][Elapsed] = time_so_far() - last_timestamp;
delta[which][CPU] = cpu_so_far() - last_cpustamp;
}
/****************************************************
*****************/
/* FUNCTION cpu_so_far */
/****************************************************
*****************/
/* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Identifies the System to check some variables */
/* if SysV */
/* i) Creates a structure tms. */
/* ii) returns the CPU time after adding over */
/* certain fields in the tms structure. */
/* Else */
/* i) Creates a structure rusage. */
/* ii) Calls getrusage().(NOTE: Use man pages */
/* to view the specific parameters write uses. */
126. /* Make sure you understand the return values, */
/* and see the errors the function returns). */
/* iii) returns the CPU time after adding over */
/* certain fields in the rusage structure. */
/****************************************************
*****************/
/* OUTPUT: return the CPU usage until the time it has been
called */
/****************************************************
*****************/
static double cpu_so_far()
{
#if defined(SysV)
struct tms tms;
if (times(&tms) == -1)
io_error("times");
return ((double) tms.tms_utime) / ((double)
sysconf(_SC_CLK_TCK)) +
((double) tms.tms_stime) / ((double)
sysconf(_SC_CLK_TCK));
#else
struct rusage rusage;
getrusage(RUSAGE_SELF, &rusage);
return ((double) rusage.ru_utime.tv_sec) +
(((double) rusage.ru_utime.tv_usec) / 1000000.0) +
((double) rusage.ru_stime.tv_sec) +
(((double) rusage.ru_stime.tv_usec) / 1000000.0);
#endif
}
/****************************************************
*****************/
/* FUNCTION time_so_far */
/****************************************************
*****************/
127. /* INPUT: does not receive any parameter */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Identifies the System to check some variables */
/* if SysV */
/* i) Creates a structure tms. */
/* ii) Call the times function and assign the */
/* value it returns to the variable val */
/* iii) returns the CPU time after dividing val*/
/* by the returning value from sysconf() */
/* Else */
/* i) Creates a structure timeval tp. */
/* ii) Calls gettimeofday().(NOTE:Use man
pages*/
/* to view the specific parameters */
/* gettimeofday uses. Make sure you understand
*/
/* the return values, and see the errors the */
/* function returns). */
/* iii) returns the CPU time after substractin */
/* certain fields in the tp structure. */
/****************************************************
*****************/
/* OUTPUT: return the time it has been used */
/****************************************************
*****************/
static double time_so_far()
{
#if defined(SysV)
int val;
struct tms tms;
if ((val = times(&tms)) == -1)
io_error("times");
128. return ((double) val) / ((double) sysconf(_SC_CLK_TCK));
#else
struct timeval tp;
if (gettimeofday(&tp, (struct timezone *) NULL) == -1)
io_error("gettimeofday");
return ((double) (tp.tv_sec - basetime)) +
(((double) tp.tv_usec) / 1000000.0);
#endif
}
/****************************************************
*****************/
/* FUNCTION io_error */
/****************************************************
*****************/
/* INPUT: Receives the error string */
/****************************************************
*****************/
/* PROCESS: */
/* 1. Call perror().(NOTE:Use man pages to view the
*/
/* specific parameters gettimeofday uses. Make sure you
*/
/* understand the return values, and see the errors the
*/
/* function returns). */
/* 2. Call exit().(NOTE:Use man pages to view the
*/
/* specific parameters gettimeofday uses. Make sure you
*/
/* understand the return values, and see the errors the
*/
/* function returns). */
/****************************************************
*****************/
129. /* OUTPUT: return the time it has been used */
/****************************************************
*****************/
static void io_error(char *message)
{
char buf[Chunk];
sprintf(buf, "Program: drastic I/O error (%s)", message);
perror(buf);
exit(1);
}
/*
* Do a typical-of-something random I/O. Any serious
application that
* has a random I/O bottleneck is going to be smart enough to
operate
* in a page mode.
* The 'where' argument is used as a chunk number
* To keep the cache from getting too clever, some pages must
be updated.
* However an application that updated each of many random
pages that
* it looked at is hard to imagine.
* However, it would be wrong to put the update percentage in
as a
* parameter - the effect is too nonlinear.
*/
static void doseek(off_t where, int fd, int update)
{
int buf[Chunk / IntSize];
off_t probe;
off_t size;
probe = where * Chunk;
if (lseek(fd, probe, 0) != probe)
130. io_error("lseek in doseek");
if ((size = read(fd, (char *) buf, Chunk)) == -1)
io_error("read in doseek");
/* every so often, update a block */
if (update) { /* update this block */
/* touch a word */
buf[((int) random() % (size / IntSize - 2)) + 1]--;
if (lseek(fd, (long) probe, 0) != probe)
io_error("lseek in doseek update");
if (write(fd, (char *) buf, size) == -1)
io_error("write in doseek");
} /* update this block */
}
#if defined(SysV)
static char randseed[32];
static void srandom(int seed)
{
sprintf(randseed, "%06d", seed);
}
static long random()
{
return nrand48(randseed);
}
#endif
assign4-2/assign4_part1/testrunner.h
/*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************/
typedef int (*test_fp) (int, const char **);
131. typedef struct {
const char *name;
const char *suite;
test_fp test_function;
} testentry_t;
int run_testrunner(int argc, const char **argv, testentry_t *
entries,
int entry_count);
void set_testrunner_default_timeout(int s);
void set_testrunner_timeout(int s);
assign4-2/assign4_part1/teardown.sh
#!/bin/sh
#*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************
rm -rf ./testdata
assign4-2/assign4_part1/restart.h
/*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************/
#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>
#ifndef ETIME
#define ETIME ETIMEDOUT
#endif
struct timeval add2currenttime(double seconds);
132. int copyfile(int fromfd, int tofd);
int r_close(int fildes);
int r_dup2(int fildes, int fildes2);
int r_open2(const char *path, int oflag);
int r_open3(const char *path, int oflag, mode_t mode);
ssize_t r_read(int fd, void *buf, size_t size);
pid_t r_wait(int *stat_loc);
pid_t r_waitpid(pid_t pid, int *stat_loc, int options);
ssize_t r_write(int fd, void *buf, size_t size);
ssize_t readblock(int fd, void *buf, size_t size);
int readline(int fd, char *buf, int nbytes);
ssize_t readtimed(int fd, void *buf, size_t nbyte, double
seconds);
int readwrite(int fromfd, int tofd);
int readwriteblock(int fromfd, int tofd, char *buf, int size);
int waitfdtimed(int fd, struct timeval end);
assign4-2/assign4_part1/util.h
/*************** YOU SHOULD NOT MODIFY ANYTHING
IN THIS FILE ***************/
#include <stdlib.h>
/* stdlib required for size_t */
#define quit_if_ne(p1,p2) {if((p1) != (p2))
quit_with_message((int)errno,"" #p1 "!=" #p2
,__FILE__,__LINE__);}
#define quit_if(mutley) {if(mutley)
quit_with_message((int)errno, #mutley,__FILE__,__LINE__);}
#define quit(mesg)
{quit_with_message((int)errno,mesg,__FILE__,__LINE__);}
void quit_with_message(int errn, char *mesg, char *src, int
line);
133. unsigned short checksum(char *buffer, size_t sz, unsigned short
val);
assign4-2/assign4_part1/fileio.h
#include <stdlib.h>
#define IOERR_INVALID_ARGS (-1)
#define IOERR_INVALID_PATH (-2)
#define IOERR_POSIX (-3)
#define IOERR_BUFFER_TOO_SMALL (-4)
#define IOERR_NOT_YET_IMPLEMENTED (-5)
/* You will implement all of the following functions in fileio.c.
*/
/*
ERROR HANDLING
These functions will support basic error handling:
If the arguments are bad (e.g., a pointer is NULL), then the
function should immediately return
IOERR_INVALID_ARGS.
If a POSIX error occurs, the function should return
IOERR_POSIX,
unless the error is due to a bad path, in which case the return
value is IOERR_INVALID_PATH.
These functions do not return if a POSIX function is
interrupted by
a signal; only dirlist returns IOERR_BUFFER_TOO_SMALL
(see below).
You may find some of the library functions in restart.c
useful.
134. COMMON PARAMETERS
path - file to be read
offest - where to start reading/writing from
buffer - buffer to write bytes into
bufbytes - maximum number of bytes to read
FUNCTION DESCRIPTIONS
int file_read(char *path, int offset, void *buffer, size_t
bufbytes);
Reads bytes from a file into the buffer.
Return value: >=0 number of bytes read, <0 ERROR (see
above)
int file_info(char *path, void *buffer, size_t bufbytes)
Writes into buffer a string that describes meta information
about
the file. The string is in format:
"Size:NNN Accessed:NNN Modified:NNN Type X"
X can be 'f' or 'd' (file or directory, respectively)
Size is in bytes
Accessed and Modified - accessed and modified times
(seconds since epoch)
int file_write(char *path, int offset, void *buffer, size_t
bufbytes);
Writes bytes from 'buffer' into file 'path' at position 'offset'.
Return value: >0 number of bytes written, <0 ERROR (see
above)
int file_create(char *path, char *pattern, int repeatcount);
Creates a new file with the string 'pattern' repeated
'repeatcount'
times.
Return value:0 Success , <0 ERROR (see above)
135. int file_remove(char *path);
Removes an existing file if it exists.
Return value: 0 file removed, <0 ERROR (see above)
int dir_create(char *path);
Creates a new directory.
Return value: 0 directory created, <0 ERROR (see above)
int dir_list(char *path, void *buffer, size_t bufbytes);
Writes a list file and directory names inside path (including
"."
and ".." entries). Each entry is line terminated with the
newline
character 'n'.
Return value: 0 success, <0 ERROR (see above)
Returns IOERR_BUFFER_TOO_SMALL if the buffer is not
large enough to
write all entries.
Hint: man opendir, readdir, closedir
int file_checksum(char *path)
Calculates a checksum value calculated by summing all the
bytes of a
file using an unsigned short.
Return value: >=0 checksum value, <0 ERROR (see above)
Hint: use the checksum function in util.c
int dir_checksum(char *path);
Recursively calculated a checksum: checksums of regular
files are
calculated using file_checksum; directory entries are
traversed,
also the subdirectory names are included in the checksum
calculation
See lmp1_tests.c for details of what we are looking for.
Return value: >=0 checksum value, <0 ERROR (see above)