Module | RubyRunCommander__ |
In: |
lib/rubyrun/rubyrun_commander__.rb
|
Show the top 20 Ruby classes which have the largest no. of instances in memory The snapshot is taken after a gc call is made
# File lib/rubyrun/rubyrun_commander__.rb, line 103 103: def dump_object_map 104: start_time = Time.now 105: $rubyrun_obj_map_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_object_map.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_obj_map_reporter 106: object_map = Hash.new 107: ttl_object = 0 108: ObjectSpace.garbage_collect 109: ObjectSpace.each_object { |obj| 110: ttl_object += 1 111: object_map.has_key?(obj.class) ? object_map[obj.class] += 1 : object_map[obj.class] = 1 112: } 113: results = object_map.sort{|a,b| a[1]<=>b[1]}.reverse! 114: table_content = '' 115: odd_row ||=true 116: 20.times {|i| 117: table_content += sprintf("#{odd_row ? OBJ_MAP_ODD_ROW : OBJ_MAP_EVEN_ROW}", 118: results[i][0], results[i][1].to_s) 119: odd_row = !odd_row 120: } 121: html_content = OBJ_MAP_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y")) 122: html_content.sub!(/%OBJ_MAP_ROW%/,table_content) 123: $rubyrun_obj_map_reporter.info(html_content) 124: end
Dump Controller/Actions response time metrics metrics structure metrics[0] Thread ID metrics[1] Timestamp of the request metrics[2] URL metrics[3] Controller name metrics[4] Action name metrics[5] Response time metrics[6] Action time metrics[7] Database IO time metrics[8] View time metrics[9] Uncaptured time metrics[10] Dispatch wait time
# File lib/rubyrun/rubyrun_commander__.rb, line 46 46: def dump_reports(dump_all_reports = false) 47: buffer = return_and_switch_buffer 48: buffer.each { |metrics| 49: # Last element is 1, representing a request count of 1, used for calculating average response time for this controller/action 50: update_perf_metrics(metrics[3], {metrics[4] => [metrics[5],metrics[6],metrics[7],metrics[8],metrics[9],metrics[10],1]}) 51: } 52: @rubyrun_req_count ||= 0 53: @rubyrun_req_count += buffer.length 54: if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_PERF_SUMMARY) && dump_all_reports 55: create_rss_channels if (!$rubyrun_perf_summary_rss && $rubyrun_rails_env) 56: add_perf_summary_rss_item(@rubyrun_req_count) 57: @rubyrun_req_count = 0 58: end 59: if $rubyrun_config['OUTPUT'].include?(RUBYRUN_OUTPUT_TXN_LOG) 60: create_csv_files unless $rubyrun_txn_log_reporter 61: add_txn_log_csv_item(buffer) 62: end 63: buffer.clear # Clear the buffer so that the main thread will push the data into a blank bucket 64: end
Use Thread.list to list show thread status, and native code to display the last line # and function of the threads
# File lib/rubyrun/rubyrun_commander__.rb, line 20 20: def dump_thread_status 21: (unsupport_function; return) unless $rubyrun_native 22: $rubyrun_thread_status_reporter = RubyRunHTMLWriter.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_status.html', nil, shift_age = 10, shift_size = 4096000) unless $rubyrun_thread_status_reporter 23: start_time = Time.now 24: th_data_hash = RubyRunNative__.get_all_top_stacks 25: odd_row ||= true 26: table_content = '' 27: Thread.list.each {|th| 28: thread_id = get_thread_id(th) 29: table_content += sprintf("#{odd_row ? THREAD_STATUS_ODD_ROW : THREAD_STATUS_EVEN_ROW}", 30: thread_id, th.status, get_top_stack(th_data_hash, thread_id)) 31: odd_row = !odd_row 32: } 33: html_content = THREAD_STATUS_HTML.sub(/%START_TIMESTAMP%/,start_time.strftime("%H:%M:%S %m/%d/%Y")) 34: html_content.sub!(/%THREAD_STATUS_ROW%/,table_content) 35: $rubyrun_thread_status_reporter.info(html_content) 36: end
If exists, indicate to the monitor thread to exit
# File lib/rubyrun/rubyrun_commander__.rb, line 187 187: def exit_monitor? 188: File.exists?(ENV[RUBYRUN_WORKING_DIR] + RUBYRUN_CMD_EXIT) 189: end
If exists, indicate to the monitor thread that a hard kill (kill all threads including the main thread) command is sent
# File lib/rubyrun/rubyrun_commander__.rb, line 177 177: def hard_kill? 178: File.exists?(ENV[RUBYRUN_WORKING_DIR] + RUBYRUN_CMD_HARD_KILL + '_' + Process.pid.to_s) 179: end
The way to do soft/hard kill is to performa a thr.raise on the thread from the thread monitor. Using the begin/rescue created around the block in Thread.new by RubyRunInstrumentor__, the raise will be rescued and $@ is then extracted to a global hash. Softkill only kills non-main threads. Hardkill kills the main thread also but as the last step.
# File lib/rubyrun/rubyrun_commander__.rb, line 72 72: def kill_threads(monitor_thr) 73: (unsupport_function; return) unless $rubyrun_native 74: if !$rubyrun_thread_dump_reporter 75: $rubyrun_thread_dump_reporter = Logger.new(@rubyrun_report_folder + '/' + File.basename($0, ".*") + '_' + $$.to_s + '_thread_dump.txt', shift_age = 10, shift_size = 4096000) 76: $rubyrun_thread_dump_reporter.level = Logger::INFO 77: class << $rubyrun_thread_dump_reporter 78: include RubyRunUtils__ 79: def format_message (severity, timestamp, progname, msg) 80: "[#{timestamp.strftime("%Y-%m-%d %H:%M:%S")}.#{("%.3f" % timestamp.to_f).split('.')[1]}] #{get_thread_id} #{msg}\n" 81: end 82: end 83: end 84: th_data_hash = RubyRunNative__.get_all_top_stacks 85: j_th_id = return_joined_thread(th_data_hash) 86: Thread.list.each {|th| 87: th_id = get_thread_id(th) 88: if th.status == 'sleep' && th_id != get_thread_id && th_id != get_thread_id(monitor_thr) && 89: th_id != get_thread_id(Thread.main) && th_id != j_th_id 90: $rubyrun_thread_dump_reporter.info "*** Raising exception #{RUBYRUN_KILL_3_STRING} to #{get_thread_id(th)} ***" 91: th.raise ThreadError, RUBYRUN_KILL_3_STRING 92: end 93: } 94: sleep 3 95: back_trace_all(th_data_hash) 96: hard_kill = hard_kill? 97: remove_cmd_folder 98: Thread.main.raise ThreadError, RUBYRUN_KILL_3_STRING if hard_kill 99: end
If exists, indicate to the montior thread that a object map is requested
# File lib/rubyrun/rubyrun_commander__.rb, line 182 182: def object_map? 183: File.exists?(ENV[RUBYRUN_WORKING_DIR] + RUBYRUN_CMD_OBJECT_MAP) 184: end
Remove the cmd_kill-3 folder or file if any
# File lib/rubyrun/rubyrun_commander__.rb, line 155 155: def remove_cmd_folder 156: [RUBYRUN_CMD_SOFT_KILL, RUBYRUN_CMD_HARD_KILL].each { |cmd| 157: path = ENV[RUBYRUN_WORKING_DIR] + cmd + '_' + Process.pid.to_s 158: next unless File.exist?(path) 159: File.directory?(path) ? Dir.delete(path) : File.delete(path) 160: } 161: end
If a thread is joined this method returns the joining thread ID
# File lib/rubyrun/rubyrun_commander__.rb, line 145 145: def return_joined_thread(th_data_hash) 146: th_data_hash.each {|th, top_stack| 147: if th.to_s.include?(get_thread_id(Thread.main)) 148: top_stack[0] =~ /\*\*(.+?)\*\*/ 149: return $1 150: end 151: } 152: end
If exists, indicate to the monitor thread that a soft kill (kill all threads except the main thread) command is sent
# File lib/rubyrun/rubyrun_commander__.rb, line 171 171: def soft_kill? 172: File.exists?(ENV[RUBYRUN_WORKING_DIR] + RUBYRUN_CMD_SOFT_KILL + '_' + Process.pid.to_s) 173: end
If exists, indicate to the monitor thread that a thread status report is requested
# File lib/rubyrun/rubyrun_commander__.rb, line 165 165: def thread_status? 166: File.exists?(ENV[RUBYRUN_WORKING_DIR] + RUBYRUN_CMD_STATUS) 167: end
Log if native library can‘t be loaded or not found
# File lib/rubyrun/rubyrun_commander__.rb, line 192 192: def unsupport_function 193: $rubyrun_logger.info "Native library not available. Function not supported." 194: end
metrics hash is a global collection point for all metrics (averaged) for all actions by controller Use serialization before updating this global hash Structure of $rubyrun_metrics_hash: controller_name => {action_name => [response_time, action_time,
db_io_time, view_time, uncaptured_time, dispatch_wait_time, request_count]}
# File lib/rubyrun/rubyrun_commander__.rb, line 134 134: def update_perf_metrics(controller, action_metrics_hash) 135: $rubyrun_metrics_hash[controller].merge!(action_metrics_hash) {|action, o_metrics, new_metrics| 136: o_metrics.each_index { |x| 137: (o_metrics[x] += new_metrics[x]; break) if x == (o_metrics.length-1) # Calculate the total request count for this controller/action 138: o_metrics[x] = (o_metrics[x] * o_metrics.last + new_metrics[x])/(o_metrics.last + new_metrics.last).to_f 139: } 140: o_metrics 141: } 142: end