Profile Launchpad performance¶
Profiling helps you identify performance bottlenecks in Launchpad by measuring where your code spends time during execution. Launchpad supports multiple profiling methods and profilers to suit different debugging needs.
This guide covers web-based profiling using ++profile++ URL segments and
inline profiling via Python decorators and context managers. Both approaches
support pstats and PyInstrument profilers.
Prerequisites¶
Profiling must be enabled through configuration or a feature flag.
Configuration-based enablement (default for development):
Profiling is disabled by default in the schema
(lib/lp/services/config/schema-lazr.conf):
[profiling]
profiling_allowed: False
profile_dir: .
The local development config at configs/development/launchpad-lazr.conf overrides
profiling_allowed to True, so profiling is enabled out of the box in local Launchpad setup.
Profile output is written to profile_dir, which defaults to the current
working directory (.).
Feature flag enablement:
Alternatively, enable profiling using the profiling.enabled feature flag.
Note
profiling.enabled flag has higher precedence over the profiling_allowed
config. However, they both use profile_dir as the base folder to write
profiling results.
Web-based profiling with ++profile++¶
The easiest way to profile Launchpad is by adding ++profile++ to any URL.
This method profiles the entire request, including traversal, rendering, and
database queries.
Get profiling help¶
Navigate to any Launchpad page and append /++profile++/ in the URL:
http://launchpad.test/++profile++/
This leads to a help page, that provides further information and examples.
Profile with pstats¶
To generate a pstats profile (Python’s standard library profiler):
http://launchpad.test/++profile++pstats/
This saves a .prof file to your configured profile_dir. The filename
includes a timestamp, page ID, OOPS ID, and thread name for easy identification.
To view pstats results in your browser:
http://launchpad.test/++profile++pstats&show/
The browser displays profile statistics sorted by internal time, cumulative time, and call count. For details about these metrics, see the pstats documentation.
To analyze the profile file from the command line:
python -m pstats 2026-06-02_10:15:30-PageName-OOPS-ID-ThreadName.prof
Note
The profiling files are written to profile_dir, which defaults to the
current working directory (.) in the local development environment.
Type help at the pstats prompt for available commands.
Profile with PyInstrument¶
PyInstrument is a modern statistical profiler that provides interactive HTML reports with flame graphs and call trees. It uses sampling rather than tracing, resulting in lower overhead and more accurate timing:
http://launchpad.test/++profile++pyinstrument/
This saves an HTML file to your profile_dir. Open the file in a web browser
to view the interactive visualization.
To see both the file output and browser results:
http://launchpad.test/++profile++pyinstrument&show/
Profile with Callgrind¶
TBD
Profile SQL queries¶
To profile SQL queries with Python stacktraces:
http://launchpad.test/++profile++sqltrace/
This can be slow on large pages. Filter SQL traces to specific statements:
# Get stacktraces for SQL containing "Product.blueprints_usage"
http://launchpad.test/++profile++sqltrace:includes Product.blueprints_usage/
# Get stacktraces for SQL starting with "SELECT Distribution"
http://launchpad.test/++profile++sqltrace:startswith SELECT Distribution/
# Get stacktraces for SQL ending with specific WHERE clause
http://launchpad.test/++profile++sqltrace:endswith WHERE Project.id = 5 LIMIT 1/
# Combine multiple filters with pipe (|)
http://launchpad.test/++profile++sqltrace:startswith SELECT | includes Product/
To see only SQL queries without stacktraces:
http://launchpad.test/++profile++sql/
Flexible URL placement¶
The ++profile++ segment can appear anywhere in the URL:
http://launchpad.test/++profile++show/
http://launchpad.test/++profile++show/ubuntu
http://launchpad.test/ubuntu/++profile++show
Some pages may redirect unexpectedly, so experimentation may be necessary.
Inline profiling via code¶
For profiling specific code sections without requesting a full page profile, use inline profiling with context managers or decorators.
Context manager profiling¶
Insert profiling calls directly in your code:
from lp.services.profile import profiling
def my_view_method(self):
# This code runs normally
setup_data()
with profiling():
# Only this section is profiled
expensive_operation()
another_expensive_call()
# This code runs normally
cleanup()
Multiple profiling blocks within a single request are automatically aggregated.
Choose the profiler type¶
By default, inline profiling uses pstats. To use PyInstrument:
from lp.services.profile import profiling
from lp.services.profile.profile import ProfilerType
with profiling(ProfilerType.PYINSTRUMENT):
expensive_operation()
View inline profiling results¶
After making a request with inline profiling code, view the results:
http://launchpad.test/your-page/++profile++show/
The page displays aggregated profiling data with a notice indicating these are inline profiling results.
Note
If you use ++profile++show (or pstats or callgrind or
pyinstrument) in the URL, it takes precedence over inline profiling.
The full request will be profiled and inline calls will be ignored with a
warning message.
Using the profiled decorator (for test layers)¶
For test layer profiling, use the @profiled decorator:
from lp.services.testing.profiled import profiled
class MyTestLayer:
@profiled
def setUp(cls):
# This method's execution time is tracked
expensive_setup()
This is used primarily for profiling the runtime of Launchpad’s test layers.
Layer profiling is enabled only when three or more -v (verbose) flags are
passed to the test runner:
bin/test -vvvct
When enabled, the test runner prints a profiling report at the end of the run, listing the number of calls and total time spent in each decorated method.