Project 4: A Max-Heap Job Queue
Due: Tuesday, April 23, before 9:00 pm
Addenda
-
[4/18] There are two cases in which a range_error
exception should be thrown:
- If getNextJob() is called on an empty job queue.
- If insertJob() is called on a queue that is filled to capacity and you are not dynamically resizing your job queue (dynamic resizing is not a requirement of the project).
- [4/8] Posted and updated version of JQueue.h. Includes a typedef for the priority function pointer, simplifying the declarations of the constructor and accessors.
Objectives
- Become familiar with heap structures.
- Become familiar with function pointers.
- More practice with recursion!!
Introduction
On High Performance Computing (HPC) clusters, there is typically greater demand for compute resources than can be met at any one time. The job management system maintains a queue of submitted compute jobs and determines which jobs can be run based on policy set by the administrators. For example, a compute job that requires a small number of processors, say 16, and is expected to run for only a few minutes, might be prioritized ahead of a job that requires many processors and hours or days to run. On the other hand, there may be times (e.g. times of lower demand such as nighttime or over school breaks) where the resource-intensive jobs are given priority. Therefore, the job queue must be very flexible and able to support a wide range of prioritization functions.
In this project, you will implement a job queue class (JQueue) based on a max-heap data structure; it will maintain a max-heap based on the computed priority of each job, where the priority function is provided to the JQueue constructor via a function pointer. Inserting to and extracting from the max-heap requires “bubbling up ” or “bubbling down” to maintain the max-heap property; the comparisons that are part of the “bubbling” process will be made on the computed priorities of jobs in the heap. In addition, if the prioritization function is changed, the heap must be rebuilt, which also requires using the appropriate “bubbling” method.
For the purposes of this project, compute jobs have the following attributes (defined in JQueue.h) that can be used by the prioritization function:
-
Job Name
A descriptive name; not useful for prioritization. -
Priority
A user-specified priority in the range 1–100. This should not be confused with the computed priority, which takes the user-specified priority and other job attributes into account. -
User
A user id in the range 0–100. The computed priority may depend on the user id. -
Group
A group id in the range 0–100. Groups could represent different research groups or funding sources. -
Proc
The number of processors required by the job, in the range 1–255. -
Mem
Memory requirements per processor in number of Mb. The range is 1–65536 (1 Mb - 64 Gb). -
Time
Maximum wallclock time required, in seconds. The range is 1–172,800 (1 second - 48 hours).
A particularly simple prioritization function would be to just use the user-specified priority. However, the function can be much more complicated. The following function is implemented in the sample driver:
- Let pri be the computed priority. Initialize pri to the user-specified priority.
- If the user id is 7 or 23, add 300 to pri; otherwise, add 100 to pri.
- If the group id is 0 or 11, add 200 to pri; otherwise, add 100 to pri.
- Subtract the number of processors requested from pri.
- Subtract 1/100 of the requested memory size from pri.
- Subtract 1/3600 of the requested time from pri.
- The computed priority is the integer value of pri.
Assignment
Your assignment is to complete the JQueue class, testing it thoroughly with a variety of job data and prioritization functions. To get started, you are provided with the following files:
- JQueue.h — declarations for the JQueue class. [previous version of JQueue.h]
- JQueue.cpp — JQueue implementation file. Empty except for overloaded insertion operator for the job class.
- JQTest.cpp — a simple test driver for the JQueue class.
- JQTest.txt — sample output from JQTest.cpp.
First, you must implement the methods of the JQueue class. The methods are described in the requirements section, below. Then, you must write your own, extensive test driver; your test driver should check at least the following properties of your JQueue implementation:
- Basic correctness. Creating a queue, inserting jobs, and reading them out in priority order functions correctly.
- Correctness of copy constructor, assignment operator.
- Can change the prioritization function using the setter method and the max-heap is rebuilt correctly.
- Efficiency with large queues. Insertion and extraction with a large queue operates in logarithmic time.
Specifications
Requirement: Private helper functions must be declared in JQueue.h. No other modifications to JQueue.h are permitted!
Requirement: You must use a max-heap data structure to store the job queue. The heap must be ordered according to the prioritization function priority declared in JQueue.h and set by the constructor or setter method. If the prioritization function is changed using the setter method, then the max-heap must be rebuilt using the new prioritization function.
Requirement: Computed priority values may not be pre-computed and stored with the jobs in the queue. They must be computed as needed using the priority function.
Requirement: Insertion to and extraction from the max-heap must run in logarithmic time.
Requirement: You must use the provided operator<< to output job_t objects.
These are the member functions of the JQueue class.
-
JQueue(int capacity, int (*priFn)(const job_t& job)); This is the constructor for the JQueue class. It must be provided with the capacity of the queue and a pointer to the prioritization function. If the capacity is less than one, throw an out_of_range exception.
-
~JQueue(); Destructor for the JQueue class. All dynamically-allocated data must be deallocated.
-
JQueue(const JQueue& rhs); Copy constructor for the JQueue class. Must make a deep copy of the rhs object.
-
JQueue& operator=(const JQueue& rhs); Assignment operator for the JQueue class. Remember to check for self-assignment and to free all dynamically allocated data members of the host. You should not use the copy constructor in the implementation of the assignment operator.
-
void insertJob(const job_t input); Insert a job into the job queue. Must maintain the max-heap property.
-
job_t getNextJob(); Extract the highest priority job from the job queue. Must maintain the max-heap property.
-
int numJobs() const; Return the current number of jobs in the queue.
-
void printJobQueue() const; Print the contents of the job queue. The jobs should be listed be in array order not priority order (although the first job listed should have highest priority).
-
int (*getPriorityFn())(const job_t&); Get the current priority function.
-
void setPriorityFn(int (*priFn)(const job_t& job)); Set a new priority function. Must rebuild the heap!
-
void dump() const; Dump the entire heap, not just the portion currently in use. For debugging purposes.
Test Programs
The following program may be used as a basic test of your implementation. Remember, you are required to submit an extensive test program as described above. Additional test programs may be provided at a later date.
- JQTest.cpp — a simple test driver for the JQueue class.
- JQTest.txt — sample output from JQTest.cpp.
These and all the provided project files are available on GL:
Implementation Notes
- Like binary search trees, heaps are a data structure that benefit greatly from recursion. The “bubbling up” and “bubbling down” functions are most easily written as recursive functions.
What to Submit
You must submit the following files to the proj4 directory.
- JQueue.h (Only modification allowed is addition of private class methods)
- JQueue.cpp
- MyJQTest.cpp
If you followed the instructions in the Project Submission page to set up your directories, you can submit your code using this Unix command command: