How to Perform workerd Performance Profiling Using Built-In Perfetto Tracing
Enable the --perfetto-trace flag when starting workerd to capture low-overhead C++ and JavaScript trace events, then analyze the resulting .perfetto file in the Perfetto UI or CLI to identify bottlenecks across native and application layers.
Cloudflare's workerd runtime ships with built-in Perfetto tracing support that captures detailed timing data from both the native C++ layer and JavaScript worker code. By leveraging the --perfetto-trace command-line option implemented in src/workerd/server/workerd.c++, you can generate comprehensive profiles that correlate native request handling with performance.mark() calls in your application logic. This guide covers the complete workflow from enabling traces to analyzing request latency.
Enabling Perfetto Tracing at Startup
workerd exposes tracing through the -p or --perfetto-trace flag. The syntax requires a file path followed by an equals sign and a comma-separated list of categories:
# Capture all default categories in the workerd::traces namespace
workerd -p /tmp/trace.perfetto=*
# Capture only request handling and async I/O categories
workerd -p /tmp/trace.perfetto=request,async_io
The flag parsing logic resides in src/workerd/server/workerd.c++ around line 802, where addOptionWithArg processes the input and stores values in perfettoTraceDestination and perfettoTraceCategories. These members initialize a PerfettoSession at lines 1416-1418 when the server starts. Use * to enable every category, or leave the category list empty after the equals sign to disable all categories.
Instrumenting C++ Code with TRACE_EVENT Macros
To emit custom events from native code, include the convenience header and use the standard Perfetto macros defined in src/workerd/util/perfetto-tracing.h:
#include <workerd/util/use-perfetto-categories.h>
void handleRequest(jsg::Lock& js) {
TRACE_EVENT("request", "handle_start", "method", request.method.cStr());
// ... request handling logic ...
TRACE_EVENT_END("request");
}
When WORKERD_USE_PERFETTO is undefined, these macros expand to no-ops (see the #else branch in perfetto-tracing.h), making them safe to retain in production builds without impacting performance. To add custom categories, extend the PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(workerd::traces, ...) block in perfetto-tracing.h with new perfetto::Category("your_name") entries.
Using the JavaScript Performance API
workerd implements a minimal Performance object in src/workerd/api/performance.h and src/workerd/api/performance.c++ that forwards calls to the underlying tracing system:
export default {
async fetch(request) {
performance.mark('fetch_start');
const response = await fetch(request);
performance.measure('fetch_duration', 'fetch_start');
console.log('Duration:', performance.getEntriesByName('fetch_duration')[0].duration);
return response;
}
};
When tracing is active, performance.mark() and performance.measure() automatically generate PerformanceMark and PerformanceMeasure entries that internally call TRACE_EVENT. This allows seamless correlation between JavaScript timing markers and native C++ execution phases in a single trace file.
Analyzing Trace Output
Web Interface
Open the trace file generated by src/workerd/util/perfetto-tracing.c++ in the Perfetto UI:
- Navigate to https://ui.perfetto.dev
- Drag and drop the
.perfettofile onto the window - In the Tracks panel, enable the
workerdgroup to view native events - Use the Search bar to filter by category (e.g.,
requestor custom names) - Hover over events to inspect timestamps, durations, and attached arguments
Command Line
Use the perfetto CLI to process traces programmatically:
# Human-readable text output
perfetto -i /tmp/trace.perfetto --txt
# Generate an SVG flamegraph
perfetto -i /tmp/trace.perfetto --flamegraph > profile.svg
The trace contains nanosecond-resolution timestamps for all enabled categories, enabling precise analysis of event-loop latency and async I/O patterns.
Summary
- Enable tracing by passing
-p /path/to/file.perfetto=categorieswhen starting workerd; the parser insrc/workerd/server/workerd.c++handles the category list and initializes aPerfettoSession - Instrument C++ code using
TRACE_EVENTmacros fromsrc/workerd/util/perfetto-tracing.h, which safely compile to no-ops when tracing is disabled - Instrument JavaScript via the standard
performance.mark()andperformance.measure()API implemented insrc/workerd/api/performance.c++ - Analyze results using the Perfetto web UI or CLI tools to view synchronized timelines of native and JavaScript execution
Frequently Asked Questions
Does Perfetto tracing impact production performance?
When disabled, the TRACE_EVENT macros defined in src/workerd/util/perfetto-tracing.h expand to no-ops, resulting in zero runtime overhead. When enabled, Perfetto uses lock-free, memory-mapped ring buffers designed for minimal latency, though you should target specific categories rather than using * in high-traffic production environments to reduce serialization overhead.
Can I define custom trace categories?
Yes. Add new categories to the PERFETTO_DEFINE_CATEGORIES_IN_NAMESPACE(workerd::traces, ...) declaration in src/workerd/util/perfetto-tracing.h. You must include src/workerd/util/use-perfetto-categories.h in any translation unit that emits events with your custom category names.
How do I correlate JavaScript and C++ events in the same trace?
The JavaScript Performance API implementation in src/workerd/api/performance.c++ internally calls the same TRACE_EVENT infrastructure used by C++ code. When you open the trace in Perfetto, events from both layers appear on synchronized timelines. Use distinct category names (e.g., "js_handler" vs "request") to filter and compare execution phases across language boundaries.
What file format does workerd use for traces?
workerd generates standard Perfetto trace files (conventionally .perfetto) that follow the ProtoTrace format. These files can be opened directly in the Perfetto UI, processed with the perfetto CLI, or converted to other formats like JSON or flamegraphs using the standard Perfetto toolchain.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →