Skip to content

Commit

Permalink
Add memory scripts.
Browse files Browse the repository at this point in the history
  • Loading branch information
stevenbeales committed Apr 4, 2018
1 parent a688222 commit 73262d7
Show file tree
Hide file tree
Showing 9 changed files with 516 additions and 6 deletions.
1 change: 1 addition & 0 deletions .rubocop.yml
Expand Up @@ -6,6 +6,7 @@ AllCops:
- 'db/schema.rb'
- 'bin/**/*'
- 'public/**/*'
- 'script/**/*'
TargetRubyVersion: 2.5

Metrics/LineLength:
Expand Down
8 changes: 7 additions & 1 deletion Gemfile
Expand Up @@ -8,15 +8,20 @@ gem 'audited', '>= 4.7.0', require: false # adds table auiting support
gem 'bugsnag', '>= 6.6', require: false # online bug reporting
gem 'bundler-audit', '>= 0.6.0', require: false # check gems for security issues
gem 'dotenv', '>= 2.2.1', require: false # adds environment variables from .env files
gem 'fast_blank', '>= 1.0.0', platform: :ruby, require: false # faster implementation of blank?
gem 'fast_stack', '>= 0.2.0', platform: :ruby, require: false # stack profiler
gem 'flamegraph', '>= 0.9.5', require: false # rack profiling
gem 'i18n', '>= 1.0.0', require: false # internationalization support
gem 'jsonb_accessor', '>= 1.0.0', require: false # adds methods to access Jsonb fields
gem 'memory_profiler', '>= 0.9.10', platform: :ruby, require: false # memory profiler
gem 'multi_json', '>= 1.13.1', require: false # common interface to load json
gem 'oj', '>= 3.5.0', require: false # faster json parsing
gem 'pg', '>= 1.0.0', platform: :ruby, require: false # for Postgres
gem 'pg_search', '>= 2.1.2', require: false # Postgres full text search
gem 'puma', '>= 3.11.2', require: false # puma web server
gem 'rack-contrib', '>= 2.0.1', require: false # browser localization
gem 'rack-heartbeat', '>= 1.1.0', require: false # provide heartbeat URL
gem 'rack-mini-profiler', '>= 1.0.0', require: false # profiling Rack apps
gem 'rack-timeout', '>= 0.4.2', require: false # configure Rack timeout
gem 'rake', '>= 12.3.1', require: false # so we can run Rake tasks
gem 'ralyxa', '>= 1.7.0', require: false # ruby alexa framework
Expand Down Expand Up @@ -45,7 +50,6 @@ group :test do
gem 'scrutinizer-ocular', '>= 1.0.1', require: false # scrutinizer code coverage
gem 'simplecov', '>= 0.16.1', require: false # for code coverage
gem 'simplecov-console', '>= 0.4.2', require: false # code coverage to console
gem 'timecop', '>= 0.9.1', require: false # testing time dependent
gem 'travis', '>= 1.8.8', require: false # for continuous integrations
gem 'travis_check_rubies', '>= 0.2.5', require: false # check ruby versions on Travis
end
Expand All @@ -57,6 +61,8 @@ group :development, :test do
gem 'guard', '>= 2.14.2', require: false # watch for changed files
gem 'guard-rspec', '>= 4.7.3', require: false # run rspec on code change
gem 'overcommit', require: false # git hooks
gem 'ruby-prof', platform: :ruby, require: false
gem 'timecop', '>= 0.9.1', require: false # testing time dependent
end

group :doc do
Expand Down
14 changes: 13 additions & 1 deletion Gemfile.lock
Expand Up @@ -55,8 +55,11 @@ GEM
multipart-post (>= 1.2, < 3)
faraday_middleware (0.12.2)
faraday (>= 0.7.4, < 1.0)
fast_blank (1.0.0)
fast_stack (0.2.0)
ffi (1.9.23)
ffi (1.9.23-x64-mingw32)
flamegraph (0.9.5)
formatador (0.2.5)
fspath (3.1.0)
fuubar (2.3.1)
Expand Down Expand Up @@ -104,6 +107,7 @@ GEM
lumberjack (1.0.13)
mail (2.7.0)
mini_mime (>= 0.1.1)
memory_profiler (0.9.10)
method_source (0.9.0)
mime-types (3.1)
mime-types-data (~> 3.2015)
Expand Down Expand Up @@ -146,6 +150,8 @@ GEM
rack (~> 2.0)
rack-heartbeat (1.1.0)
rack
rack-mini-profiler (1.0.0)
rack (>= 1.2.0)
rack-protection (2.0.1)
rack
rack-ssl (1.4.1)
Expand Down Expand Up @@ -192,6 +198,7 @@ GEM
rainbow (>= 2.2.2, < 4.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-prof (0.17.0)
ruby-progressbar (1.9.0)
ruby_audit (1.2.0)
bundler-audit (~> 0.6.0)
Expand Down Expand Up @@ -258,7 +265,6 @@ GEM
unf (0.1.4)
unf_ext
unf_ext (0.0.7.5)
unf_ext (0.0.7.5-x64-mingw32)
unicode-display_width (1.3.0)
useragent (0.16.10)
valid_email2 (2.2.2)
Expand All @@ -284,11 +290,15 @@ DEPENDENCIES
dotenv (>= 2.2.1)
factory_bot (>= 4.0)
faker (>= 1.8.7)
fast_blank (>= 1.0.0)
fast_stack (>= 0.2.0)
flamegraph (>= 0.9.5)
fuubar (>= 2.3.1)
guard (>= 2.14.2)
guard-rspec (>= 4.7.3)
i18n (>= 1.0.0)
jsonb_accessor (>= 1.0.0)
memory_profiler (>= 0.9.10)
multi_json (>= 1.13.1)
oj (>= 3.5.0)
overcommit
Expand All @@ -297,6 +307,7 @@ DEPENDENCIES
puma (>= 3.11.2)
rack-contrib (>= 2.0.1)
rack-heartbeat (>= 1.1.0)
rack-mini-profiler (>= 1.0.0)
rack-protection (>= 2.0.1)
rack-ssl (>= 1.4.1)
rack-test (>= 1.0.0)
Expand All @@ -307,6 +318,7 @@ DEPENDENCIES
route_downcaser (>= 1.2.1)
rspec (>= 3.7.0)
rubocop (>= 0.54.0)
ruby-prof
ruby_audit (>= 1.2.0)
scrutinizer-ocular (>= 1.0.1)
sdoc (>= 1.0.0)
Expand Down
3 changes: 3 additions & 0 deletions config/environment.rb
@@ -0,0 +1,3 @@
# frozen_string_literal: true

# Rails compatibility
39 changes: 39 additions & 0 deletions script/diff_heaps.rb
@@ -0,0 +1,39 @@
# to be used to compare ruby heaps generated in 2.1
# can isolate memory leaks
#
# rbtrace -p 15193 -e 'Thread.new{require "objspace"; ObjectSpace.trace_object_allocations_start; GC.start(full_mark: true); ObjectSpace.dump_all(output: File.open("heap.json","w"))}.join'
#
#
require 'set'
require 'json'

if ARGV.length != 2
puts "Usage: diff_heaps [ORIG.json] [AFTER.json]"
exit 1
end

origs = Set.new

File.open(ARGV[0], "r").each_line do |line|
parsed = JSON.parse(line)
origs << parsed["address"] if parsed && parsed["address"]
end

diff = []

File.open(ARGV[1], "r").each_line do |line|
parsed = JSON.parse(line)
if parsed && parsed["address"]
diff << parsed unless origs.include? parsed["address"]
end
end

diff.group_by do |x|
[x["type"], x["file"], x["line"]]
end.map { |x, y|
[x, y.count]
}.sort { |a, b|
b[1] <=> a[1]
}.each { |x, y|
puts "Leaked #{y} #{x[0]} objects at: #{x[1]}:#{x[2]}"
}
169 changes: 169 additions & 0 deletions script/measure.rb
@@ -0,0 +1,169 @@
# using this script to try figure out why Ruby 2 is slower than 1.9
require 'flamegraph'

Flamegraph.generate('test.html', fidelity: 2) do
require File.expand_path("../../config/environment", __FILE__)
end
exit

require 'memory_profiler'

result = MemoryProfiler.report do
require File.expand_path("../../config/environment", __FILE__)
end
result.pretty_print

exit

require 'benchmark'

def profile_allocations(name)
GC.disable
initial_size = ObjectSpace.count_objects
yield
changes = ObjectSpace.count_objects
changes.each do |k, _|
changes[k] -= initial_size[k]
end
puts "#{name} changes"
changes.sort { |a, b| b[1] <=> a[1] }.each do |a, b|
next if b <= 0
# 1 extra hash for tracking
puts "#{a} #{a == :T_HASH ? b - 1 : b}"
end
GC.enable
end

def profile(name, &block)
puts "Profiling all object allocation for #{name}"
GC.start
GC.disable

items = []
objs = []

ObjectSpace.trace_object_allocations do
block.call

ObjectSpace.each_object do |o|
objs << o
end

objs.each do |o|
g = ObjectSpace.allocation_generation(o)
if g
l = ObjectSpace.allocation_sourceline(o)
f = ObjectSpace.allocation_sourcefile(o)
c = ObjectSpace.allocation_class_path(o)
m = ObjectSpace.allocation_method_id(o)
items << "Allocated #{c} in #{m} #{f}:#{l}"
end
end
end

items.group_by { |x| x }.sort { |a, b| b[1].length <=> a[1].length }.each do |row, group|
puts "#{row} x #{group.length}"
end

GC.enable
profile_allocations(name, &block)
end

def stuff
u = User.first
r = TopicQuery.new(u, {}).list_latest
r.topics.to_a
end

stuff
profile_allocations "stuff" do
stuff
end

# Benchmark.bmbm do |x|
#
# x.report("find") do
# 100.times{stuff}
# end
#
# end
#
# x.report("grab 10 users id") do
# 100.times{User.limit(10).select(:id).to_a}
# end
#
# x.report("grab 10 users") do
# 100.times{User.limit(10).to_a}
# end
#
# profile("topic query") do
# r = TopicQuery.new(u, {}).list_latest
# r.topics.to_a
# end

#
# RubyProf.start
#
# r = TopicQuery.new(u, {}).list_latest
# r.topics.to_a
#
# result = RubyProf.stop
# printer = RubyProf::GraphPrinter.new(result)
# # printer = RubyProf::FlatPrinter.new(result)
# printer.print(STDOUT, :min_percent => 2)
#
# exit
#
# # User.limit(10).to_a
# User.limit(10).select(:created_at).to_a
#
# profile("limit 10") do
# User.limit(10).select(:created_at).to_a
# end
#
# exit
# User.limit(10).to_a
# exit
#
# User.select('id, 2 bob').first
# Benchmark.bmbm do |x|
#
# x.report("find") do
# 100.times{User.find(1)}
# end
#
# x.report("grab 10 users created_at") do
# 100.times{User.limit(10).select(:created_at).to_a}
# end
#
# x.report("grab 10 users id") do
# 100.times{User.limit(10).select(:id).to_a}
# end
#
# x.report("grab 10 users") do
# 100.times{User.limit(10).to_a}
# end
#
#
# x.report("pg direct grab 10 users") do
# 100.times do
# r = ActiveRecord::Base.connection.raw_connection.async_exec("select * from users limit 10")
# r.fields.each_with_index do |f,i|
# r.ftype(i)
# end
# r.each_row do |x|
# x
# end
# end
# end
#
# end
#

# profile("find") do
# User.find(1)
# end
# puts
# profile("where") do
# User.where(id: 1).first
# end

0 comments on commit 73262d7

Please sign in to comment.