CSE 473 PSU Thread Schedulers Report Overall Design and Implementation Essay
THE CODING PART IS FINISHED, ALL I NEED IS THE PROJECT REPORTINSTURCTION FOR THE REPORT AS FOLLOWS:- overall design of your implementation including how you broke it up into pieces and did it modularly.- any challenges/trade-offs that you faced and how you handled them- partitioning of work between team members (should be evenly distributed for two teammates)- any specifics/quirks that we need to know about your projectTHE REPORT ONLY NEEDS TO BE A BRIEF REPORT NOT A DETAILED REPORTTHE PROJECT CODE IS IN THE ATTACHMENTbelow is the project detail, I will be happy to provide any support documentsCSE 473 Project 1: Thread Schedulers(due before 11:59PM, Oct 12 thru Github - NO MORE EXTENSIONS WILL BE GIVEN!)Please direct all your project-related questions/clarifications to the TAs.Academic Integrity Statement:The University defines academic integrity as the pursuit of scholarly activity in an open, honest and responsible manner. All students should act with personal integrity, respect other students' dignity, rights and property, and help create and maintain an environment in which all can succeed through the fruits of their efforts (refer to Senate Policy 49-20. Dishonesty of any kind will not be tolerated in this course. Dishonesty includes, but is not limited to, cheating, plagiarizing, fabricating information or citations, facilitating acts of academic dishonesty by others, having unauthorized possession of examinations, submitting work of another person or work previously used without informing the instructor, or tampering with the academic work of other students. Students who are found to be dishonest will receive academic sanctions and will be reported to the University's Office of Student Conduct for possible further disciplinary sanctions (refer to Senate Policy G-9). The Academic Integrity policy for the Department of Computer Science and Engineering for programming projects can be explicitly found at EECS Academic Integrity Policy (Links to an external site.). Please go through it carefully and do ask the instructor for any clarifications if something is not clear.No exchange of code or collaborations is permitted across teams nor is use of code from any Internet sources. Both giver(s) and taker(s) will be punished harshly with a zero in the Project Grade. Hence, make sure that your code is not visible to anyone outside your team!DescriptionIn this project, you will implement four thread schedulers for a uni-processor environment with support for semaphore synchronization:First Come First Served (FCFS) - no preemptionShortest Remaining Time First (SRTF) - with preemptionPriority Based Scheduling (PBS) - with preemption, andMulti Level Feedback Queue (MLFQ) - with preemption and aging.RequirementsYou will be given a test program which creates many threads each performing multiples of the following activities during their execution.Use the CPU for a duration of burstlength using schedule_me().P: to wait on a counting semaphore, blocking till the corresponding semaphore is signalled or has been signalledV: to signal a semaphore (signal), and in the process waking up any waiting thread.The test program will take an input file and perform the required activities. We will provide code to parse the input file and invoke the appropriate functions that you have to implement.The thread will progress, when given the CPU (on a single CPU system), to execute its burstlength. Whenever it is done with the CPU burst, and there is no other event (semaphore), the thread completes and leaves the system. On the other hand, if it does a P() on a semaphore, it will block (giving up the CPU), until some other thread does a V() on that semaphore. Coming out of P(), it will go back and join the READY queue for the subsequent CPU burstlength, similar to how it would have joined had the thread been newly created. This is what your code should achieve and the READY queue service discipline should follow one of the 4 schedulers mentioned above.Below is an illustrative example, with input and the Gantt Chart for FCFS and SRTF:DeliverablesTo implement this, your scheduler should implement the following interfaces in C, and all these functions should be provided in a new file called scheduler.c.YOUR IMPLEMENTATION SHOULD BE MULTI-THREAD SAFE ACROSS ALL THESE FUNCTIONs.void init_scheduler(int sched_type);This function will be invoked once in the beginning for initializing anything that you may want in your code.The parameter sched_type will contain values from 0 to 3, denoting 0-FCFS, 1-SRTF, 2-PBS, 3-MLFQ.The following are common parameters for the next 3 interface definitions (schedule_me(), P(), V())float currentTime;currentTime indicates the time at which the call is made by some thread. No two invocations of any of the functions will have the same currentTime value. However, it is possible that when a thread is executing one of your functions, another thread invokes one of the functions, albeit with a higher currentTime. Your scheduler should maintain a global current time value which should be updated based on the currentTime value passed to the invocations of the 3 functions by different threads.NOTE: This currentTime can take float values.int tid;tid indicates the thread identification number of the calling thread.When it eventually returns from each of these functions, the function should return the global current time value to the thread. Note that we are simplifying your implementation so that time quanta are always assigned at integral values, and these quanta will never start at non-integral time values (e.g. a thread will never relinquish the CPU for I/O at non-integral time values, even if it arrives in the system at non-integral time values). This is further explained below.int schedule_me(float currentTime, int tid, int remainingTime, int tprio); // returns current global timeA thread will call this function for every timer tick, with the current time and the remaining time in its CPU burst. You should return from this function only when this thread has got the CPU until the next timer tick. Else it should block until it does. As it keeps getting the CPU, the remaining time in its burst will accordingly reduce. This function should implement the actual scheduler functionality based on the initialized scheduler type in the init_scheduler() function.It takes 4 input arguments from the calling thread. They are:currentTime: (as described above)tid: (as described above)remainingTime indicates the amount of remaining CPU time requested by the thread for its current CPU burst. The remainingTime will always be an integer number. Note that this will keep decreasing (by 1 unit for each subsequent call) as it keeps getting the CPU.tprio indicates the priority of the thread. tprio can take a value between 1 and 5, 1 being the highest priority.int P(float currentTime, int tid, int sem_id); // returns current global timecurrentTime and tid are as described before.This function should implement the WAIT operation for a semaphore identified by sem_id. This is a blocking call and returns when the calling thread gets a new/pending signal from another thread.NOTE: The valid maximum number for sem_id will be defined by the global constant SEM_ID_MAX (Semaphore numbers ranging from 0..SEM_ID_MAX-1 are valid). This will be defined in your scheduler.c file. You should provide support for a semaphore identified by the sem_id.int V(float currentTime, int tid, int sem_id); // returns current global timecurrentTime and tid are as described above.This function should implement the SIGNAL operation for a semaphore identified by sem_id. Valid numbers for sem_id are as explained above.Implementation DirectionsA thread scheduler requires maintaining a state machine involving 3 states:- READY, RUNNING, and BLOCKED. Based on the scheduling policy followed and the activity it performs, every thread should be queued up in exactly one of these states. As, we have a uni-processor environment, only ONE thread can be in RUNNING state at any time.The READY queue should be maintained as dictated by the appropriate (one of the 4) scheduling policy. When a thread comes out of the BLOCKED state, by being SIGNALed on a Semaphore (V() operation), it should go back and join the READY queue for its subsequent CPU burst. This will again be determined by its priority and scheduling discipline, similar to how the thread joined the READY queue upon its creation. While logically the BLOCKED state may appear as a single queue, in practice you should implement this as multiple queues - one for each semaphore on which a thread may be blocked. Note that multiple threads could be concurrently blocked on the same semaphore and the V() operation should wakeup the first in line.Scheduling decisions should be made only at integral time units. Note that these would also be pre-emption points based on the type of scheduler. The global current time maintained by your scheduler should be updated based on the currentTime being passed from the threads, and also the elapsing of time (every 1 integral time unit for every call in the CPU burst). For instance, say T1 arrives at time 1.1, and calls schedule_me() with a remainingTime = 2. Initially the globalTime will be 0. When T1 calls schedule_me(), it should get the CPU at globalTime = 2 and return from the function with this value (since scheduling decisions are made only at integral values, it is as though this thread arrived at time 2). It will subsequently make two more invocations to schedule_me(), at times 3 and 4, with a corresponding remaining time of 1 and 0 respectively. schedule_me() should return back time values of 3 and 4 respectively at these 2 points.Your scheduler should not use any system timer interrupt functionality - the only notion of time for your scheduler is the currentTime indicated by the threads. When a thread has finished all its work (CPU bursts and synchronizations) and is ready to terminate, it will invoke the schedule_me() function with remainingTime = 0. This thread will no longer be in consideration for scheduling.Return from the schedule_me() function indicates that the thread is either granted the CPU or has completed its CPU burst (when it calls the schedule_me() function with remainingTime = 0).Since multiple threads could be simultaneously accessing common data structures (like the READY queue), make sure you use pthread synchronization primitives at appropriate places to ensure there are no race conditions. pthread calls should be used to block threads until they are supposed to get the CPU.THERE SHOULD NOT BE ANY BUSY/SPIN WAITs of ANY KIND IN YOUR CODE. You should always block the thread that cannot proceed using a pthread synchronization mechanism.Boiler-plate source filesAll source files will be in the Git repository. You are provided with a file called project1.c which creates threads using the pthread library and invokes the above four functions. You are NOT to make any edits to project1.c - all your code goes in to scheduler.c. The application (the main function in 'project1.c') will take an integer command line argument specifying the type of scheduler to be used ([0-3]: 0-FCFS, 1-SRTF, 2-PBS, 3-MLFQ as mentioned above) which will be passed to the init_scheduler function. The file 'project1.c' parses an input file which indicates the thread arrivals and their execution times (burst length) and semaphore operations, and issues corresponding schedule_me()/P()/V() calls. 'project1.c' also spits out an output file which indicates the actual schedule order (Gantt chart) of the threads.The file, project1.c is in the Git repository.Compiling and RunningTo compile your code (project1.c and scheduler.c) we provide a sample Makefile. Run the Makefile script using the command 'make'. This will result in the generation of the binary 'out'.To run the binary use the command: out [scheduler_type] [input_file]where [scheduler_type] is 0,1,2 or 3 indicating FCFS, SRTF, PBS and MLFQ respectively. [input_file] is the path to the input file.Debugging your code with test casesFor testing/debugging your work, a set of input files and their corresponding output files are provided in the Git repository.Input files are available in the directory 'TestInputs' which can be used by all schedulers. Each line in the input file is represented in the following format,Every line has the following:[arrival time][tab][thread id][tab][priority]followed by multiples of either one of the following:-[tab][burst length][tab][P][semaphore-id][tab][V][semaphore-id]You do not need to worry about reading/parsing the input files. It will be done in the code made available to you in project1.c.The output is a Gantt chart where each line is represented in the following format,[start time] - [end time]: [thread id]The output files corresponding to the input files are available in the directory 'TestOutputs' for each scheduler type.The test cases are NOT limited to these files. There will be additional test cases on which your code will be evaluated.Details on the scheduling policiesBelow is a brief description of the four kind of schedulers that you will implement:FCFS: This scheduling scheme is non-preemption based and schedules the threads based on who arrives first at the scheduler. The threads are scheduled for the entire remainingTime duration without preemption in between. Assume no two threads arrive at the same time.SRTF: This scheduling scheme is preemption based and schedules the threads based on who has the least remainingTime value. If two or more threads have the same remainingTime value, then the thread with least currentTime is chosen for scheduling. Further note that when a thread with a shorter execution/remaining time arrives in the system at a non-integral time value, it still waits for the next integral boundary before pre-empting the currently running thread.PBS: This scheduling scheme is preemption based and schedules the threads based on who has the highest priority. If two or more threads have the same tprio value, then the thread with least currentTime is chosen for scheduling.MLFQ: This scheduling scheme is preemption based with multi-level feedback queues. The READY queue should be implemented as a multi-level queue with 5 levels. The time quantum for the 5 levels (starting from the highest level) are 5, 10, 15, 20, and 25 time units respectively. Threads initially join the READY queue at the highest level. When a thread completes its time quantum on a particular level, it will be moved to the next lower level. Your scheduler should select threads from a lower level queue only when there are no threads in any of the higher levels. A thread entering the READY queue at the highest level will preempt threads at the lower levels at the next integral time unit. Within a level, you should use FCFS to select the threads. You will use Round-robin at the last level.Note that tprio is only used in PBS, and is a don't care value for the other 3 schemes.Some useful pthread calls:You are allowed to use the pthread ( pthread.h (Links to an external site.) ) thread library to implement the scheduler functionality. You may find the following pthread functions useful when implementing the scheduler. You can click on the functions to view their man pages.int pthread_cond_init(pthread_cond_t *, const pthread_condattr_t *); (Links to an external site.)int pthread_cond_signal(pthread_cond_t *); (Links to an external site.)int pthread_cond_wait(pthread_cond_t *, pthread_mutex_t *); (Links to an external site.)int pthread_cond_destroy(pthread_cond_t *); (Links to an external site.)pthread_t pthread_self(void); (Links to an external site.)int pthread_mutex_init(pthread_mutex_t*, const pthread_mutexattr_t *); (Links to an external site.)int pthread_mutex_lock(pthread_mutex_t* ) ; (Links to an external site.)int pthread_mutex_unlock(pthread_mutex_t* ); (Links to an external site.)int pthread_mutex_destroy(pthread_mutex_ t* ); (Links to an external site.)Additional Information, PLEASE READ CAREFULLY!!!An illustrative figure to describe the operation of the PBS scheduler is provided here.The inputs and sample outputs are given just for illustrative purposes to test your code. You can create more extensive input files for further testing.The TAs WILL surprise you with several other test inputs during the demo and your routines should still work.Please stay tuned constantly to the canvas page for the exact and latest interface functions you need to implement, their arguments, test programs, examples, documentation/manuals and announcements.You can work in teams (at most 2 per team - they could be across sections), or individually, for the project. You are free to choose your partner but if either of you choose to drop out of your team for any reason at any time, each of you will be individually responsible for implementing and demonstrating the entire project and writing the project report by the designated deadline. If you have difficulty finding a partner, give your name to the TAs who will maintain an online list of students without partners to pair you up.Even though you will work in pairs, each of you should be fully familiar with the entire code and be prepared to answer a range of questions related to the entire project. It will be a good idea to work together at least during the initial design of the code. You should also ensure that there is a fair division of labor between the members.All the code-bases will be tested on the W-204 Linux Lab machines located on the second floor of Westgate. Ensure you test and run them in that environment.GitHub Invitation to create private repository (Links to an external site.)Submission GuidelinesEnsure your Git local environment is configured and setup, and you have signed up for GitHub. (Refer to P0 for detailed steps on this). You should have a valid GitHub account (personal accounts are fine).Accept the invitation for P1 from this link (Links to an external site.). This should setup your private repository for this project with the starter code on GitHub. Please note, this is by default a private repository only accessible by you and the course instructors. You can add your team-mates as collaborators (follow P0 for this). Please ensure this is the ONLY repository that you submit your code to. Any of your code should NOT BE published publically on your own repositories. Contact the TAs incase you have queries regarding this.Clone your remote (private) repository using the $ git clone command to get started on the project. (Refer to P0 for the detailed explanation).Ensure you commit your code often and on time using the $ git commit and the $ git push commands (similar to how you had done P0).The last commit that you do prior to the timeline will be taken as your final submissionThe projects (including a brief report) is due by 11:59PM on the designated day and the reports+programs. Ensure you push all these into the git repos by then.NO EXTENSIONS WILL BE ENTERTAINED. You will not be able to submit after the deadline, as the Git repos will not allow you to push code.ENSURE YOU PUSH YOUR CODE TO THE GIT REPOS BEFORE THE DEADLINE.You need to set up an appointment with your TAs to demonstrate your implementation.