// SIMMEMAN.CPP by LOUIS G. GUZIK #ifndef __SIMMEMAN_CPP #define __SIMMEMAN_CPP #include "simmeman.h" #include ///////////////////////////////////////////////////////////////////////////// int Screen::page = 0; Screen::Screen() { Crt.GraphicInit(); maxX = getmaxx()+1; maxY = getmaxy()+1; } inline Screen::~Screen() { Crt.GraphicClose(); } void Screen::DrawScr( Task *Jobs, Task *Runs, Task *Free ) { int i; char buffer[ 132 ]; char tmp[ 32 ]; setactivepage( page ); // DRAW THE HEADER LINES setcolor( WHITE ); outtextxy( 10, 2, "Simulation of Variable Partition Multiprogramming: by Louis G Guzik April 1994" ); // strcpy( buffer, "E)xit T)oggle Garbage Collecting" ); strcpy( buffer, "E)xit" ); outtextxy( 10, 12, buffer ); strcpy( buffer, "C++" ); outtextxy( 610, 12, buffer ); line( 0, 22, maxX, 22 ); // DRAW THE MEMORY AND JOB QUEUE BOXES ON THE SCREEN outtextxy( 57, 96, "MAIN MEMORY" ); outtextxy( 290, 30, "JOB QUEUE" ); setcolor( RED ); setfillstyle( CLOSE_DOT_FILL, WHITE ); bar3d( 49, 109, 151, 311, 0, 0 ); // MEMORY bar3d( 50, 40, 640, 70, 0, 0 ); // JOB QUEUE for( i=50; i<=620; i+=80 ) line( i, 40, i, 70 ); // ERROR CORRT setcolor( BLUE ); setfillstyle( SOLID_FILL, BLUE ); bar3d( 47, 312, 153, 321, 0, 0 ); // MEMORY // DRAW THE FILLED SPACE FOR THE OP SYS 11K setcolor( RED ); setfillstyle( SOLID_FILL, YELLOW ); bar3d( 50, 110, 150, 132, 0, 0 ); // MEMORY OP. SYS. setcolor( BLACK ); outtextxy( 60, 118, "OP SYS 11K" ); // DRAW HORZ. LINES MARKING THE K VALUES OF MEMORY setcolor( WHITE ); for( i=110; i<= 310; i+=20 ) { line( 153, i, 200, i ); itoa( (i-110)/2, buffer, 10 ); strcat( buffer, "K" ); outtextxy( 205, i-3, buffer ); } // TIME setcolor( WHITE ); outtextxy( 435, 84, "TIME" ); // STATS setcolor( WHITE ); outtextxy( 408, 140, "MEMORY STATS" ); setcolor( RED ); setfillstyle( SOLID_FILL, LIGHTGRAY ); bar3d( 300, 150, 600, 330, 0, 0 ); setcolor( BLACK ); itoa( UsedList->TotalJobs, tmp, 10 ); strcpy( buffer, "Total Jobs Serviced: " ); strcat( buffer, tmp ); outtextxy( 310, 160, buffer ); ltoa( UsedList->TotalSizes/UsedList->TotalJobs, tmp, 10 ); strcpy( buffer, "Avg. Size: " ); strcat( buffer, tmp ); strcat( buffer, " K bytes" ); outtextxy( 310, 175, buffer ); itoa( UsedList->TotalTime/UsedList->TotalJobs, tmp, 10 ); strcpy( buffer, "Avg Run Time: " ); strcat( buffer, tmp ); strcat( buffer, " secs" ); outtextxy( 310, 190, buffer ); outtextxy( 310, 205, "Garbage Collect:" ); if( GC ) { setcolor( RED ); outtextxy( 449, 205, "ON" ); } else { setcolor( WHITE ); outtextxy( 449, 205, "OFF" ); } // TOTALS setcolor( GREEN ); setfillstyle( SOLID_FILL, BLUE ); bar3d( 20, 320, 235, 345, 0, 0 ); // MEMORY OP. SYS. Task *task; int totalfree = 0; int totalused = 11; float remain; static long TFree = 0; static long TUsed = 11; static long Count = 0; Count++; task = Free; while( task ) { totalfree += ( task->EndAddr - task->BeginAddr ); task = task->Next; } TFree += totalfree; ltoa( totalfree, tmp, 10 ); strcpy( buffer, "Total Free " ); if( totalfree < 10 ) strcat( buffer, " " ); strcat( buffer, tmp ); strcat( buffer, " K" ); setcolor( WHITE ); outtextxy( 30, 325, buffer ); if( totalfree == 0 ) { setcolor( RED ); outtextxy( 330, 305, "BINGO" ); } task = Runs; while( task ) { totalused += task->Size; task = task->Next; } TUsed += totalused; ltoa( totalused, tmp, 10 ); strcpy( buffer, "Total Used " ); if( totalused < 10 ) strcat( buffer, " " ); strcat( buffer, tmp ); strcat( buffer, " K" ); setcolor( WHITE ); outtextxy( 30, 335, buffer ); itoa( totalfree + totalused, tmp, 10 ); strcpy( buffer, "= " ); strcat( buffer, tmp ); strcat( buffer, " K" ); outtextxy( 158, 328, buffer ); setcolor( BLACK ); int xx; int xxx; xx = TFree/Count; if( TFree%Count > .5 ) xx++; itoa( xx, tmp, 10 ); strcpy( buffer, "Avg Total Free Space: " ); if( xx < 10 ) strcat( buffer, " " ); strcat( buffer, tmp ); outtextxy( 310, 220, buffer ); xxx = TUsed/Count; if( TUsed%Count > .5 ) ;// xxx++; itoa( xxx, tmp, 10 ); strcpy( buffer, "Avg Total Used Space: " ); strcat( buffer, tmp ); outtextxy( 310, 235, buffer ); outtextxy( 478, 240, "----" ); itoa( xx + xxx, tmp, 10 ); if( xx + xxx < 100 ) strcpy( buffer, " " ); else strcpy( buffer, "" ); strcat( buffer, tmp ); strcat( buffer, " K" ); outtextxy( 478, 247, buffer ); if( TService ) ltoa( AvgService/TService, tmp, 10 ); else strcpy( tmp, "0" ); strcpy( buffer, "Avg Service Time: " ); strcat( buffer, tmp ); strcat( buffer, " secs" ); outtextxy( 310, 265, buffer ); // DRAW THE JOBS IN THE JOB QUEUE int x = 50; int y = 40; while( Jobs ) { // DRAW SMALL JOB BOX setcolor( RED ); setfillstyle( SOLID_FILL, WHITE ); bar3d( x, y, x+80, y+30, 0, 0 ); // MEMORY OP. SYS. // WRITE TEXT INFO FOR JOB setcolor( BLACK ); strcpy( buffer, "J-" ); itoa( Jobs->ID, tmp, 10 ); strcat( buffer, tmp ); outtextxy( x+12, y+5, buffer ); strcpy( buffer, Jobs->SizeCh ); strcat( buffer, " T-" ); itoa( Jobs->RunTime, tmp, 10 ); strcat( buffer, tmp ); outtextxy( x+12, y+19, buffer ); // INCERMENT Jobs = Jobs->Next; x+=80; } // DRAW THE RUNNING JOBS IN MEMORY x = 50; int y1; int y2; while( Runs ) { if( Runs->RunTime != -1 ) { // DRAW SMALL RUN BOX setcolor( RED ); setfillstyle( SOLID_FILL, WHITE ); y1 = Runs->BeginAddr * 2; y2 = Runs->EndAddr * 2; bar3d( x, y1+110, x+100, y2+110, 0, 0 ); // WRITE TEXT INFO FOR RUNS setcolor( BLACK ); strcpy( buffer, "J" ); itoa( Runs->ID, tmp, 10 ); strcat( buffer, tmp ); strcat( buffer, " T" ); itoa( Runs->RunTime, tmp, 10 ); strcat( buffer, tmp ); strcat( buffer, " " ); strcat( buffer, Runs->SizeCh ); outtextxy( x+3, y1+113, buffer ); // INCERMENT } Runs = Runs->Next; } int err = 1; // WRITE THE FREE SPACE IN MEMORY while( Free ) { i = Free->EndAddr - Free->BeginAddr; // ERROR CORRECTION /////////////// if( Free->BeginAddr > 100 ) { if( Free == FreeList ) FreeList = FreeList->Next; Free->Disconnect(); delete Free; i = 0; break; } if( err && UsedList && Free->Next && Free->BeginAddr > Free->Next->BeginAddr ) { err = 0; // cout << "E " // << "\007" // ; Free->Next->BeginAddr = Free->EndAddr; Free->Next->EndAddr = Free->EndAddr + i; // Crt.GraphicClear( BLUE ); } // ERROR CORRECTION //////////////// if( i > 3 ) { itoa( i, tmp, 10 ); strcpy( buffer, "Free " ); strcat( buffer, tmp ); strcat( buffer, " K" ); setcolor( WHITE ); outtextxy( x+15, Free->BeginAddr*2+112, buffer ); } Free = Free->Next; } setvisualpage( page++ ); if( page > 1 ) page = 0; } ///////////////////////////////////////////////////////////////////////////// inline Time::Time() { ; } inline Time::~Time() { ; } void Time::Display( int x, int y, int depth, int flag, int fill, int color ) { #include static time_t Start = time( NULL ); long elapsed; char datebuf[9]; char timebuf[9]; char buffer[32]; char tmp[32]; int t; _strdate( datebuf ); _strtime( timebuf ); setcolor( BLACK ); strcpy( buffer, "Elapsed Time: " ); elapsed = time( NULL ) - Start; t = elapsed; if( t > 3599 ) { itoa( t/3600, tmp, 10 ); if( t/3600 < 10 ) strcat( buffer, "0" ); strcat( buffer, tmp ); strcat( buffer, ":"); t = t - ((t/3600) * 3600); } if( t > 59 ) { itoa( t/60, tmp, 10 ); if( t/60 < 10 ) strcat( buffer, "0" ); strcat( buffer, tmp ); strcat( buffer, ":"); t = t - ((t/60) * 60); } itoa( t, tmp, 10 ); if( t < 10 ) strcat( buffer, "0" ); strcat( buffer, tmp ); outtextxy( 310, 280, buffer ); setcolor( RED ); setfillstyle( fill, color ); bar3d( x, y, x+80, y+25, depth, flag ); setcolor( BLACK ); outtextxy( x+10, y+10, timebuf ); } ///////////////////////////////////////////////////////////////////////////// int Task::SeqNumber = -1; long Task::TotalSizes = 11; int Task::TotalTime = 0; int Task::TotalJobs = 0; Task::Task() { int i; char tmp[ 32 ]; Prev = NULL; Next = NULL; StopTime = 0; BeginAddr = 0; EndAddr = 0; Service = time( NULL ); // SEQ NUMBER ID if( SeqNumber > 999 ) SeqNumber = 1; SeqNumber++; ID = SeqNumber; // FOR RUNTIME i = rand() % 90; while( i < 6 || i > 13 ) // SPEED { i = rand() % 100; } RunTime = i; // FOR SIZE IN K i = rand() % 90; while( i < 9 || i > 24 ) { i = rand() % 100; } Size = i; itoa( Size, tmp, 10 ); strcpy( SizeCh, tmp ); strcat( SizeCh, "K" ); } inline Task::~Task() { ; } Task *Task::Connect_Left_of( Task *Right ) { Task *Left = Right->Prev; if( Right ) { Prev = Left; Right->Prev = this; Next = Right; if( Left ) Left->Next = this; return( this ); } else { Next = NULL; return( NULL ); } } Task *Task::Connect_Right_of( Task *Left ) { Task *Right = Left->Next; if( Left ) { Next = Right; Left->Next = this; Prev = Left; if( Right ) Right->Prev = this; return( this ); } else { Prev = NULL; return( NULL ); } } Task *Task::Disconnect() { Task *Left = Prev; Task *Right = Next; if( Left ) Left->Next = this->Next; if( Right ) Right->Prev = this->Prev; this->Prev = NULL; this->Next = NULL; return( this ); } ///////////////////////////////////////////////////////////////////////////// int Dispatch() { int flag = 0; // INIT, COULD NOT DISPATCH ANY JOBS Task *jobptr; Task *freeptr; Task *usedptr; Task *task; Task *tasktmp; Task *taskloop; int freesize; int size; int found; // DISPATCH A JOB taskloop = JobQ; while( taskloop ) { size = taskloop->Size; freeptr = FreeList; found = 0; while( freeptr && ! found ) { freesize = freeptr->EndAddr - freeptr->BeginAddr; // WE FOUND FREE SPACE if( size <= freesize && freeptr->BeginAddr > 10 ) { found = 1; // DISPATCHED AT LEAST ONE JOB flag = 1; jobptr = taskloop; taskloop = taskloop->Next; UsedList->TotalJobs = UsedList->TotalJobs + 1; UsedList->TotalSizes = UsedList->TotalSizes + jobptr->Size; UsedList->TotalTime = UsedList->TotalTime + jobptr->RunTime; // IF HEAD if( JobQ == jobptr ) JobQ = JobQ->Next; // REMOVE IT FROM JOB QUEUE jobptr->Disconnect(); // NO USED LIST TO ADD TOO if( ! UsedList ) { UsedList = jobptr; UsedList->BeginAddr = freeptr->BeginAddr; UsedList->EndAddr = UsedList->BeginAddr + size; UsedList->StopTime = UsedList->RunTime + time( NULL ); } // PLACE IT IN ORDER else { jobptr->BeginAddr = freeptr->BeginAddr; jobptr->EndAddr = freeptr->BeginAddr + size; if( jobptr->BeginAddr < UsedList->BeginAddr ) { jobptr->Connect_Left_of( UsedList ); jobptr->StopTime = jobptr->RunTime + time( NULL ); UsedList = jobptr; } else { task = UsedList; while( task->Next && jobptr->BeginAddr > task->Next->BeginAddr ) task = task->Next; jobptr->Connect_Right_of( task ); jobptr->StopTime = jobptr->RunTime + time( NULL ); } } // ADJUST FREE SPACE LIST // THE CURRENT FREE NODE WILL HAVE NO FREE SPACE, SO REMOVE IT if( size == freesize ) { if( freeptr == FreeList ) FreeList = FreeList->Next; freeptr->Disconnect(); delete freeptr; } // PLACE IT IN ORDER else { if( freeptr == FreeList ) FreeList->BeginAddr = FreeList->BeginAddr + size; else { freeptr->Disconnect(); freeptr->BeginAddr = freeptr->BeginAddr + size; if( freeptr->BeginAddr <= FreeList->BeginAddr ) { freeptr->Connect_Left_of( FreeList ); FreeList = freeptr; } else { task = FreeList; while( task->Next && freeptr->BeginAddr > task->Next->BeginAddr ) task = task->Next; freeptr->Connect_Right_of( task ); } } } } // SIZE TO SMALL, TRY NEXT FREE SPACE else { found = 0; freeptr = freeptr->Next; } // IF FOUND ANY FREE SPACE BREAK OUT OF LOOP if( found ) break; } // while( freeptr ) if( ! found ) taskloop = taskloop->Next; } // while( taskloop ) // CHECK TO SEE IF ANY JOBS HAVE ENDED usedptr = UsedList; while( usedptr ) { if( usedptr->StopTime < time( NULL ) ) { // IF IT'S THE HEAD AvgService += (long) time(NULL) - usedptr->Service; TService++; if( usedptr == UsedList ) UsedList = usedptr->Next; usedptr->Disconnect(); if( ! FreeList ) FreeList = usedptr; else if( usedptr->BeginAddr < FreeList->BeginAddr ) { usedptr->Connect_Left_of( FreeList ); FreeList = usedptr; } // PLACE IT IN ORDER else { tasktmp = FreeList; while( tasktmp->Next && usedptr->BeginAddr > tasktmp->Next->BeginAddr ) tasktmp = tasktmp->Next; usedptr->Connect_Right_of( tasktmp ); } usedptr = UsedList; } else usedptr = usedptr->Next; } // while( usedptr ) // COALESCE THE FREE LIST Task *ptr = FreeList; Task *tmp; while( ptr ) { if( ptr->BeginAddr < FreeList->BeginAddr ) { ptr->Disconnect(); ptr->Connect_Left_of( FreeList ); FreeList = ptr; } else ptr = ptr->Next; } ptr = FreeList; while( ptr ) { found = 0; tmp = ptr->Next; while( tmp && ! found ) { if( ptr->EndAddr == tmp->BeginAddr ) found = 1; else tmp = tmp->Next; } if( found ) { ptr->EndAddr = tmp->EndAddr; ptr = tmp->Next; tmp->Disconnect(); delete tmp; } else ptr = ptr->Next; } // NO JOBQ, NOTHING TO DISPATCH, SO NOTHING NOT TO DISPATCH if( ! JobQ ) flag = 1; return( flag ); } ///////////////////////////////////////////////////////////////////////////// int GarbageCollect() { Task *freeptr = FreeList; Task *usedptr = UsedList; int freesize; int flag = 0; // COULD NOT GARBAGE COLLECT // GARBAGE COLLECT // while( freeptr && usedptr && ! flag ) if( FreeList && UsedList ) { // while( freeptr && usedptr && ! flag ) freesize = ( FreeList->EndAddr - FreeList->BeginAddr); while( usedptr && ! flag ) { if( FreeList->BeginAddr <= usedptr->BeginAddr && FreeList->BeginAddr > 11 && freesize > 0 ) { flag = 1; // IF FOUND, ADJUST SIZES /* usedptr->BeginAddr = usedptr->BeginAddr - freesize; usedptr->EndAddr = usedptr->EndAddr - freesize; freeptr->BeginAddr = usedptr->EndAddr; freeptr->EndAddr = freeptr->BeginAddr + freesize; */ usedptr->BeginAddr = FreeList->BeginAddr; usedptr->EndAddr = ( FreeList->BeginAddr + usedptr->Size ); FreeList->BeginAddr = FreeList->BeginAddr + usedptr->Size; FreeList->EndAddr = ( FreeList->BeginAddr + freesize ); char tmp[256]; char buffer[256]; freesize = ( FreeList->EndAddr - FreeList->BeginAddr); itoa( freesize, tmp, 10 ); strcpy( buffer, "freesize: " ); strcat( buffer, tmp ); setcolor( WHITE ); // outtextxy( 310, 321, buffer ); break; } else usedptr = usedptr->Next; } // usedptr = UsedList; // if( ! flag ) // freeptr = freeptr->Next; } return( flag ); } ///////////////////////////////////////////////////////////////////////////// Task *CreateJobs( int Count ) { Task *Head = NULL; Task *tmp; Task *ptr; if( Count ) { Head = new Task; Count--; ptr = Head; for( ; Count > 0; Count-- ) { tmp = new Task; tmp->Connect_Right_of( ptr ); ptr = tmp; } } return( Head ); } ///////////////////////////////////////////////////////////////////////////// #endif // __SIMMEMAN_CPP