The AWS Serverless feature you’re probably not using (yet)

Yariv Levy
4 min readJan 21, 2023

--

We’ve all been there: you’re working on a fancy new feature, everything looks promising and works smoothly… and suddenly, you realize performance isn’t great. At first, you try to analyze the code and see where the problem is, but with complex microservices, it might be quite difficult to profile components on your machine, or even simulate a production-like environment.

This is where AWS CodeGuru Profiler comes in. As the utilization of serverless architecture continues to rise, the need for tools that can optimize the performance of these applications becomes increasingly important. CodeGuru Profiler is a powerful tool that collects runtime performance data from your live applications and provides data and recommendations that can help you fine-tune your application performance. It integrates seamlessly with Lambda functions, making the whole experience effortless.

In this blog post, I will provide an overview of the features of AWS CodeGuru Profiler for profiling Lambda functions and provide a step-by-step guide on how to set it up and use it to optimize the performance of your serverless applications.

Setting up CodeGuru Profiler

One of the best things about using CodeGuru Profiler is how easy it is to set up for supported Lambda runtimes — Python 3.6 to Python 3.9, and Java 8 (Corretto) and Java 11 (Corretto).

For those who prefer using the AWS Console, all you have to do is enable Code profiling under the Monitoring and operations tools in the Configuration tab of your function. This will add the CodeGuru Profiler layer to your function, set the necessary environment variables, and add the AmazonCodeGuruProfilerAgentAccess policy to your function’s role.

Alternatively, you can use the AWS CLI to set up CodeGuru Profiler. The following is an example of a snippet for a Python function:

#!/bin/bash

group_name=$1
lambda_arn=$2

# Create a new profiling group
aws codeguruprofiler create-profiling-group \
--compute-platform AWSLambda \
--profiling-group-name "$group_name"

AWS_LAMBDA_EXEC_WRAPPER=/opt/codeguru_profiler_lambda_exec
CODEGURU_VARIABLES="{
\"AWS_LAMBDA_EXEC_WRAPPER\": \"$AWS_LAMBDA_EXEC_WRAPPER\",
\"AWS_CODEGURU_PROFILER_TARGET_REGION\": \"us-west-2\",
\"AWS_CODEGURU_PROFILER_HEAP_SUMMARY_ENABLED\": \"true\",
\"AWS_CODEGURU_PROFILER_GROUP_NAME\": \"$group_name\"
}"

ROLE=$(aws lambda get-function --function-name FancyFunction | jq -r '.Configuration.Role' | awk -F '/' '{print $NF}')
# Grant permissions to Lambda to perform CodeGuru actions
aws iam attach-role-policy \
--role-name "$ROLE" \
--policy-arn arn:aws:iam::aws:policy/AmazonCodeGuruProfilerAgentAccess

# Update environment variables
aws lambda update-function-configuration \
--function-name "$lambda_arn" \
--environment "{ \"Variables\": $CODEGURU_VARIABLES }" \
--layers "arn:aws:lambda:us-west-2:157417159150:layer:AWSCodeGuruProfilerPythonAgentLambdaLayer:11"

It’s also integrated perfectly with AWS CDK:

export class LambdaStack extends Stack {

constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);

let region = Stack.of(this).region;
const LAYER_ARN = 'arn:aws:lambda:us-west-2:157417159150:layer:AWSCodeGuruProfilerPythonAgentLambdaLayer:11';

const CodeGuruLayer = LayerVersion.fromLayerVersionArn(this,
"CodeGuruLayer",
LAYER_ARN
);

const function = new lambda.Function(this, 'MyFunction', {
runtime: lambda.Runtime.PYTHON_3_9,
handler: 'lambda_handler.handler',
code: Code.fromAsset("./lambda_assets/"),
environment: {
'AWS_LAMBDA_EXEC_WRAPPER': '/opt/codeguru_profiler_lambda_exec',
},
layers: [CodeGuruLayer],
profiling: true,
});


function.add_to_role_policy(
iam.PolicyStatement(
effect=iam.Effect.ALLOW,
actions=[
"codeguru-profiler:ConfigureAgent",
"codeguru-profiler:CreateProfilingGroup",
"codeguru-profiler:PostAgentProfile",
],
resources=["arn:aws:codeguru-profiler:*:*:profilingGroup/*"],
)
);

}

}

It’s also worth noting, that CodeGuru Profiler can integrate with other runtime versions of Java or Python.

CodeGuru Profiler in action

To demonstrate the capabilities of CodeGuru Profiler, let’s create a new Lambda function with a simple handler that has a permission issue. The function includes several slow functions that simulate a performance problem:

import time

def slow_function():
time.sleep(2)

def another_slow_function():
time.sleep(3)

def even_slower_function():
time.sleep(4)

def innocent_looking_function():
even_slower_function()
another_slow_function()

def innocent_function():
time.sleep(0.2)

def lambda_handler(event, context):
innocent_function()
innocent_looking_function()
slow_function()
innocent_function()
another_slow_function()
even_slower_function()
innocent_looking_function()
innocent_function()

return {
'statusCode': 200,
'body': 'Hello, World!'
}

Using the instructions above, we’ll enable Code profiling from the Lambda console. Once the function is executed, we can view the results in the CodeGuru Profiler:

Obviously the example here is oversimplified, here is a sample demo provided by CodeGuru:

CPU usage graph

I really like the ability to to navigate between different frames in the CPU graph. This provides a detailed breakdown of what’s happening with the performance of your Lambda.

Heap summary graph

The heap summary graph also provides valuable insight into your application’s heap usage over time, although I would appreciate more granular information, such as heap usage for specific packages.

Recommendation panel

The recommendation panel is a great addition, as it offers actionable suggestions for mitigating performance issues. While I haven’t personally found the recommendations to be particularly helpful yet, I believe this feature has potential. I think that navigating through recommendations and CPU usage graph could be more user-friendly, and point to where in my codebase changes should be made.

It’s important to note that the data collected will be more reliable and accurate if you run your function multiple times over an extended period of time. Keep in mind that it may take a few minutes for the results to appear.

Overall, AWS CodeGuru Profiler is an excellent tool that can help you identify and fix performance issues, resulting in improved user experience and reduced costs. You should definitely give it a try.

--

--

Yariv Levy

I'm a Software Engineer at AWS. Passionate about clean code, distributed systems, IaC and vi. Tel Aviv born & raised, food lover. All opinions are my own.