[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"project-8019":3},{"id":4,"name":5,"fullName":6,"owner":7,"repo":5,"description":8,"homepage":9,"htmlUrl":10,"language":11,"languages":10,"totalLinesOfCode":10,"stars":12,"forks":13,"watchers":14,"openIssues":15,"contributorsCount":16,"subscribersCount":16,"size":16,"stars1d":16,"stars7d":16,"stars30d":17,"stars90d":16,"forks30d":16,"starsTrendScore":16,"compositeScore":18,"rankGlobal":10,"rankLanguage":10,"license":19,"archived":20,"fork":20,"defaultBranch":21,"hasWiki":22,"hasPages":20,"topics":23,"createdAt":10,"pushedAt":10,"updatedAt":24,"readmeContent":25,"aiSummary":26,"trendingCount":16,"starSnapshotCount":16,"syncStatus":27,"lastSyncTime":28,"discoverSource":29},8019,"stackprof","tmm1\u002Fstackprof","tmm1","a sampling call-stack profiler for ruby 2.2+","",null,"Ruby",2194,136,32,38,0,12,28.41,"MIT License",false,"master",true,[],"2026-06-12 02:01:47","# Stackprof\n\nA sampling call-stack profiler for Ruby.\n\nInspired heavily by [gperftools](https:\u002F\u002Fcode.google.com\u002Fp\u002Fgperftools\u002F), and written as a replacement for [perftools.rb](https:\u002F\u002Fgithub.com\u002Ftmm1\u002Fperftools.rb).\n\n## Requirements\n\n* Ruby 2.2+\n* Linux-based OS\n\n## Getting Started\n\n### Install\n\nIn your Gemfile add:\n\n```ruby\ngem 'stackprof'\n```\n\nThen run `$ bundle install`. Alternatively you can run `$ gem install stackprof`.\n\n\n### Run\n\nin ruby:\n\n``` ruby\nStackProf.run(mode: :cpu, out: 'tmp\u002Fstackprof-cpu-myapp.dump') do\n  #...\nend\n```\n\nvia rack:\n\n``` ruby\nuse StackProf::Middleware, enabled: true,\n                           mode: :cpu,\n                           interval: 1000,\n                           save_every: 5\n```\n\nreporting:\n\n```\n$ stackprof tmp\u002Fstackprof-cpu-*.dump --text --limit 1\n  ==================================\n    Mode: cpu(1000)\n    Samples: 60395 (1.09% miss rate)\n    GC: 2851 (4.72%)\n  ==================================\n       TOTAL    (pct)     SAMPLES    (pct)     FRAME\n        1660   (2.7%)        1595   (2.6%)     String#blank?\n\n$ stackprof tmp\u002Fstackprof-cpu-*.dump --method 'String#blank?'\n  String#blank? (gems\u002Factivesupport-2.3.14.github30\u002Flib\u002Factive_support\u002Fcore_ext\u002Fobject\u002Fblank.rb:80)\n    samples:  1595 self (2.6%)  \u002F   1660 total (2.7%)\n    callers:\n       373  (   41.0%)  ApplicationHelper#current_user\n       192  (   21.1%)  ApplicationHelper#current_repository\n    callers:\n       803  (   48.4%)  Object#present?\n    code:\n                                    |    80  |   def blank?\n   1225    (2.0%) \u002F  1225   (2.0%)  |    81  |     self !~ \u002F[^[:space:]]\u002F\n                                    |    82  |   end\n\n$ stackprof tmp\u002Fstackprof-cpu-*.dump --method 'Object#present?'\n  Object#present? (gems\u002Factivesupport-2.3.14.github30\u002Flib\u002Factive_support\u002Fcore_ext\u002Fobject\u002Fblank.rb:20)\n    samples:    59 self (0.1%)  \u002F    910 total (1.5%)\n    callees (851 total):\n       803  (   94.4%)  String#blank?\n        32  (    3.8%)  Object#blank?\n        16  (    1.9%)  NilClass#blank?\n    code:\n                                    |    20  |   def present?\n    910    (1.5%) \u002F    59   (0.1%)  |    21  |     !blank?\n                                    |    22  |   end\n```\n\nFor an experimental version of WebUI reporting of stackprof, see [stackprof-webnav](https:\u002F\u002Fgithub.com\u002Falisnic\u002Fstackprof-webnav)\n\nTo generate flamegraphs with Stackprof, additional data must be collected using the `raw: true` flag. Once you've collected results with this flag enabled, generate a flamegraph with:\n\n```\n$ stackprof --flamegraph tmp\u002Fstackprof-cpu-myapp.dump > tmp\u002Fflamegraph\n```\n\nAfter the flamegraph has been generated, you can generate a viewer command with:\n\n```\n$ stackprof --flamegraph-viewer=tmp\u002Fflamegraph\n```\n\nThe `--flamegraph-viewer` command will output the exact shell command you need to run in order to open the `tmp\u002Fflamegraph` you generated with the built-in stackprof flamegraph viewer:\n\n![Flamegraph Viewer](http:\u002F\u002Fi.imgur.com\u002FEwndrgD.png)\n\nAlternatively, you can generate a flamegraph that uses [d3-flame-graph](https:\u002F\u002Fgithub.com\u002Fspiermar\u002Fd3-flame-graph):\n\n```\n$ stackprof --d3-flamegraph tmp\u002Fstackprof-cpu-myapp.dump > flamegraph.html\n```\n\nAnd just open the result by your browser.\n\n## Sampling\n\nFour sampling modes are supported:\n\n  - `:wall` (using `ITIMER_REAL` and `SIGALRM`) [default mode]\n  - `:cpu` (using `ITIMER_PROF` and `SIGPROF`)\n  - `:object` (using `RUBY_INTERNAL_EVENT_NEWOBJ`)\n  - `:custom` (user-defined via `StackProf.sample`)\n\nSamplers have a tuneable interval which can be used to reduce overhead or increase granularity:\n\n  - Wall time: sample every _interval_ microseconds of wallclock time (default: 1000)\n\n```ruby\nStackProf.run(mode: :wall, out: 'tmp\u002Fstackprof.dump', interval: 1000) do\n  #...\nend\n```\n\n  - CPU time: sample every _interval_ microseconds of CPU activity (default: 1000 = 1 millisecond)\n\n```ruby\nStackProf.run(mode: :cpu, out: 'tmp\u002Fstackprof.dump', interval: 1000) do\n  #...\nend\n```\n\n  - Object allocation: sample every _interval_ allocations (default: 1)\n\n\n```ruby\nStackProf.run(mode: :object, out: 'tmp\u002Fstackprof.dump', interval: 1) do\n  #...\nend\n```\n\nBy default, samples taken during garbage collection will show as garbage collection frames\nincluding both mark and sweep phases. For longer traces, these can leave gaps in a flamegraph\nthat are hard to follow. They can be disabled by setting the `ignore_gc` option to true.\nGarbage collection time will still be present in the profile but not explicitly marked with\nits own frame.\n\nSamples are taken using a combination of three new C-APIs in ruby 2.1:\n\n  - Signal handlers enqueue a sampling job using `rb_postponed_job_register_one`.\n    this ensures callstack samples can be taken safely, in case the VM is garbage collecting\n    or in some other inconsistent state during the interruption.\n\n  - Stack frames are collected via `rb_profile_frames`, which provides low-overhead C-API access\n    to the VM's call stack. No object allocations occur in this path, allowing stackprof to collect\n    callstacks in allocation mode.\n\n  - In allocation mode, samples are taken via `rb_tracepoint_new(RUBY_INTERNAL_EVENT_NEWOBJ)`,\n    which provides a notification every time the VM allocates a new object.\n\n## Aggregation\n\nEach sample consists of N stack frames, where a frame looks something like `MyClass#method` or `block in MySingleton.method`.\nFor each of these frames in the sample, the profiler collects a few pieces of metadata:\n\n  - `samples`: Number of samples where this was the topmost frame\n  - `total_samples`: Samples where this frame was in the stack\n  - `lines`: Samples per line number in this frame\n  - `edges`: Samples per callee frame (methods invoked by this frame)\n\nThe aggregation algorithm is roughly equivalent to the following pseudo code:\n\n``` ruby\ntrap('PROF') do\n  top, *rest = caller\n\n  top.samples += 1\n  top.lines[top.lineno] += 1\n  top.total_samples += 1\n\n  prev = top\n  rest.each do |frame|\n    frame.edges[prev] += 1\n    frame.total_samples += 1\n    prev = frame\n  end\nend\n```\n\nThis technique builds up an incremental call graph from the samples. On any given frame,\nthe sum of the outbound edge weights is equal to total samples collected on that frame\n(`frame.total_samples == frame.edges.values.sum`).\n\n## Reporting\n\nMultiple reporting modes are supported:\n  - Text\n  - Dotgraph\n  - Source annotation\n\n### `StackProf::Report.new(data).print_text`\n\n```\n     TOTAL    (pct)     SAMPLES    (pct)     FRAME\n        91  (48.4%)          91  (48.4%)     A#pow\n        58  (30.9%)          58  (30.9%)     A.newobj\n        34  (18.1%)          34  (18.1%)     block in A#math\n       188 (100.0%)           3   (1.6%)     block (2 levels) in \u003Cmain>\n       185  (98.4%)           1   (0.5%)     A#initialize\n        35  (18.6%)           1   (0.5%)     A#math\n       188 (100.0%)           0   (0.0%)     \u003Cmain>\n       188 (100.0%)           0   (0.0%)     block in \u003Cmain>\n       188 (100.0%)           0   (0.0%)     \u003Cmain>\n```\n\n### `StackProf::Report.new(data).print_graphviz`\n\n```\ndigraph profile {\n  70346498324780 [size=23.5531914893617] [fontsize=23.5531914893617] [shape=box] [label=\"A#pow\\n91 (48.4%)\\r\"];\n  70346498324680 [size=18.638297872340424] [fontsize=18.638297872340424] [shape=box] [label=\"A.newobj\\n58 (30.9%)\\r\"];\n  70346498324480 [size=15.063829787234042] [fontsize=15.063829787234042] [shape=box] [label=\"block in A#math\\n34 (18.1%)\\r\"];\n  70346498324220 [size=10.446808510638299] [fontsize=10.446808510638299] [shape=box] [label=\"block (2 levels) in \u003Cmain>\\n3 (1.6%)\\rof 188 (100.0%)\\r\"];\n  70346498324220 -> 70346498324900 [label=\"185\"];\n  70346498324900 [size=10.148936170212766] [fontsize=10.148936170212766] [shape=box] [label=\"A#initialize\\n1 (0.5%)\\rof 185 (98.4%)\\r\"];\n  70346498324900 -> 70346498324780 [label=\"91\"];\n  70346498324900 -> 70346498324680 [label=\"58\"];\n  70346498324900 -> 70346498324580 [label=\"35\"];\n  70346498324580 [size=10.148936170212766] [fontsize=10.148936170212766] [shape=box] [label=\"A#math\\n1 (0.5%)\\rof 35 (18.6%)\\r\"];\n  70346498324580 -> 70346498324480 [label=\"34\"];\n  70346497983360 [size=10.0] [fontsize=10.0] [shape=box] [label=\"\u003Cmain>\\n0 (0.0%)\\rof 188 (100.0%)\\r\"];\n  70346497983360 -> 70346498325080 [label=\"188\"];\n  70346498324300 [size=10.0] [fontsize=10.0] [shape=box] [label=\"block in \u003Cmain>\\n0 (0.0%)\\rof 188 (100.0%)\\r\"];\n  70346498324300 -> 70346498324220 [label=\"188\"];\n  70346498325080 [size=10.0] [fontsize=10.0] [shape=box] [label=\"\u003Cmain>\\n0 (0.0%)\\rof 188 (100.0%)\\r\"];\n  70346498325080 -> 70346498324300 [label=\"188\"];\n}\n```\n\n### `StackProf::Report.new(data).print_method(\u002Fpow|newobj|math\u002F)`\n\n```\nA#pow (\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb:11)\n                         |    11  |   def pow\n   91  (48.4% \u002F 100.0%)  |    12  |     2 ** 100\n                         |    13  |   end\nA.newobj (\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb:15)\n                         |    15  |   def self.newobj\n   33  (17.6% \u002F  56.9%)  |    16  |     Object.new\n   25  (13.3% \u002F  43.1%)  |    17  |     Object.new\n                         |    18  |   end\nA#math (\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb:20)\n                         |    20  |   def math\n    1   (0.5% \u002F 100.0%)  |    21  |     2.times do\n                         |    22  |       2 + 3 * 4 ^ 5 \u002F 6\nblock in A#math (\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb:21)\n                         |    21  |     2.times do\n   34  (18.1% \u002F 100.0%)  |    22  |       2 + 3 * 4 ^ 5 \u002F 6\n                         |    23  |     end\n```\n\n## Usage\n\nThe profiler is compiled as a C-extension and exposes a simple api: `StackProf.run(mode: [:cpu|:wall|:object])`.\nThe `run` method takes a block of code and returns a profile as a simple hash.\n\n``` ruby\n# sample after every 1ms of cpu activity\nprofile = StackProf.run(mode: :cpu, interval: 1000) do\n  MyCode.execute\nend\n```\n\nThis profile data structure is part of the public API, and is intended to be saved\n(as json\u002Fmarshal for example) for later processing. The reports above can be generated\nby passing this structure into `StackProf::Report.new`.\n\nThe format itself is very simple. It contains a header and a list of frames. Each frame has a unique ID and\nidentifying information such as its name, file, and line. The frame also contains sampling data, including per-line\nsamples, and a list of relationships to other frames represented as weighted edges.\n\n``` ruby\n{:version=>1.0,\n :mode=>:cpu,\n :inteval=>1000,\n :samples=>188,\n :missed_samples=>0,\n :frames=>\n  {70346498324780=>\n    {:name=>\"A#pow\",\n     :file=>\"\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb\",\n     :line=>11,\n     :total_samples=>91,\n     :samples=>91,\n     :lines=>{12=>91}},\n   70346498324900=>\n    {:name=>\"A#initialize\",\n     :file=>\"\u002FUsers\u002Ftmm1\u002Fcode\u002Fstackprof\u002Fsample.rb\",\n     :line=>5,\n     :total_samples=>185,\n     :samples=>1,\n     :edges=>{70346498324780=>91, 70346498324680=>58, 70346498324580=>35},\n     :lines=>{8=>1}},\n```\n\nAbove, `A#pow` was involved in 91 samples, and in all cases it was at the top of the stack on line 12.\n\n`A#initialize` was in 185 samples, but it was at the top of the stack in only 1 sample. The rest of the samples are\ndivided up between its callee edges. All 91 calls to `A#pow` came from `A#initialize`, as seen by the edge numbered\n`70346498324780`.\n\n## Advanced usage\n\nThe profiler can be started and stopped manually. Results are accumulated until retrieval, across\nmultiple `start`\u002F`stop` invocations.\n\n``` ruby\nStackProf.running? # => false\nStackProf.start(mode: :cpu)\nStackProf.running? # => true\nStackProf.stop\nStackProf.results('\u002Ftmp\u002Fsome.file')\n```\n\n## All options\n\n`StackProf.run` accepts an options hash. Currently, the following options are recognized:\n\nOption      | Meaning\n-------     | ---------\n`mode`      | Mode of sampling: `:cpu`, `:wall`, `:object`, or `:custom` [c.f.](#sampling)\n`out`       | The target file, which will be overwritten\n`interval`  | Mode-relative sample rate [c.f.](#sampling)\n`ignore_gc` | Ignore garbage collection frames\n`aggregate` | Defaults: `true` - if `false` disables [aggregation](#aggregation)\n`raw`       | Defaults `false` - if `true` collects the extra data required by the `--flamegraph` and `--stackcollapse` report types\n`metadata`  | Defaults to `{}`. Must be a `Hash`. metadata associated with this profile\n`save_every`| (Rack middleware only) write the target file after this many requests\n\n## Todo\n\n* file\u002Fiseq blacklist\n* restore signal handlers on stop\n","Stackprof 是一个针对 Ruby 2.2+ 的采样调用栈分析工具。它通过采样方式收集程序运行时的调用栈信息，帮助开发者识别性能瓶颈。核心功能包括 CPU 和内存使用情况的分析，支持多种报告格式如文本、火焰图等，并且可以作为 Rack 中间件集成到 Web 应用中。适用于需要对 Ruby 应用进行性能优化和调试的场景，尤其是在 Linux 环境下开发和部署的应用。",2,"2026-06-11 03:15:41","top_language"]