Last active
October 6, 2022 12:47
-
-
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`.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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" |
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 😉 )
@brandonkboswell No, I haven't tried it with puma. Let us know if you figure it out.
@mrzasa License is Public Domain per https://creativecommons.org/publicdomain/zero/1.0/
Feel free to use it. https://xkcd.com/1553/
I haven't tried it with unicorn but don't show size of memory! I need put on script's directory?
@luiszacheu You should set proper server_pid
in the script
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
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.