diff options
author | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2006-12-27 00:00:17 +0000 |
---|---|---|
committer | Giuseppe Bilotta <giuseppe.bilotta@gmail.com> | 2006-12-27 00:00:17 +0000 |
commit | c6af7de45f49f74d4ff6f85eb61b27f7b7275335 (patch) | |
tree | 2e2d1c80a08405c042e1b3ff6c42979724901b38 | |
parent | 5723c5ba7b10392e959f3eeda8c3e21ce6fec5e0 (diff) |
Debugger plugin, which can be used to profile memory usage in rbot and detect memory leaks
-rw-r--r-- | data/rbot/plugins/debugger.rb | 132 |
1 files changed, 132 insertions, 0 deletions
diff --git a/data/rbot/plugins/debugger.rb b/data/rbot/plugins/debugger.rb new file mode 100644 index 00000000..f0ff0c03 --- /dev/null +++ b/data/rbot/plugins/debugger.rb @@ -0,0 +1,132 @@ +# Debugging/profiling for rbot +# +# (c) 2006 Giuseppe Bilotta <giuseppe.bilotta@gmail.com> +# Licensed under GPL V2. + +class DebugPlugin < Plugin + BotConfig.register BotConfigIntegerValue.new('debug.interval', + :default => 10, :validate => Proc.new{|v| v > 0}, + :desc => "Number of seconds between memory profile dumps") + BotConfig.register BotConfigBooleanValue.new('debug.dump_strings', + :default => false, + :desc => "Set to true if you want the profiler to dump strings, false otherwise") + BotConfig.register BotConfigStringValue.new('debug.logdir', + :default => "", + :desc => "Directory where profile/string dumps are to be stored") + + def initialize + super + @prev = Hash.new(0) + @curr = Hash.new(0) + @delta = Hash.new(0) + @file = File.open("#{@bot.botclass}/#{@bot.config['debug.logdir']}/memory_profiler.log",'w') + @thread = @bot.timer.add(@bot.config['debug.interval']) { + begin + GC.start + @curr.clear + + curr_strings = [] + + ObjectSpace.each_object do |o| + @curr[o.class] += 1 #Marshal.dump(o).size rescue 1 + if @bot.config['debug.dump_strings'] and o.class == String + curr_strings.push o + end + end + + if @bot.config['debug.dump_strings'] + File.open("#{@bot.botclass}/#{@bot.config['debug.logdir']}/memory_profiler_strings.log.#{Time.now.to_i}",'w') do |f| + curr_strings.sort.each do |s| + f.puts s + end + end + curr_strings.clear + end + + @delta.clear + (@curr.keys + @delta.keys).uniq.each do |k,v| + @delta[k] = @curr[k]-@prev[k] + end + + @file.puts "Top 20" + @delta.sort_by { |k,v| -v.abs }[0..19].sort_by { |k,v| -v}.each do |k,v| + @file.printf "%+5d: %s (%d)\n", v, k.name, @curr[k] unless v == 0 + end + @file.flush + + @delta.clear + @prev.clear + @prev.update @curr + GC.start + rescue Exception => err + error "** memory_profiler error: #{err}" + end + } + @bot.timer.block(@thread) + end + + def help( plugin, topic="" ) + "debug start => start the periodic profiler; " + \ + "debug stop => stops the periodic profiler; " + \ + "debug dumpstrings => dump all of the strings" + end + + def start_it(m, params) + begin + @bot.timer.unblock(@thread) + m.reply "profile dump started" + rescue Exception => err + m.reply "couldn't start profile dump" + error "couldn't start profile dump: #{err}" + end + end + + def stop_it(m, params) + begin + @bot.timer.block(@thread) + m.reply "profile dump stop" + rescue Exception => err + m.reply "couldn't stop profile dump" + error "couldn't stop profile dump: #{err}" + end + end + + def dump_strings(m, params) + curr_strings = [] + + m.reply "Dumping strings ..." + begin + GC.start + ObjectSpace.each_object do |o| + if o.class == String + curr_strings.push o + end + end + + File.open("#{@bot.botclass}/#{@bot.config['debug.logdir']}/memory_profiler_strings.log.#{Time.now.to_i}",'w') do |f| + curr_strings.sort.each do |s| + f.puts s + end + end + GC.start + m.reply "... done" + rescue Exception => err + m.reply "dumping strings failed" + error "dumping strings failed: #{err}" + end + end + +end + + +plugin = DebugPlugin.new +plugin.register( "debug" ) +plugin.default_auth( 'start', false ) +plugin.default_auth( 'stop', false ) +plugin.default_auth( 'dumpstrings', false ) + +plugin.map 'debug start', :action => 'start_it' +plugin.map 'debug stop', :action => 'stop_it' +plugin.map 'debug dumpstrings', :action => 'dump_strings' + + |