require 'optparse' require 'json' require 'tempfile' require 'tmpdir' module PerfMonger module Command class PlotCommand < BaseCommand register_command 'plot', "Plot system performance graphs collected by 'record'" def initialize @parser = OptionParser.new @parser.banner = </dev/null 2>&1') puts("ERROR: convert(1) not found.") puts("ERROR: ImageMagick is required for #{typ}") puts(@parser.help) exit(false) end @output_type = typ end @parser.on('-p', '--prefix PREFIX', 'Output file name prefix.') do |prefix| if ! (prefix =~ /-\Z/) prefix += '-' end @output_prefix = prefix end @parser.on('-s', '--save', 'Save GNUPLOT and data files.') do @save_gpfiles = true end @parser.parse!(argv) if argv.size == 0 puts("ERROR: PerfMonger log file is required") puts(@parser.help) exit(false) end @data_file = File.expand_path(argv.shift) end def run(argv) parse_args(argv) unless system('which gnuplot >/dev/null 2>&1') puts("ERROR: gnuplot not found") puts(@parser.help) exit(false) end unless system('gnuplot -e "set terminal"|grep pdfcairo >/dev/null 2>&1') puts("ERROR: pdfcairo is not supported by installed gnuplot") puts("ERROR: PerfMonger requires pdfcairo-supported gnuplot") puts(@parser.help) exit(false) end plot_ioinfo() plot_cpuinfo() end private def plot_ioinfo() iops_pdf_filename = @output_prefix + 'iops.pdf' transfer_pdf_filename = @output_prefix + 'transfer.pdf' gp_filename = @output_prefix + 'io.gp' dat_filename = @output_prefix + 'io.dat' if @output_type != 'pdf' iops_img_filename = @output_prefix + 'iops.' + @output_type transfer_img_filename = @output_prefix + 'transfer.' + @output_type else iops_img_filename = nil transfer_img_filename = nil end Dir.mktmpdir do |working_dir| Dir.chdir(working_dir) do datafile = File.open(dat_filename, 'w') gpfile = File.new(gp_filename, 'w') start_time = nil devices = nil File.open(@data_file).each_line do |line| record = JSON.parse(line) time = record["time"] ioinfo = record["ioinfo"] return unless ioinfo start_time ||= time devices ||= ioinfo["devices"] datafile.puts([time - start_time, devices.map{|device| [ioinfo[device]["riops"], ioinfo[device]["wiops"], ioinfo[device]["rsecps"] * 512 / 1024 / 1024, # in MB/s ioinfo[device]["wsecps"] * 512 / 1024 / 1024, # in MB/s ] }].flatten.map(&:to_s).join("\t")) end datafile.close col_idx = 2 iops_plot_stmt_list = devices.map do |device| plot_stmt = [] plot_stmt.push("\"#{dat_filename}\" usi 1:#{col_idx} with lines lw 2 title \"#{device} read\"") plot_stmt.push("\"#{dat_filename}\" usi 1:#{col_idx + 1} with lines lw 2 title \"#{device} write\"") col_idx += 4 plot_stmt end.flatten col_idx = 4 transfer_plot_stmt_list = devices.map do |device| plot_stmt = [] plot_stmt.push("\"#{dat_filename}\" usi 1:#{col_idx} with lines lw 2 title \"#{device} read\"") plot_stmt.push("\"#{dat_filename}\" usi 1:#{col_idx + 1} with lines lw 2 title \"#{device} write\"") col_idx += 4 plot_stmt end.flatten gpfile.puts <