Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
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

This comment has been minimized.

Copy link

commented Mar 19, 2015

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Owner Author

commented Aug 3, 2015

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

@brianhempel

This comment has been minimized.

Copy link
Owner Author

commented Aug 3, 2015

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

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

@luiszacheu

This comment has been minimized.

Copy link

commented Dec 20, 2016

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

@leemour

This comment has been minimized.

Copy link

commented Dec 24, 2016

@luiszacheu You should set proper server_pid in the script

@murphyryan1

This comment has been minimized.

Copy link

commented Feb 23, 2017

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
You can’t perform that action at this time.