From c273a6d1d4cc0b4c797a262bb904d0c96b75bc3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lourens=20Naud=C3=A9?= Date: Sat, 6 Dec 2014 21:02:58 +0000 Subject: [PATCH 1/3] Rails -> Ruby verbiage change in script/measure.rb --- script/measure.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/script/measure.rb b/script/measure.rb index d643625fb..bc49614ac 100644 --- a/script/measure.rb +++ b/script/measure.rb @@ -1,4 +1,4 @@ -# using this script to try figure out why Rails 2 is slower that 1.9 +# using this script to try figure out why Ruby 2 is slower that 1.9 # require 'flamegraph' 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 2/3] 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) From 2f75078758c5740751f9e436d414e6d07c58de5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lourens=20Naud=C3=A9?= Date: Sun, 7 Dec 2014 23:28:38 +0000 Subject: [PATCH 3/3] Do not assume all interpreter versions support allocation tracing --- config/boot.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/config/boot.rb b/config/boot.rb index afa16ad5a..517524d87 100644 --- a/config/boot.rb +++ b/config/boot.rb @@ -1,6 +1,10 @@ if ENV['DISCOURSE_DUMP_HEAP'] == "1" require 'objspace' - ObjectSpace.trace_object_allocations_start + begin + ObjectSpace.trace_object_allocations_start + rescue NoMethodError + puts "Heap dumps not available for Ruby #{RUBY_VERSION} (> 2.1 required)" + end end require 'rubygems'