In this video, you’ll see how to improve code efficiency using Amazon CodeGuru Profiler.
With this service, you can analyze your application performance, visualize profiling data,
and receive automated recommendations for resolving inefficiencies.
Amazon CodeGuru Profiler is a service that uses machine learning to collect runtime performance data
from your live applications and then show you the methods that take the most time
and CPU capacity to execute.
To get started, navigate from the AWS Management Console to Amazon CodeGuru.
Here, you have the option to choose between the CodeGuru Reviewer and Profiler services.
Next, select the CodeGuru Profiler service from the drop-down list and click the button to proceed.
To begin using CodeGuru Profiler, you must first create a profiling group,
which is a set of applications that are profiled together as a unit.
Specify a name for the profiling group and create it.
Next, you must choose the users and roles that can submit profiling data to this profiling group
with the CodeGuru Profiler agent.
The Profiler agent is a program that runs alongside or within a user’s code in order to analyze it.
In this case, let’s select the EC2InstanceProfileForCodeGuru role.
Next, you’ll download and configure the CodeGuru Profiler agent
to run the CodeGuru Profiler agent alongside the code to be analyzed.
Let’s do that now.
Note that you have two choices here.
To quickly start profiling, you can download the executable JAR file on this page
and passit as a command line argument when starting your application.
To have more control over when to start profiling,
you can add the Code Guru profile agent into your application code.
For our purposes, let’s use the simpler method and download the JAR file.
Now that the profiler agent has been downloaded,
flip the toggle switch to indicate that you have completed the step.
Let’s take a look at the code we’ll run alongside the profiling agent.
The application used for the demo can be downloaded at the URL shown on-screen.
The code in this sample .java file is used for benchmarking.
It continuously loops while performing various computational tasks,
and then submits a message with a random number to an AWS Simple Queue Service (SQS) queue.
Let’s take a brief look at the methods involved.
The first method creates an SQS client in our region, generates a random number between 0 and 1,
and then waits a second before sending a message with the random number.
Note that it constructs the SQS client every time the putOnQueue method is called.
These are the methods that are called by the load methods.
For the purposes of this example, the code has already been compiled and an executable
JAR file is ready to be run alongside the profiler, so let's return to CodeGuru.
Next, let’s set up the CodeGuru agent associated with the profiling group to analyze the code.
First, open a terminal.
We’ll use the example command provided on the Profiling group setup page
to run the agent alongside the application code.
The profiler has run successfully alongside the application,
and the first profiling data point will be sampled soon.
Let’s return to CodeGuru and make sure that it is able to receive the profiling stream.
Refresh the view.
Under Status, we can see that CodeGuru has received an initial message from the agent,
indicating that profiling reports can be sent to CodeGuru.
Refresh the view again.
Now the status shows that CodeGuru has received the first profile of the application.
Let’s fast forward a few hours when we have enough samples from the CodeGuru Profiler
to accurately trace the performance of the application.
This Overview visualization provides a bottom-up view of your profiling data in a “flame graph”
that charts the computational cost of methods within a program as well as their hierarchal relationships.
The scale of each method along the x-axis represents the CPU time spent within that method.
Each bar is called a “stack frame.”
Let’s take a look at some of the information that can be gleaned from the Overview.
To explore the data, you can pause over the visualization.
For instance, when you pause over a frame, all frames with the same method name are highlighted.
This makes it easy to see where and how often the method is called.
You can also see details about the method.
For example, here you can see a breakdown of the time spent performing various types of actions
over the one-hour timespan we have chosen.
The load methods to the left are considered “shallow”
since they do not call or invoke any other methods beyond the ones directly above them.
However, the putOnQueue method, which constructs an SQS client and sends a message to an SQS queue
in the account as noted in the application code earlier, invokes several sub-methods within the AWS SDK.
Let’s zoom into putOnQueue to get a better look.
Here you can see that the majority of the time spent within putOnQueue is taken up by the method
AmazonSQSClient.getQueueUrl.
You can zoom in further to learn about a method’s parent and child methods
by right-clicking and selecting Inspect.
The Inspect view zooms into a selected frame, provides the fully qualified method signature,
and explicitly denotes its parent and child methods.
This can be particularly useful when a method appears multiple times in a visualization.
Let’s work our way up the stack frames to see the full trail of AWS methods invoked.
Let’s look at a different visualization.
The Hotspots visualization provides a “top-down” view of the same method hierarchy shown in the Overview,
which provided a bottom-up view.
Here, we’re looking at CPU usage.
The methods consuming the most application time are at the top.
Let's take a look at latency.
Sections colored purple or green are time spent waiting in methods.
You can view a bottom-up view of the same data by switching back to the overview.
Notice that the main method takes up about 99.7% of the overall CPU running time.
However, in the latency view, it is responsible for just about half of the combined time.
Let’s inspect the putOnQueue method in the latency view.
As you can see, the stack profile is very different when viewing latency as opposed to CPU time.
The latency view provides more detailed information on network behavior and performance,
and on how they are impacted by methods within a program.
If you let the profiler run for several hours, CodeGuru also provides recommendations for code changes
that may increase execution efficiency.
Each recommendation report includes information about why the recommendation was made,
a description, suggested resolution steps, and the stack locations affected by the recommendation.
The initial profiling has produced two recommendations.
The first suggests using newer, faster cryptographic libraries
than the ones currently implemented in the application.
It also provides a link to a suggested cryptographic library.
In addition, it gives the actual percentage of time the profile spent on these frames
compared to the percentage expected.
The second recommendation points out the redundant construction of the AmazonSQSClient,
which is re-created every time the main loop restarts.
CodeGuru says that the profile spends 1.04% of its runnable and blocked time re-creating AWS SDK clients,
when in performant apps, it typically spends less than 1%.
It then identifies the method call which appears to be most matched to this issue.
Let’s look at the frame that appears to be responsible.
This is a zoomed in view of the AmazonWebServiceClient initialization method
within the profile.
Looking at the parent methods, you can see that this method is directly linked to the
AmazonSQSClientBuilder object constructed in the putOnQueue method.
Let’s modify the code to take care of this issue.
Currently, the AmazonSQS constructor is in the putOnQueue method,
which runs repeatedly over the course of the application's lifetime.
Let’s put it above the main method as a class variable so that it is constructed only once
during the class initialization.
Save the changes.
Now let’s run the profiler again and check back in a few hours to see how the profile changes.
As you can see, the section of the stack profile associated with the putOnQueue CPU time
is much smaller.
Now that a full profile has been generated, let’s search for the putOnQueue method
to see how its relative running time and stack composition has changed.
Notice that the putOnQueue method is now responsible for 4.39% of the overall CPU time,
as opposed to the 32.19% it had been responsible for previously.
Let’s zoom in to look at the overall profile.
As you can see, the section that had been previously associated with AmazonSQSClientBuilder
is no longer present within the putOnQueue profile.
You’ve just seen how to improve code efficiency using Amazon CodeGuru Profiler.
Thanks for watching.
Now it’s your turn to try.