aiwilliams-oink 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/History.txt +4 -0
- data/MIT-LICENSE +21 -0
- data/README.rdoc +118 -0
- data/Rakefile +44 -0
- data/bin/oink +5 -0
- data/lib/oink.rb +5 -0
- data/lib/oink/active_record_instantiation_reporter.rb +65 -0
- data/lib/oink/base.rb +39 -0
- data/lib/oink/cli.rb +97 -0
- data/lib/oink/memory_usage_reporter.rb +70 -0
- data/lib/oink/oinked_request/oinked_ar_request.rb +9 -0
- data/lib/oink/oinked_request/oinked_memory_request.rb +9 -0
- data/lib/oink/oinked_request/oinked_request.rb +20 -0
- data/lib/oink/priority_queue.rb +37 -0
- data/lib/oink/rails/instance_type_counter.rb +84 -0
- data/lib/oink/rails/memory_usage_logger.rb +17 -0
- metadata +71 -0
data/History.txt
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
Copyright (c) 2009 Noah Davis
|
2
|
+
Copyright (c) 2008 Ben Johnson of Binary Logic (binarylogic.com)
|
3
|
+
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
a copy of this software and associated documentation files (the
|
6
|
+
"Software"), to deal in the Software without restriction, including
|
7
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be
|
13
|
+
included in all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,118 @@
|
|
1
|
+
=== Oink
|
2
|
+
|
3
|
+
* http://github.com/noahd1/oink
|
4
|
+
|
5
|
+
=== Description
|
6
|
+
|
7
|
+
Rails plugin and log parser to help narrow down the source(s) of increased memory usage in rails applications.
|
8
|
+
|
9
|
+
=== Synopsis
|
10
|
+
|
11
|
+
Oink adds memory and active record instantiation information to rails log during runtime and provides an executable to help digest the enhanced logs.
|
12
|
+
|
13
|
+
Given a minimum threshold and a metric (memory or active record instantiation), the oink executable reports:
|
14
|
+
|
15
|
+
1. The top ten single requests which exceeded the threshold for the metric, ordered by the request which exceeded the threshold the most
|
16
|
+
2. The number of times each action exceeded the threshold for the metric, ordered by the action which exceeded the threshold the most
|
17
|
+
3. (in verbose mode) The log lines produced by requests which exceeded the threshold
|
18
|
+
|
19
|
+
Many thanks to Ben Johnson for Memory Usage Logger (http://github.com/binarylogic/memory_usage_logger/tree/master) which is the basis of this plugin.
|
20
|
+
|
21
|
+
== Dependencies
|
22
|
+
|
23
|
+
Currently oink can only parse logs in the Hodel3000Logger format
|
24
|
+
|
25
|
+
- http://github.com/topfunky/hodel_3000_compliant_logger/tree/master
|
26
|
+
|
27
|
+
=== Install
|
28
|
+
|
29
|
+
To print memory usage at the end of each request, include Oink::MemoryUsageLogger in your controller. This will add lines like:
|
30
|
+
|
31
|
+
class ApplicationController
|
32
|
+
include Oink::MemoryUsageLogger
|
33
|
+
end
|
34
|
+
|
35
|
+
which results in lines like this added to each request:
|
36
|
+
|
37
|
+
Feb 08 11:39:54 ey33-s00302 rails[9076]: Memory usage: 316516 | PID: 9076
|
38
|
+
|
39
|
+
To print active record instantiation at the end of each request, include Oink::InstanceTypeCounter in your controller.
|
40
|
+
|
41
|
+
class ApplicationController
|
42
|
+
include Oink::InstanceTypeCounter
|
43
|
+
end
|
44
|
+
|
45
|
+
which results in lines like this added to each request:
|
46
|
+
|
47
|
+
Feb 27 13:21:04 ey04-s00295 rails[11862]: Instantiation Breakdown: Total: 73 | User: 34 | Group: 20 | Medium: 20 | Sport: 10 | Post: 4 | Discussion: 2
|
48
|
+
|
49
|
+
== Usage
|
50
|
+
|
51
|
+
After installing the plugin and aggregating some enhanced logs, run the oink executable against the logs. Oink can point at a log file or a directory of log files
|
52
|
+
|
53
|
+
Usage: oink [options] files
|
54
|
+
-t, --threshold [INTEGER] Memory threshold in MB
|
55
|
+
-f, --file filepath Output to file
|
56
|
+
--format FORMAT Select format
|
57
|
+
(ss,v,s,verbose,short-summary,summary)
|
58
|
+
-m, --memory Check for Memory Threshold (default)
|
59
|
+
-r, --active-record Check for Active Record Threshold
|
60
|
+
|
61
|
+
Oink hunts for requests which exceed a given threshold. In "memory" mode (the default), the threshold represents a megabyte memory increase from the previous request. In "active record" mode (turned on by passing the --active-record switch), the threshold represents the number of active record objects instantiated during a request.
|
62
|
+
|
63
|
+
e.g. To find all actions which increase the heap size more than 75 MB, where log files are location in /tmp/logs/
|
64
|
+
|
65
|
+
$ oink --threshold=75 /tmp/logs/*
|
66
|
+
---- MEMORY THRESHOLD ----
|
67
|
+
THRESHOLD: 75 MB
|
68
|
+
|
69
|
+
-- SUMMARY --
|
70
|
+
Worst Requests:
|
71
|
+
1. Feb 02 16:26:06, 157524 KB, SportsController#show
|
72
|
+
2. Feb 02 20:11:54, 134972 KB, DashboardsController#show
|
73
|
+
3. Feb 02 19:06:13, 131912 KB, DashboardsController#show
|
74
|
+
4. Feb 02 08:07:46, 115448 KB, GroupsController#show
|
75
|
+
5. Feb 02 12:19:53, 112924 KB, GroupsController#show
|
76
|
+
6. Feb 02 13:03:00, 112064 KB, ColorSchemesController#show
|
77
|
+
7. Feb 02 13:01:59, 109148 KB, SessionsController#create
|
78
|
+
8. Feb 02 06:11:17, 108456 KB, PublicPagesController#join
|
79
|
+
9. Feb 02 08:43:06, 94468 KB, CommentsController#create
|
80
|
+
10. Feb 02 20:49:44, 82340 KB, DashboardsController#show
|
81
|
+
|
82
|
+
Worst Actions:
|
83
|
+
10, DashboardsController#show
|
84
|
+
9, GroupsController#show
|
85
|
+
5, PublicPagesController#show
|
86
|
+
5, UsersController#show
|
87
|
+
3, MediaController#show
|
88
|
+
2, SportsController#show
|
89
|
+
1, SessionsController#create
|
90
|
+
1, GroupInvitesController#by_email
|
91
|
+
1, MediaController#index
|
92
|
+
1, PostsController#show
|
93
|
+
1, PhotoVotesController#create
|
94
|
+
1, AlbumsController#index
|
95
|
+
1, SignupsController#new
|
96
|
+
1, ColorSchemesController#show
|
97
|
+
1, PublicPagesController#join
|
98
|
+
1, CommentsController#create
|
99
|
+
|
100
|
+
e.g. In verbose mode, oink will print out all the log information from your logs about the actions which exceeded the threshold specified
|
101
|
+
|
102
|
+
$ oink --verbose --threshold=75 /tmp/logs/*
|
103
|
+
|
104
|
+
---------------------------------------------------------------------
|
105
|
+
Feb 08 11:39:52 ey33-s00302 rails[9076]: Processing UsersController#show (for 11.187.34.45 at 2009-02-08 11:39:52) [GET]
|
106
|
+
Feb 08 11:39:52 ey33-s00302 rails[9076]: Parameters: {"action"=>"show", "id"=>"45", "controller"=>"users"}
|
107
|
+
Feb 08 11:39:52 ey33-s00302 rails[9076]: Rendering template within layouts/application
|
108
|
+
Feb 08 11:39:52 ey33-s00302 rails[9076]: Rendering users/show
|
109
|
+
Feb 08 11:39:54 ey33-s00302 rails[9076]: Memory usage: 316516 | PID: 9076
|
110
|
+
Feb 08 11:39:54 ey33-s00302 rails[9076]: Completed in 2008ms (View: 1136, DB: 264) | 200 OK [http://www.example.com/users/45]
|
111
|
+
---------------------------------------------------------------------
|
112
|
+
|
113
|
+
Verbose format prints the summary as well as each action which exceeded the threshold.
|
114
|
+
|
115
|
+
=== Authors
|
116
|
+
|
117
|
+
- Maintained by Noah Davis
|
118
|
+
- Thanks to Weplay (http://weplay.com) for sponsoring development and supporting open sourcing it from the start
|
data/Rakefile
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require "rake/gempackagetask"
|
3
|
+
require "rake/clean"
|
4
|
+
require "spec/rake/spectask"
|
5
|
+
require './lib/oink/base.rb'
|
6
|
+
|
7
|
+
spec = Gem::Specification.new do |s|
|
8
|
+
s.name = "oink"
|
9
|
+
s.version = Oink::Base::VERSION
|
10
|
+
s.author = "Noah Davis"
|
11
|
+
s.email = "noahd1" + "@" + "yahoo.com"
|
12
|
+
s.homepage = "http://github.com/noahd1/oink"
|
13
|
+
s.summary = "Log parser to identify actions which significantly increase VM heap size"
|
14
|
+
s.description = s.summary
|
15
|
+
s.executables = "oink"
|
16
|
+
s.files = %w[History.txt MIT-LICENSE README.rdoc Rakefile] + Dir["bin/*"] + Dir["lib/**/*"]
|
17
|
+
end
|
18
|
+
|
19
|
+
Spec::Rake::SpecTask.new do |t|
|
20
|
+
t.spec_opts == ["--color"]
|
21
|
+
end
|
22
|
+
|
23
|
+
Rake::GemPackageTask.new(spec) do |package|
|
24
|
+
package.gem_spec = spec
|
25
|
+
end
|
26
|
+
|
27
|
+
desc "Run the specs"
|
28
|
+
task :default => ["spec"]
|
29
|
+
|
30
|
+
desc 'Show information about the gem.'
|
31
|
+
task :write_gemspec do
|
32
|
+
File.open("oink.gemspec", 'w') do |f|
|
33
|
+
f.write spec.to_ruby
|
34
|
+
end
|
35
|
+
puts "Generated: oink.gemspec"
|
36
|
+
end
|
37
|
+
|
38
|
+
CLEAN.include ["pkg", "*.gem", "doc", "ri", "coverage"]
|
39
|
+
|
40
|
+
desc 'Install the package as a gem.'
|
41
|
+
task :install_gem => [:clean, :package] do
|
42
|
+
gem = Dir['pkg/*.gem'].first
|
43
|
+
sh "sudo gem install --local #{gem}"
|
44
|
+
end
|
data/bin/oink
ADDED
data/lib/oink.rb
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
require "date"
|
2
|
+
require "oink/base"
|
3
|
+
require "oink/oinked_request/oinked_ar_request"
|
4
|
+
require "oink/priority_queue"
|
5
|
+
|
6
|
+
module Oink
|
7
|
+
|
8
|
+
class ActiveRecordInstantiationReporter < Base
|
9
|
+
|
10
|
+
def print(output)
|
11
|
+
output.puts "---- OINK FOR ACTIVERECORD ----"
|
12
|
+
output.puts "THRESHOLD: #{@threshold} Active Record objects per request\n"
|
13
|
+
|
14
|
+
output.puts "\n-- REQUESTS --\n" if @format == :verbose
|
15
|
+
|
16
|
+
@inputs.each do |input|
|
17
|
+
input.each_line do |line|
|
18
|
+
line = line.strip
|
19
|
+
|
20
|
+
if line =~ /rails\[(\d+)\]/
|
21
|
+
pid = $1
|
22
|
+
@pids[pid] ||= { :buffer => [], :ar_count => -1, :action => "", :request_finished => true }
|
23
|
+
@pids[pid][:buffer] << line
|
24
|
+
end
|
25
|
+
|
26
|
+
if line =~ /Processing ((\w+)#(\w+)) /
|
27
|
+
|
28
|
+
@pids[pid][:action] = $1
|
29
|
+
unless @pids[pid][:request_finished]
|
30
|
+
@pids[pid][:buffer] = [line]
|
31
|
+
end
|
32
|
+
@pids[pid][:request_finished] = false
|
33
|
+
|
34
|
+
elsif line =~ /Instantiation Breakdown: Total: (\d+)/
|
35
|
+
|
36
|
+
@pids[pid][:ar_count] = $1.to_i
|
37
|
+
|
38
|
+
elsif line =~ /Completed in/
|
39
|
+
|
40
|
+
if @pids[pid][:ar_count] > @threshold
|
41
|
+
@bad_actions[@pids[pid][:action]] ||= 0
|
42
|
+
@bad_actions[@pids[pid][:action]] = @bad_actions[@pids[pid][:action]] + 1
|
43
|
+
date = /^(\w+ \d{2} \d{2}:\d{2}:\d{2})/.match(line).captures[0]
|
44
|
+
@bad_requests.push(OinkedARRequest.new(@pids[pid][:action], date, @pids[pid][:buffer], @pids[pid][:ar_count]))
|
45
|
+
if @format == :verbose
|
46
|
+
@pids[pid][:buffer].each { |b| output.puts b }
|
47
|
+
output.puts "---------------------------------------------------------------------"
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
@pids[pid][:request_finished] = true
|
52
|
+
@pids[pid][:buffer] = []
|
53
|
+
@pids[pid][:ar_count] = -1
|
54
|
+
|
55
|
+
end # end elsif
|
56
|
+
end # end each_line
|
57
|
+
end # end each input
|
58
|
+
|
59
|
+
print_summary(output)
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
data/lib/oink/base.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
module Oink
|
2
|
+
|
3
|
+
class Base
|
4
|
+
|
5
|
+
VERSION = '0.1.0'
|
6
|
+
FORMATS = %w[verbose short-summary summary]
|
7
|
+
FORMAT_ALIASES = { "v" => "verbose", "ss" => "short-summary", "s" => "summary" }
|
8
|
+
|
9
|
+
def initialize(input, threshold, options = {})
|
10
|
+
@inputs = Array(input)
|
11
|
+
@threshold = threshold
|
12
|
+
@format = options[:format] || :short_summary
|
13
|
+
|
14
|
+
@pids = {}
|
15
|
+
@bad_actions = {}
|
16
|
+
@bad_requests = PriorityQueue.new(10)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
def print_summary(output)
|
22
|
+
output.puts "\n-- SUMMARY --\n"
|
23
|
+
output.puts "Worst Requests:"
|
24
|
+
@bad_requests.each_with_index do |offender, index|
|
25
|
+
output.puts "#{index + 1}. #{offender.datetime}, #{offender.display_oink_number}, #{offender.action}"
|
26
|
+
if @format == :summary
|
27
|
+
offender.log_lines.each { |b| output.puts b }
|
28
|
+
output.puts "---------------------------------------------------------------------"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
output.puts "\nWorst Actions:"
|
32
|
+
@bad_actions.sort{|a,b| b[1]<=>a[1]}.each { |elem|
|
33
|
+
output.puts "#{elem[1]}, #{elem[0]}"
|
34
|
+
}
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
|
39
|
+
end
|
data/lib/oink/cli.rb
ADDED
@@ -0,0 +1,97 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
class Cli
|
4
|
+
|
5
|
+
def initialize(args)
|
6
|
+
@args = args
|
7
|
+
end
|
8
|
+
|
9
|
+
def process
|
10
|
+
options = { :format => :short_summary, :type => :memory }
|
11
|
+
|
12
|
+
op = OptionParser.new do |opts|
|
13
|
+
opts.banner = "Usage: oink [options] files"
|
14
|
+
|
15
|
+
opts.on("-t", "--threshold [INTEGER]", Integer,
|
16
|
+
"Memory threshold in MB") do |threshold|
|
17
|
+
options[:threshold] = threshold
|
18
|
+
end
|
19
|
+
|
20
|
+
opts.on("-f", "--file filepath", "Output to file") do |filename|
|
21
|
+
options[:output_file] = filename
|
22
|
+
end
|
23
|
+
|
24
|
+
format_list = (Oink::MemoryUsageReporter::FORMAT_ALIASES.keys + Oink::MemoryUsageReporter::FORMATS).join(',')
|
25
|
+
opts.on("--format FORMAT", Oink::MemoryUsageReporter::FORMATS, Oink::MemoryUsageReporter::FORMAT_ALIASES, "Select format",
|
26
|
+
" (#{format_list})") do |format|
|
27
|
+
options[:format] = format.to_sym
|
28
|
+
end
|
29
|
+
|
30
|
+
opts.on("-m", "--memory", "Check for Memory Threshold (default)") do |v|
|
31
|
+
options[:type] = :memory
|
32
|
+
end
|
33
|
+
|
34
|
+
opts.on("-r", "--active-record", "Check for Active Record Threshold") do |v|
|
35
|
+
options[:type] = :active_record
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
op.parse!(@args)
|
41
|
+
|
42
|
+
if @args.empty?
|
43
|
+
puts op
|
44
|
+
exit
|
45
|
+
end
|
46
|
+
|
47
|
+
output = nil
|
48
|
+
|
49
|
+
if options[:output_file]
|
50
|
+
output = File.open(options[:output_file], 'w')
|
51
|
+
else
|
52
|
+
output = STDOUT
|
53
|
+
end
|
54
|
+
|
55
|
+
files = get_file_listing(@args)
|
56
|
+
|
57
|
+
handles = files.map { |f| File.open(f) }
|
58
|
+
|
59
|
+
if options[:type] == :memory
|
60
|
+
|
61
|
+
options[:threshold] ||= 75
|
62
|
+
options[:threshold] *= 1024
|
63
|
+
|
64
|
+
Oink::MemoryUsageReporter.new(handles, options[:threshold], :format => options[:format]).print(output)
|
65
|
+
|
66
|
+
elsif options[:type] == :active_record
|
67
|
+
|
68
|
+
options[:threshold] ||= 500
|
69
|
+
|
70
|
+
Oink::ActiveRecordInstantiationReporter.new(handles, options[:threshold], :format => options[:format]).print(output)
|
71
|
+
|
72
|
+
end
|
73
|
+
|
74
|
+
output.close
|
75
|
+
handles.each { |h| h.close }
|
76
|
+
end
|
77
|
+
|
78
|
+
protected
|
79
|
+
|
80
|
+
def get_file_listing(args)
|
81
|
+
listing = []
|
82
|
+
args.each do |file|
|
83
|
+
unless File.exist?(file)
|
84
|
+
raise "Could not find \"#{file}\""
|
85
|
+
end
|
86
|
+
if File.directory?(file)
|
87
|
+
listing += Dir.glob("#{file}/**")
|
88
|
+
else
|
89
|
+
listing << file
|
90
|
+
end
|
91
|
+
end
|
92
|
+
listing
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
96
|
+
|
97
|
+
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require "date"
|
2
|
+
require "oink/base"
|
3
|
+
require "oink/oinked_request/oinked_memory_request"
|
4
|
+
require "oink/priority_queue"
|
5
|
+
|
6
|
+
module Oink
|
7
|
+
|
8
|
+
class MemoryUsageReporter < Base
|
9
|
+
|
10
|
+
def print(output)
|
11
|
+
output.puts "---- MEMORY THRESHOLD ----"
|
12
|
+
output.puts "THRESHOLD: #{@threshold/1024} MB\n"
|
13
|
+
|
14
|
+
output.puts "\n-- REQUESTS --\n" if @format == :verbose
|
15
|
+
|
16
|
+
@inputs.each do |input|
|
17
|
+
input.each_line do |line|
|
18
|
+
line = line.strip
|
19
|
+
|
20
|
+
if line =~ /rails\[(\d+)\]/
|
21
|
+
pid = $1
|
22
|
+
@pids[pid] ||= { :buffer => [], :last_memory_reading => -1, :current_memory_reading => -1, :action => "", :request_finished => true }
|
23
|
+
@pids[pid][:buffer] << line
|
24
|
+
end
|
25
|
+
|
26
|
+
if line =~ /Processing ((\w+)#(\w+)) /
|
27
|
+
|
28
|
+
unless @pids[pid][:request_finished]
|
29
|
+
@pids[pid][:last_memory_reading] = -1
|
30
|
+
end
|
31
|
+
@pids[pid][:action] = $1
|
32
|
+
@pids[pid][:request_finished] = false
|
33
|
+
|
34
|
+
elsif line =~ /Memory usage: (\d+) /
|
35
|
+
|
36
|
+
memory_reading = $1.to_i
|
37
|
+
@pids[pid][:current_memory_reading] = memory_reading
|
38
|
+
|
39
|
+
elsif line =~ /Completed in/
|
40
|
+
|
41
|
+
@pids[pid][:request_finished] = true
|
42
|
+
unless @pids[pid][:current_memory_reading] == -1 || @pids[pid][:last_memory_reading] == -1
|
43
|
+
memory_diff = @pids[pid][:current_memory_reading] - @pids[pid][:last_memory_reading]
|
44
|
+
if memory_diff > @threshold
|
45
|
+
@bad_actions[@pids[pid][:action]] ||= 0
|
46
|
+
@bad_actions[@pids[pid][:action]] = @bad_actions[@pids[pid][:action]] + 1
|
47
|
+
date = /^(\w+ \d{2} \d{2}:\d{2}:\d{2})/.match(line).captures[0]
|
48
|
+
@bad_requests.push(OinkedMemoryRequest.new(@pids[pid][:action], date, @pids[pid][:buffer], memory_diff))
|
49
|
+
if @format == :verbose
|
50
|
+
@pids[pid][:buffer].each { |b| output.puts b }
|
51
|
+
output.puts "---------------------------------------------------------------------"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
@pids[pid][:buffer] = []
|
57
|
+
@pids[pid][:last_memory_reading] = @pids[pid][:current_memory_reading]
|
58
|
+
@pids[pid][:current_memory_reading] = -1
|
59
|
+
|
60
|
+
end # end elsif
|
61
|
+
end # end each_line
|
62
|
+
end # end each input
|
63
|
+
|
64
|
+
print_summary(output)
|
65
|
+
|
66
|
+
end
|
67
|
+
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
class OinkedRequest
|
2
|
+
|
3
|
+
attr_accessor :action, :datetime, :log_lines, :oink_number
|
4
|
+
|
5
|
+
def initialize(action, datetime, log_lines, oink_number)
|
6
|
+
@action = action
|
7
|
+
@datetime = datetime
|
8
|
+
@log_lines = log_lines
|
9
|
+
@oink_number = oink_number
|
10
|
+
end
|
11
|
+
|
12
|
+
def <=>(other)
|
13
|
+
self.oink_number <=> other.oink_number
|
14
|
+
end
|
15
|
+
|
16
|
+
def >(other)
|
17
|
+
self.oink_number > other.oink_number
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
class PriorityQueue
|
2
|
+
|
3
|
+
include Enumerable
|
4
|
+
|
5
|
+
def initialize(size)
|
6
|
+
@size = size
|
7
|
+
@queue = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def push(item)
|
11
|
+
if @queue.size < @size
|
12
|
+
@queue << item
|
13
|
+
elsif item > @queue.last
|
14
|
+
@queue[@size - 1] = item
|
15
|
+
end
|
16
|
+
prioritize
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_a
|
20
|
+
@queue
|
21
|
+
end
|
22
|
+
|
23
|
+
def size
|
24
|
+
@queue.size
|
25
|
+
end
|
26
|
+
|
27
|
+
def each
|
28
|
+
@queue.each { |i| yield i }
|
29
|
+
end
|
30
|
+
|
31
|
+
protected
|
32
|
+
|
33
|
+
def prioritize
|
34
|
+
@queue.sort! { |a, b| b <=> a }
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Oink
|
2
|
+
|
3
|
+
def self.extended_active_record?
|
4
|
+
@oink_extended_active_record
|
5
|
+
end
|
6
|
+
|
7
|
+
def self.extended_active_record!
|
8
|
+
@oink_extended_active_record = true
|
9
|
+
end
|
10
|
+
|
11
|
+
module InstanceTypeCounter
|
12
|
+
def self.included(klass)
|
13
|
+
ActiveRecord::Base.send(:include, OinkInstanceTypeCounterInstanceMethods)
|
14
|
+
|
15
|
+
klass.class_eval do
|
16
|
+
after_filter :report_instance_type_count
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def before_report_active_record_count(instantiation_data)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def report_instance_type_count
|
26
|
+
report_hash = ActiveRecord::Base.instantiated_hash.merge("Total" => ActiveRecord::Base.total_objects_instantiated)
|
27
|
+
breakdown = report_hash.sort{|a,b| b[1]<=>a[1]}.collect {|k,v| "#{k}: #{v}" }.join(" | ")
|
28
|
+
before_report_active_record_count(breakdown)
|
29
|
+
if logger
|
30
|
+
logger.info("Instantiation Breakdown: #{breakdown}")
|
31
|
+
end
|
32
|
+
ActiveRecord::Base.reset_instance_type_count
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
36
|
+
|
37
|
+
module OinkInstanceTypeCounterInstanceMethods
|
38
|
+
|
39
|
+
def self.included(klass)
|
40
|
+
klass.class_eval do
|
41
|
+
|
42
|
+
@@instantiated = {}
|
43
|
+
@@total = nil
|
44
|
+
|
45
|
+
def self.reset_instance_type_count
|
46
|
+
@@instantiated = {}
|
47
|
+
@@total = nil
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.instantiated_hash
|
51
|
+
@@instantiated
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.total_objects_instantiated
|
55
|
+
@@total ||= @@instantiated.inject(0) { |i, j| i + j.last }
|
56
|
+
end
|
57
|
+
|
58
|
+
unless Oink.extended_active_record?
|
59
|
+
if instance_methods.include?("after_initialize")
|
60
|
+
def after_initialize_with_oink
|
61
|
+
after_initialize_without_oink
|
62
|
+
increment_ar_count
|
63
|
+
end
|
64
|
+
|
65
|
+
alias_method_chain :after_initialize, :oink
|
66
|
+
else
|
67
|
+
def after_initialize
|
68
|
+
increment_ar_count
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
Oink.extended_active_record!
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def increment_ar_count
|
79
|
+
@@instantiated[self.class.base_class.name] ||= 0
|
80
|
+
@@instantiated[self.class.base_class.name] = @@instantiated[self.class.base_class.name] + 1
|
81
|
+
end
|
82
|
+
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
module Oink
|
2
|
+
module MemoryUsageLogger
|
3
|
+
def self.included(klass)
|
4
|
+
klass.class_eval do
|
5
|
+
after_filter :log_memory_usage
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
private
|
10
|
+
def log_memory_usage
|
11
|
+
if logger
|
12
|
+
memory_usage = `ps -o rss= -p #{$$}`.to_i
|
13
|
+
logger.info("Memory usage: #{memory_usage} | PID: #{$$}")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
metadata
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: aiwilliams-oink
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Noah Davis
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2009-05-22 00:00:00 -07:00
|
13
|
+
default_executable: oink
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description: Log parser to identify actions which significantly increase VM heap size
|
17
|
+
email: noahd1@yahoo.com
|
18
|
+
executables:
|
19
|
+
- oink
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- History.txt
|
26
|
+
- MIT-LICENSE
|
27
|
+
- README.rdoc
|
28
|
+
- Rakefile
|
29
|
+
- bin/oink
|
30
|
+
- lib/oink
|
31
|
+
- lib/oink/active_record_instantiation_reporter.rb
|
32
|
+
- lib/oink/base.rb
|
33
|
+
- lib/oink/cli.rb
|
34
|
+
- lib/oink/memory_usage_reporter.rb
|
35
|
+
- lib/oink/oinked_request
|
36
|
+
- lib/oink/oinked_request/oinked_ar_request.rb
|
37
|
+
- lib/oink/oinked_request/oinked_memory_request.rb
|
38
|
+
- lib/oink/oinked_request/oinked_request.rb
|
39
|
+
- lib/oink/priority_queue.rb
|
40
|
+
- lib/oink/rails
|
41
|
+
- lib/oink/rails/instance_type_counter.rb
|
42
|
+
- lib/oink/rails/memory_usage_logger.rb
|
43
|
+
- lib/oink.rb
|
44
|
+
has_rdoc: false
|
45
|
+
homepage: http://github.com/noahd1/oink
|
46
|
+
post_install_message:
|
47
|
+
rdoc_options: []
|
48
|
+
|
49
|
+
require_paths:
|
50
|
+
- lib
|
51
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
52
|
+
requirements:
|
53
|
+
- - ">="
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: "0"
|
56
|
+
version:
|
57
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: "0"
|
62
|
+
version:
|
63
|
+
requirements: []
|
64
|
+
|
65
|
+
rubyforge_project:
|
66
|
+
rubygems_version: 1.2.0
|
67
|
+
signing_key:
|
68
|
+
specification_version: 2
|
69
|
+
summary: Log parser to identify actions which significantly increase VM heap size
|
70
|
+
test_files: []
|
71
|
+
|