Skip to content

Instantly share code, notes, and snippets.

@brianhempel
Last active October 6, 2022 12:47
Show Gist options
  • Save brianhempel/6dae23d52cc7f5071a39 to your computer and use it in GitHub Desktop.
Save brianhempel/6dae23d52cc7f5071a39 to your computer and use it in GitHub Desktop.
A script to test the memory usage of your Rails application over time. It will run 30 requests against the specified action and report the final RSS. Choose the URL to hit on line 45 and then run with `ruby bench_rails_memory_usage.rb`.
require "net/http"
def start_server
# Remove the X to enable the parameters for tuning.
# These are the default values as of Ruby 2.2.0.
@child = spawn(<<-EOC.split.join(" "))
XRUBY_GC_HEAP_FREE_SLOTS=4096
XRUBY_GC_HEAP_INIT_SLOTS=10000
XRUBY_GC_HEAP_GROWTH_FACTOR=1.8
XRUBY_GC_HEAP_GROWTH_MAX_SLOTS=0
XRUBY_GC_HEAP_OLDOBJECT_LIMIT_FACTOR=2.0
XRUBY_GC_MALLOC_LIMIT=16777216
XRUBY_GC_MALLOC_LIMIT_MAX=33554432
XRUBY_GC_MALLOC_LIMIT_GROWTH_FACTOR=1.4
XRUBY_GC_OLDMALLOC_LIMIT=16777216
XRUBY_GC_OLDMALLOC_LIMIT_MAX=134217728
XRUBY_GC_OLDMALLOC_LIMIT_GROWTH_FACTOR=1.2
rails server -p3009 > /dev/null
EOC
sleep 0.1 until alive?
end
def alive?
system("curl http://localhost:3009/ &> /dev/null")
end
def stop_server
Process.kill "HUP", server_pid
Process.wait @child
end
def server_pid
`cat tmp/pids/server.pid`.to_i
end
def memory_size_mb
(`ps -o rss= -p #{server_pid}`.to_i * 1024).to_f / 2**20
end
# In /etc/hosts I have api.rails.local set to 127.0.0.1 for
# API testing on any app. Curl freaks out and takes extra
# seconds to do the request to these .local things, so we
# will use Net::HTTP for moar speed.
def do_request
uri = URI("http://api.rails.local:3009/memory_heavy_action")
req = Net::HTTP::Get.new(uri)
# Remove the next line if you don't need HTTP basic authentication.
req.basic_auth("user@example.com", "password")
req["Content-Type"] = "application/json"
Net::HTTP.start("localhost", uri.port) do |http|
http.read_timeout = 60
http.request(req)
end
end
results = []
# You can’t just measure once: memory usage has some variance.
# We will take the mean of 7 runs.
7.times do
start_server
used_mb = nil
(1..30).map do |n|
print "Request #{n}..."
do_request
used_mb = memory_size_mb
puts "#{used_mb} MB"
end
final_mb = used_mb
results << final_mb
puts "Final Memory: #{final_mb} MB"
stop_server
end
mean_final_mb = results.reduce(:+) / results.size
puts "Mean Final Memory: #{mean_final_mb} MB"
@brandonkboswell
Copy link

Any idea how to make this work with Puma and multiple works? My tmp/pids/server.pid seems to be Puma itself and not the actual workers I want to measure memory on.

@mrzasa
Copy link

mrzasa commented Apr 27, 2015

What is a license for this script? I would like to use it in a commercial project, but I don't want to breach the copyright (to me it is a common problem with gists 😉 )

@brianhempel
Copy link
Author

@brandonkboswell No, I haven't tried it with puma. Let us know if you figure it out.

@brianhempel
Copy link
Author

@mrzasa License is Public Domain per https://creativecommons.org/publicdomain/zero/1.0/

Feel free to use it. https://xkcd.com/1553/

@luiszacheu
Copy link

I haven't tried it with unicorn but don't show size of memory! I need put on script's directory?

@leemour
Copy link

leemour commented Dec 24, 2016

@luiszacheu You should set proper server_pid in the script

@murphyryan1
Copy link

How do I run this? Do I add a file in my project somewhere?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment