Overview

Our friend Penny the Ping Pong Ball is not rolling fast enough and wants us to profile her! In order to help her, in this lab, you will become more familiar with the technique of profiling your code. You might have noticed that your Autocorrect program might be a bit slow when making page requests from the server. This indicates that your Autocorrect program might have run into some performance issues. Profiling is a very important tool that allows you to understand the performance of your program, by showing you detailed information of where your program is spending the most time and memory. This is not always intuitive, and profiling allows you to focus your optimization efforts on the most highly used portion of your program.

Here you will be using VisualVM Profiler, a popular visual profiler, to profile your Autocorrect project. Then, using your knowledge of profiling, your task is to make optimizations to improve the performance of your Autocorrect project. Finally, this will give you the tools to potentially profile your TIMDb project.

Getting Started

Note: it is highly recommended that you complete this lab on department machines as it's quite buggy on laptops!

  1. Stencil Code: The original authors of the Autocorrect program were working on a low budget and they didn't have time to optimize their code. You'll be optimizing the same Autocorrect project you've been using all semester, which has had a hidden performance flaw. This stencil can be cloned here.

  2. Download VisualVM: Use this link to download a .zip file of VisualVM. You should unzip the file in a convenient directory to work in, since you will be running VisualVM from this directory.

  3. Start VisualVM: Navigate to the folder you unzipped VisualVM into, and run the appropriate binary for your OS:

    • For Windows: bin\visualvm.exe
    • For Mac/Linux (from your terminal): bin/visualvm

  4. Configure VisualVM: Continue onto the next section to configure VisualVM. You should follow these instructions carefully, but note that exact details may differ depending on if you're on Windows, Mac, or Linux. If you're working on your laptop, use the program at your own risk. To avoid any confusion, again, we highly recommend that you get checked off on a department machine.

Profiling with VisualVM

Once you run VisualVM, you should see the VisualVM GUI. When any Java application is run, VisualVM will display the running application as a node on the left hand side of the window. To better profile our Autocorrect project, we are going to use a feature of VisualVM called the "startup profiler", which begins profiling your program as soon as it starts running.

Installing the Startup Profiler: We must first install the Startup Profiler plugin for VisualVM. Go ahead and click on the Tools dropdown and select Plugins. Under the "Available Plugins" tabs, check the box next to "Startup Profiler". Hit "Install" at the bottom of the window and wait for the plugin to finish installing. Now, you can close the plugins window.

Configuring the Startup Profiler: Under the Applications dropdown, a new option should appear called "Profile Startup". Clicking that will take you to a configuration screen. Change your settings to the following:

  • Platform: Java 11
  • Architecture: 64 bit
  • Port: 5140
  • Profile: CPU
  • Start profiling from classes: Fill in your Autocorrect package name with a .* at the end (e.g. edu.brown.cs.student.main.*)
  • and leave the rest as defaults.
Then click the "copy to clipboard" button at the bottom, which will copy an additional startup flag you will pass to your program. Open up your run script and paste the flag you copied from the configuration page to the line at the bottom which starts with java. Additionally, add the following flag, -Xverify:none to the same line. The last line of your run script should look something like this (with the blank line filled in):
    java -agentpath:________ -Xverify:none -ea -cp "$TARGET$PATHSEP$CP" edu.brown.cs.$STUDENT.$MAINPKG.Main "$@"
Once you're ready, save your run script.

Running the Profiler: Go back to the profiler configuration page and hit "Profile" at the bottom. VisualVM should say something like "Connecting to the Target VM". At this point, you can now run your Autocorrect program in a new terminal with prefix, whitespace, and LED distance 3. You should see terminal output from the profiler attaching itself to your program. Note - the first time you do this, VisualVM might perform a calibration. Go ahead and correct a word of 4 characters or fewer.

Viewing the Results: Once you're done, VisualVM might say something like "Do you want to take a snapshot of the collected results?". You should say yes to this! Now, If you click on "Hot Spots" or "Profiler Snapshots" it will display a list of methods in your program that are sorted by the amount of time your program spent in those methods. Here is where you can take note of which methods take up the most time. Perhaps methods that your program spends a lot of time in could be optimized to improve performance?

Understanding Profiling Results

A method you did not write, called java.util.concurrent.ThreadPoolExecutor$Worker.run, might show up at the top of the list taking a significant portion of the execution of your program. This is referring to the run() method of a class known as a Worker. The worker (or, “Worker Thread”) is initialized by the JVM to execute your program. Simplifying things a bit, your public static void main(String args[]) is called by Worker.run().

When VisualVM is determining how long a method takes to run, it times the method itself, plus all of the methods that it calls. It then considers that amount of time as a percentage of the total time it takes your program to run. Since VisualVM treats run() just like any other method, and because your entire program gets executed inside of the run() method, VisualVM (accurately) reports that the run() method is taking a huge percentage of the program’s run time.

All of this is to say - you can mostly disregard the fact that Worker.run() seems like it’s taking a disproportionate amount of time to run. You could optimize your code beyond belief, and Worker.run() would still take a huge percentage of your app’s run time.

Addressing Performance Issues in Autocorrect

Try running your Autocorrect program with --prefix --whitespace --led=3 and you should see that a certain function seems to be monopolizing your program's runtime when correcting a word. If you don't see this, you should call a TA for help at this point!

We want to make this function run much faster. Try thinking about time complexity and space.

Once you have made changes, re-run your Autocorrect code. You should notice that it is considerably quicker and certain parts of your program do not have a much more significant CPU usage than others.

Troubleshooting

If the port you are trying to run Autocorrect on is in use you can change the port number in the VisualVM set up as well as the path in the run script.

If you get "Permission Denied" errors while trying to run VisualVM you might need to run 'chmod 700 bin/visualvm' from the visualvm folder.

Optional: TIMDb

With your newfound knowledge of profiling, go ahead and profile your TIMDb code! Run a few queries and note which methods are taking the most amount of time and/or memory. You can call over a TA to discuss your findings. This might help you improve the performance of your code.

Getting Checked Off

When you have addressed the performance issues in Autocorrect, call over a TA to get checked off. Be prepared to show the output of your profiler, discuss your findings, and present your improved Autocorrect solution.