{
  "schema_version": 2,
  "id": "operate/oss_and_stack/management/optimization/cpu-profiling",
  "title": "Redis CPU profiling",
  "url": "https://redis.io/docs/latest/operate/oss_and_stack/management/optimization/cpu-profiling/",
  "summary": "Performance engineering guide for on-CPU profiling and tracing",
  "aliases": [
    "/manual/optimization/cpu-profiling/",
    "/management/optimization/cpu-profiling/"
  ],
  "tags": [
    "docs",
    "operate",
    "stack",
    "oss"
  ],
  "last_updated": "2026-04-21T16:48:23+01:00",
  "page_type": "content",
  "content_hash": "02be9afc3eb0aa3c424a7019ffcf03c4535e4cd13d6c1db627ae72531e2fdbd2",
  "sections": [
    {
      "id": "filling-the-performance-checklist",
      "title": "Filling the performance checklist",
      "role": "overview",
      "text": "Redis is developed with a great emphasis on performance. We do our best with\nevery release to make sure you'll experience a very stable and fast product. \n\nNevertheless, if you're finding room to improve the efficiency of Redis or\nare pursuing a performance regression investigation you will need a concise\nmethodical way of monitoring and analyzing Redis performance. \n\nTo do so you can rely on different methodologies (some more suited than other \ndepending on the class of issues/analysis we intend to make). A curated list\nof methodologies and their steps are enumerated by Brendan Greg at the\n[following link](http://www.brendangregg.com/methodology.html). \n\nWe recommend the Utilization Saturation and Errors (USE) Method for answering\nthe question of what is your bottleneck. Check the following mapping between\nsystem resource, metric, and tools for a practical deep dive:\n[USE method](http://www.brendangregg.com/USEmethod/use-rosetta.html)."
    },
    {
      "id": "ensuring-the-cpu-is-your-bottleneck",
      "title": "Ensuring the CPU is your bottleneck",
      "role": "content",
      "text": "This guide assumes you've followed one of the above methodologies to perform a \ncomplete check of system health, and identified the bottleneck being the CPU. \n**If you have identified that most of the time is spent blocked on I/O, locks,\ntimers, paging/swapping, etc., this guide is not for you**."
    },
    {
      "id": "build-prerequisites",
      "title": "Build Prerequisites",
      "role": "content",
      "text": "For a proper On-CPU analysis, Redis (and any dynamically loaded library like\nRedis Modules) requires stack traces to be available to tracers, which you may\nneed to fix first. \n\nBy default, Redis is compiled with the `-O2` switch (which we intent to keep\nduring profiling). This means that compiler optimizations are enabled. Many\ncompilers omit the frame pointer as a runtime optimization (saving a register),\nthus breaking frame pointer-based stack walking. This makes the Redis\nexecutable faster, but at the same time it makes Redis (like any other program)\nharder to trace, potentially wrongfully pinpointing on-CPU time to the last\navailable frame pointer of a call stack that can get a lot deeper (but\nimpossible to trace).\n\nIt's important that you ensure that:\n- debug information is present: compile option `-g`\n- frame pointer register is present: `-fno-omit-frame-pointer`\n- we still run with optimizations to get an accurate representation of production run times, meaning we will keep: `-O2`\n\nYou can do it as follows within redis main repo:\n\n    $ make REDIS_CFLAGS=\"-g -fno-omit-frame-pointer\""
    },
    {
      "id": "a-set-of-instruments-to-identify-performance-regressions-andor-potential-on-cpu-performance-improvements",
      "title": "A set of instruments to identify performance regressions and/or potential **on-CPU performance** improvements",
      "role": "content",
      "text": "This document focuses specifically on **on-CPU** resource bottlenecks analysis,\nmeaning we're interested in understanding where threads are spending CPU cycles\nwhile running on-CPU and, as importantly, whether those cycles are effectively\nbeing used for computation or stalled waiting (not blocked!) for memory I/O,\nand cache misses, etc.\n\nFor that we will rely on toolkits (perf, bcc tools), and hardware specific PMCs\n(Performance Monitoring Counters), to proceed with:\n\n- Hotspot analysis (perf or bcc tools): to profile code execution and determine which functions are consuming the most time and thus are targets for optimization. We'll present two options to collect, report, and visualize hotspots either with perf or bcc/BPF tracing tools.\n\n- Call counts analysis: to count events including function calls, enabling us to correlate several calls/components at once, relying on bcc/BPF tracing tools.\n\n- Hardware event sampling: crucial for understanding CPU behavior, including memory I/O, stall cycles, and cache misses."
    },
    {
      "id": "tool-prerequisites",
      "title": "Tool prerequisites",
      "role": "content",
      "text": "The following steps rely on Linux perf_events (aka [\"perf\"](https://man7.org/linux/man-pages/man1/perf.1.html)), [bcc/BPF tracing tools](https://github.com/iovisor/bcc), and Brendan Greg’s [FlameGraph repo](https://github.com/brendangregg/FlameGraph).\n\nWe assume beforehand you have:\n\n- Installed the perf tool on your system. Most Linux distributions will likely package this as a package related to the kernel. More information about the perf tool can be found at perf [wiki](https://perf.wiki.kernel.org/).\n- Followed the install [bcc/BPF](https://github.com/iovisor/bcc/blob/master/INSTALL.md#installing-bcc) instructions to install bcc toolkit on your machine.\n- Cloned Brendan Greg’s [FlameGraph repo](https://github.com/brendangregg/FlameGraph) and made accessible the `difffolded.pl` and `flamegraph.pl` files, to generated the collapsed stack traces and Flame Graphs."
    },
    {
      "id": "hotspot-analysis-with-perf-or-ebpf-stack-traces-sampling",
      "title": "Hotspot analysis with perf or eBPF (stack traces sampling)",
      "role": "content",
      "text": "Profiling CPU usage by sampling stack traces at a timed interval is a fast and\neasy way to identify performance-critical code sections (hotspots)."
    },
    {
      "id": "sampling-stack-traces-using-perf",
      "title": "Sampling stack traces using perf",
      "role": "content",
      "text": "To profile both user- and kernel-level stacks of redis-server for a specific\nlength of time, for example 60 seconds, at a sampling frequency of 999 samples\nper second:\n\n    $ perf record -g --pid $(pgrep redis-server) -F 999 -- sleep 60\n\n#### Displaying the recorded profile information using perf report\n\nBy default perf record will generate a perf.data file in the current working\ndirectory. \n\nYou can then report with a call-graph output (call chain, stack backtrace),\nwith a minimum call graph inclusion threshold of 0.5%, with:\n\n    $ perf report -g \"graph,0.5,caller\"\n\nSee the [perf report](https://man7.org/linux/man-pages/man1/perf-report.1.html)\ndocumentation for advanced filtering, sorting and aggregation capabilities.\n\n#### Visualizing the recorded profile information using Flame Graphs\n\n[Flame graphs](http://www.brendangregg.com/flamegraphs.html) allow for a quick\nand accurate visualization of frequent code-paths. They can be generated using\nBrendan Greg's open source programs on [github](https://github.com/brendangregg/FlameGraph),\nwhich create interactive SVGs from folded stack files.\n\nSpecifically, for perf we need to convert the generated perf.data into the\ncaptured stacks, and fold each of them into single lines. You can then render\nthe on-CPU flame graph with:\n\n    $ perf script > redis.perf.stacks\n    $ stackcollapse-perf.pl redis.perf.stacks > redis.folded.stacks\n    $ flamegraph.pl redis.folded.stacks > redis.svg\n\nBy default, perf script will generate a perf.data file in the current working\ndirectory. See the [perf script](https://linux.die.net/man/1/perf-script)\ndocumentation for advanced usage.\n\nSee [FlameGraph usage options](https://github.com/brendangregg/FlameGraph#options)\nfor more advanced stack trace visualizations (like the differential one).\n\n#### Archiving and sharing recorded profile information\n\nSo that analysis of the perf.data contents can be possible on a machine other\nthan the one on which collection happened, you need to export along with the\nperf.data file all object files with build-ids found in the record data file.\nThis can be easily done with the help of \n[perf-archive.sh](https://github.com/torvalds/linux/blob/master/tools/perf/perf-archive.sh)\nscript:\n\n    $ perf-archive.sh perf.data\n\nNow please run:\n\n    $ tar xvf perf.data.tar.bz2 -C ~/.debug\n\non the machine where you need to run `perf report`."
    },
    {
      "id": "sampling-stack-traces-using-bccbpfs-profile",
      "title": "Sampling stack traces using bcc/BPF's profile",
      "role": "content",
      "text": "Similarly to perf, as of Linux kernel 4.9, BPF-optimized profiling is now fully\navailable with the promise of lower overhead on CPU (as stack traces are\nfrequency counted in kernel context) and disk I/O resources during profiling. \n\nApart from that, and relying solely on bcc/BPF's profile tool, we have also\nremoved the perf.data and intermediate steps if stack traces analysis is our\nmain goal. You can use bcc's profile tool to output folded format directly, for\nflame graph generation:\n\n    $ /usr/share/bcc/tools/profile -F 999 -f --pid $(pgrep redis-server) --duration 60 > redis.folded.stacks\n\nIn that manner, we've remove any preprocessing and can render the on-CPU flame\ngraph with a single command:\n\n    $ flamegraph.pl redis.folded.stacks > redis.svg"
    },
    {
      "id": "visualizing-the-recorded-profile-information-using-flame-graphs",
      "title": "Visualizing the recorded profile information using Flame Graphs",
      "role": "content",
      "text": ""
    },
    {
      "id": "call-counts-analysis-with-bccbpf",
      "title": "Call counts analysis with bcc/BPF",
      "role": "content",
      "text": "A function may consume significant CPU cycles either because its code is slow\nor because it's frequently called. To answer at what rate functions are being\ncalled, you can rely upon call counts analysis using BCC's `funccount` tool:\n\n    $ /usr/share/bcc/tools/funccount 'redis-server:(call*|*Read*|*Write*)' --pid $(pgrep redis-server) --duration 60\n    Tracing 64 functions for \"redis-server:(call*|*Read*|*Write*)\"... Hit Ctrl-C to end.\n\n    FUNC                                    COUNT\n    call                                      334\n    handleClientsWithPendingWrites            388\n    clientInstallWriteHandler                 388\n    postponeClientRead                        514\n    handleClientsWithPendingReadsUsingThreads      735\n    handleClientsWithPendingWritesUsingThreads      735\n    prepareClientToWrite                     1442\n    Detaching...\n\n\nThe above output shows that, while tracing, the Redis's call() function was\ncalled 334 times, handleClientsWithPendingWrites() 388 times, etc."
    },
    {
      "id": "hardware-event-counting-with-performance-monitoring-counters-pmcs",
      "title": "Hardware event counting with Performance Monitoring Counters (PMCs)",
      "role": "content",
      "text": "Many modern processors contain a performance monitoring unit (PMU) exposing\nPerformance Monitoring Counters (PMCs). PMCs are crucial for understanding CPU\nbehavior, including memory I/O, stall cycles, and cache misses, and provide\nlow-level CPU performance statistics that aren't available anywhere else.\n\nThe design and functionality of a PMU is CPU-specific and you should assess\nyour CPU supported counters and features by using `perf list`. \n\nTo calculate the number of instructions per cycle, the number of micro ops\nexecuted, the number of cycles during which no micro ops were dispatched, the\nnumber stalled cycles on memory, including a per memory type stalls, for the\nduration of 60s, specifically for redis process: \n\n    $ perf stat -e \"cpu-clock,cpu-cycles,instructions,uops_executed.core,uops_executed.stall_cycles,cache-references,cache-misses,cycle_activity.stalls_total,cycle_activity.stalls_mem_any,cycle_activity.stalls_l3_miss,cycle_activity.stalls_l2_miss,cycle_activity.stalls_l1d_miss\" --pid $(pgrep redis-server) -- sleep 60\n\n    Performance counter stats for process id '3038':\n\n      60046.411437      cpu-clock (msec)          #    1.001 CPUs utilized          \n      168991975443      cpu-cycles                #    2.814 GHz                      (36.40%)\n      388248178431      instructions              #    2.30  insn per cycle           (45.50%)\n      443134227322      uops_executed.core        # 7379.862 M/sec                    (45.51%)\n       30317116399      uops_executed.stall_cycles #  504.895 M/sec                    (45.51%)\n         670821512      cache-references          #   11.172 M/sec                    (45.52%)\n          23727619      cache-misses              #    3.537 % of all cache refs      (45.43%)\n       30278479141      cycle_activity.stalls_total #  504.251 M/sec                    (36.33%)\n       19981138777      cycle_activity.stalls_mem_any #  332.762 M/sec                    (36.33%)\n         725708324      cycle_activity.stalls_l3_miss #   12.086 M/sec                    (36.33%)\n        8487905659      cycle_activity.stalls_l2_miss #  141.356 M/sec                    (36.32%)\n       10011909368      cycle_activity.stalls_l1d_miss #  166.736 M/sec                    (36.31%)\n\n      60.002765665 seconds time elapsed\n\nIt's important to know that there are two very different ways in which PMCs can\nbe used (counting and sampling), and we've focused solely on PMCs counting for\nthe sake of this analysis. Brendan Greg clearly explains it on the following\n[link](http://www.brendangregg.com/blog/2017-05-04/the-pmcs-of-ec2.html)."
    }
  ],
  "examples": []
}
