Created
July 18, 2013 07:06
-
-
Save ssimeonov/6027269 to your computer and use it in GitHub Desktop.
Analyze dyno memory use on Heroku with this memory footprint analyzer.
This file contains hidden or 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
# Memory snapshot analyzer which parses the /proc file system on *nix | |
# | |
# Example (run in Heroku console): | |
# | |
# ms = MemorySnapshot.new | |
# 1.upto(10000).map { |i| Array.new(i) }; nil | |
# ms.snapshot!; nil | |
# ms.diff 10 | |
# => {"lib/ld-2.11.1.so"=>156, "heap"=>2068, "all"=>2224} | |
# | |
class MemorySnapshot | |
attr_reader :previous | |
attr_reader :current | |
def initialize | |
snapshot! | |
@previous = @current | |
end | |
# Generates a Hash of memory elements mapped to sizes of the elements in Kb | |
def snapshot! | |
@previous = @current | |
@current = reduce(names_with_sizes) | |
end | |
# Calculates the difference between the previous and the current snapshot | |
# Threshold is a minimum delta in kilobytes required to include an entry | |
def diff(threshold = 0) | |
self.class.diff_between previous, current, threshold | |
end | |
# Calculates the difference between two memory snapshots | |
# Threshold is a minimum delta in kilobytes required to include an entry | |
def self.diff_between(before, after, threshold) | |
names = (before.keys + after.keys).uniq | |
names.reduce({}) do |memo, name| | |
delta = after.fetch(name) { 0 } - before.fetch(name) { 0 } | |
memo[name] = delta if delta.abs >= threshold | |
memo | |
end | |
end | |
private | |
def reduce(matches) | |
total = 0 | |
current_name = nil | |
matches.reduce(Hash.new { 0 }) do |memo, match| | |
current_name = match[:name] || current_name | |
size = match[:size].to_i | |
total += size | |
memo[current_name] += size | |
memo | |
end.tap { |snapshot| snapshot['all'] = total } | |
end | |
def names_with_sizes | |
smap_entries.map do |line| | |
/((^(\/|\[)(?<name>[^ \]]+)\]?\s+)|(^))(?<size>\d+)\s/.match(line) | |
end | |
end | |
def smap_entries | |
smaps. | |
gsub(/^(([^Sa-f0-9])|(S[^i]))[^\n]+\n/m, ''). | |
gsub(/\nSize:/m, ''). | |
gsub(/[0-9a-f]+-[0-9a-f]+.{6}[0-9a-f]+ [0-9a-f]+:[0-9a-f]+ [0-9a-f]+\s+/i, ''). | |
split("\n") | |
end | |
def smaps | |
File.read("/proc/#{Process.pid}/smaps") | |
end | |
end |
Same here. Not sure how I can use this.
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Hi @ssimeonov, thank you for sharing this.
I am running 2 dynos on Heroku App - Web dyno and Sidekiq worker dyno.
But I am not sure how I can check Sidekiq worker dyno memory usage using this class.
Can you help me to check?
Thank you.