In this assignment we enhance the ics432imgapp application so that a job can use multiple threads to speed up image processing.
In this assignment you have to use GitHub Issues as follows:
We wish to increase performance by overlapping I/O and computation. Create and address the following GitHub issue:
Issue Title: Multi-threaded jobs
Issue Label: enhancement
Issue Description: Add a checkbox to the Main window next to a label that says “Multithreading”. Make it so that if the checkbox is checked when job window is being opened, then that job will use three thread:
- A “reader” thread that reads input images from disk into RAM
- A “processor” thread that processes input images and produces output images in RAM
- A “writer” thread that writes output images from RAM to disk
There are four requirements (the last one being a non-requirement) for your implementation:
Requirement #1: The three threads must communicate in producer-consumer fashion (no busy waits!), using two producer-consumer “bounded buffers” (one between the reader and the processor, and one between the processor and the writer). Set the buffer size to the total number of images to process. The buffer must be implemented using Java’s ArrayDeque<> class.
Requirement #2: You must implement the producer-consumer scheme from scratch, without using the java.util.concurrent package.
Requirement #3: After a job has terminated, there should be no left-over threads (i.e., each thread you start returns from run()). This may not be as easy as it seems. We’ll test this by running multiple jobs in sequence and checking that the number of running threads in your app doesn’t increase linearly.
Non-Requirement #4: Set the Cancel button as permanently disabled. It’s ok if jobs are no longer cancelable from now on.
Note: When the Job window displays read, write, processing, and total times once the job completes, the total time should be smaller than the sum of the other three times.
Hint: It’s likely a good idea to define some “work unit” class, which is the thing that gets passed between the producers and the consumers and encodes all necessary information about the work to do for one image. Warning: if your work unit class contains “big” things (e.g., Image, BufferedImage), make sure you set them to null whenever you no longer need them so as to free up memory! In the next question we deal with RAM footprint, so you might as well save on memory right now.
Todo: In your README file, explain where in your code the producer-consumer scheme is implemented.
Todo: Run each filter on the the set of 25 jpg sea urchin images on Laulima, with and without the “Multithreading” checkbox being checked. Do these runs on a quiescent machine. In your README file report on the acceleration factor achieved by multi-threading for running each job (e.g., is a non-multithreaded run takes 10s and a multithreaded run takes 8s, the acceleration factor was 1.25x). Discuss the result, explaining why you think the results are what they are.
Warning: Runs a few “warm-up jobs” in the app before doing your timings.
One drawback of our approach is that the reader thread will keep reading images, and thus the memory footprint of the application could grow prohibitively.
Create and address the following GitHub issue:
Issue Title: Controlling the Memory Footprint
Issue Description: Add a Slider to the Main window that makes it possible to select an integer between 2 and 40, with a step size of 2, with some informative label like “#images in RAM”. If the slider’s value is X, then any subsequently created job will enforce that at most X images can be in RAM that have been read in by the reader thread and that are awaiting processing, and at most X images that have been processed by the processor thread and are awaiting being written back to disk. Make the slider long enough that it shows all 20 discrete possible values.
Note: You have to call several of the Slider methods to make sure it does discrete integer steps (e.g., setBlockIncrement, setMajorTickUnit).
Todo: To make sure that your implementation works, let’s use this set of 40 jpg large sea slug images on Laulima. The project’s pom.xml file specifies the amount of heap space that is allocated to the JVM when running the application (the line “<option>-Xmx4G</option>”). Do the following: