From fb60daa867ff2427cd671b153f20133f768fe49b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lourens=20Naud=C3=A9?= Date: Sun, 7 Dec 2014 22:54:35 +0000 Subject: [PATCH] Introduce support for dumping Rails process heap at the end of a benchmark run --- app/controllers/admin/diagnostics_controller.rb | 16 ++++++++++++++++ config/boot.rb | 5 +++++ config/routes.rb | 1 + script/bench.rb | 17 ++++++++++++++--- 4 files changed, 36 insertions(+), 3 deletions(-) diff --git a/app/controllers/admin/diagnostics_controller.rb b/app/controllers/admin/diagnostics_controller.rb index b4eee9902..d3ea9cc96 100644 --- a/app/controllers/admin/diagnostics_controller.rb +++ b/app/controllers/admin/diagnostics_controller.rb @@ -18,4 +18,20 @@ class Admin::DiagnosticsController < Admin::AdminController content_type: Mime::TEXT end + + def dump_heap + begin + # ruby 2.1 + GC.start(full_mark: true) + require 'objspace' + + io = File.open("discourse-heap-#{SecureRandom.hex(3)}.json",'w') + ObjectSpace.dump_all(:output => io) + io.close + + render text: "HEAP DUMP:\n#{io.path}", content_type: Mime::TEXT + rescue + render text: "HEAP DUMP:\nnot supported", content_type: Mime::TEXT + end + end end diff --git a/config/boot.rb b/config/boot.rb index 4489e5868..afa16ad5a 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,3 +1,8 @@ +if ENV['DISCOURSE_DUMP_HEAP'] == "1" + require 'objspace' + ObjectSpace.trace_object_allocations_start +end + require 'rubygems' # Set up gems listed in the Gemfile. diff --git a/config/routes.rb b/config/routes.rb index f694e87d9..271d7d636 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -181,6 +181,7 @@ Discourse::Application.routes.draw do end get "memory_stats"=> "diagnostics#memory_stats", constraints: AdminConstraint.new + get "dump_heap"=> "diagnostics#dump_heap", constraints: AdminConstraint.new end # admin namespace diff --git a/script/bench.rb b/script/bench.rb index d389a00d7..1b6eaaf0b 100644 --- a/script/bench.rb +++ b/script/bench.rb @@ -10,6 +10,7 @@ require "fileutils" @best_of = 1 @mem_stats = false @unicorn = false +@dump_heap = false opts = OptionParser.new do |o| o.banner = "Usage: ruby bench.rb [options]" @@ -26,6 +27,11 @@ opts = OptionParser.new do |o| o.on("-b", "--best_of [NUM]", "Number of times to run the bench taking best as result") do |i| @best_of = i.to_i end + o.on("-d", "--heap_dump") do + @dump_heap = true + # We need an env var for config/boot.rb to enable allocation tracing prior to framework init + ENV['DISCOURSE_DUMP_HEAP'] = "1" + end o.on("-m", "--memory_stats") do @mem_stats = true end @@ -103,18 +109,18 @@ end ENV["RAILS_ENV"] = "profile" -gc_env_vars = %w(RUBY_GC_HEAP_INIT_SLOTS RUBY_GC_HEAP_FREE_SLOTS RUBY_GC_HEAP_GROWTH_FACTOR RUBY_GC_HEAP_GROWTH_MAX_SLOTS RUBY_GC_MALLOC_LIMIT RUBY_GC_OLDMALLOC_LIMIT RUBY_GC_MALLOC_LIMIT_MAX RUBY_GC_OLDMALLOC_LIMIT_MAX RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR) +discourse_env_vars = %w(DISCOURSE_DUMP_HEAP RUBY_GC_HEAP_INIT_SLOTS RUBY_GC_HEAP_FREE_SLOTS RUBY_GC_HEAP_GROWTH_FACTOR RUBY_GC_HEAP_GROWTH_MAX_SLOTS RUBY_GC_MALLOC_LIMIT RUBY_GC_OLDMALLOC_LIMIT RUBY_GC_MALLOC_LIMIT_MAX RUBY_GC_OLDMALLOC_LIMIT_MAX RUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR RUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR RUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR) if @include_env puts "Running with tuned environment" ENV["RUBY_GC_MALLOC_LIMIT"] = "50_000_000" - gc_env_vars - %w(RUBY_GC_MALLOC_LIMIT).each do |v| + discourse_env_vars - %w(RUBY_GC_MALLOC_LIMIT).each do |v| ENV.delete v end else # clean env puts "Running with the following custom environment" - gc_env_vars.each do |w| + discourse_env_vars.each do |w| puts "#{w}: #{ENV[w]}" end end @@ -256,6 +262,11 @@ begin puts open("http://127.0.0.1:#{@port}/admin/memory_stats#{append}").read end + if @dump_heap + puts + puts open("http://127.0.0.1:#{@port}/admin/dump_heap#{append}").read + end + if @result_file File.open(@result_file,"wb") do |f| f.write(results)