require 'fileutils' require 'date' require 'nera_db_folders' require 'nera_simulator' module NERA # This class create & parse job scripts class JobScript # NERA::DbFolders object @db_folder #-------------------------------------- #-class methods ----------------------- #-------------------------------------- # db_folder is the instance of DbFolders def initialize( db_folder) unless db_folder.instance_of?(NERA::DbFolders) then raise ArgumentError, "Argument must be an instance of NERA::DbFolders." end @db_folder = db_folder end # job script def job_script_body(job_info) ############## job_script ################### job_script =<<"BODY" #!/bin/bash LANG=C mkdir -p #{job_info[:job_script_id]} cd #{job_info[:job_script_id]} echo \"#---------- header of #{job_info[:job_id]} ----------\" > nera_status.rb echo \"header = {\" >> nera_status.rb echo \" :database => '#{job_info[:database]}',\" >> nera_status.rb echo \" :job_id => #{job_info[:job_id]},\" >> nera_status.rb echo \" :simulator => '#{job_info[:simulator]}',\" >> nera_status.rb echo \" :simulator_id => #{job_info[:sim_id]},\" >> nera_status.rb echo \" :param_id => #{job_info[:param_id]},\" >> nera_status.rb echo \" :run_ids => #{job_info[:run_ids].inspect},\" >> nera_status.rb echo \" :parameters => {\" >> nera_status.rb BODY job_info[:params].each_pair do |key, value| job_script += "echo \" #{key.to_sym.inspect} => #{value.inspect.gsub(/\"/,'\"')},\" >> nera_status.rb\n" end job_script +=<<"BODY" echo \" },\" >> nera_status.rb echo \" :start_at => DateTime.parse( <<'NERA_DATE'.chomp )\" >> nera_status.rb date >> nera_status.rb echo \"NERA_DATE\" >> nera_status.rb echo \"}\" >> nera_status.rb echo \"body = {\" >> nera_status.rb BODY job_info[:run_ids].each_with_index do |run_id, i| job_script +=<<"BODY" echo \" #---------- #{run_id} start ----------\" >> nera_status.rb echo \" #{run_id} => {\" >> nera_status.rb echo \" :seed => #{job_info[:seeds][i]}, :start_at => DateTime.parse( <<'NERA_START_AT'.chomp), :output => <<'NERA_OUTPUT', :finish_at => DateTime.parse( <<'NERA_FINISH_AT'.chomp)\" >> nera_status.rb date >> nera_status.rb echo \"NERA_START_AT\" >> nera_status.rb echo \"#{job_info[:execs][i]}\" mkdir -p #{run_id} cd #{run_id} { time -p { #{job_info[:execs][i]};} } 2>> ../nera_status.rb if test $? -ne 0; then { echo \"Exit abnormally!\" >> ../nera_status.rb; exit; } fi cd .. echo \"NERA_OUTPUT\" >> nera_status.rb date >> nera_status.rb echo \"NERA_FINISH_AT\" >> nera_status.rb BODY if i == job_info[:run_ids].length-1 then job_script += "echo \" }\" >> nera_status.rb\n" else job_script += "echo \" },\" >> nera_status.rb\n" end job_script += "echo \" #---------- #{run_id} end ----------\" >> nera_status.rb\n" end job_script +=<<"BODY" echo \"}\" >> nera_status.rb echo \"footer = {\" >> nera_status.rb echo \" :host_name => <<'NERA_HOST'.chomp, :finish_at => DateTime.parse( <<'NERA_DATE'.chomp )\" >> nera_status.rb hostname >> nera_status.rb echo \"NERA_HOST\" >> nera_status.rb date >> nera_status.rb echo \"NERA_DATE\" >> nera_status.rb echo "}" >> nera_status.rb cd .. tar cf #{job_info[:job_script_id]}.tar #{job_info[:job_script_id]}/ if test $? -ne 0; then { echo \"#Exit abnormally!\" >> ./nera_status.rb; exit; } fi bzip2 #{job_info[:job_script_id]}.tar if test $? -ne 0; then { echo \"Exit abnormally!\"; exit; } fi rm -rf #{job_info[:job_script_id]} BODY ############## job script ################### return job_script end private :job_script_body #-------------------------------------- #-public instance methods-------------- #-------------------------------------- public # create job script -------------------- def create_script(job_id, sim_id, param_id, sim_inst, run_stat) unless job_id.is_a?(Integer) and sim_id.is_a?(Integer) and param_id.is_a?(Integer) raise ArgumentError, "Each ID of Job, Simulation and Parameter must be an Integer." end unless sim_inst.kind_of?(NERA::Simulator) raise ArgumentError, "Simulation_Instance must be a subclass of NERA::Simulator." else # if sim_inst.param == {} # raise ArgumentError, "@param in Simulation_Instance must be set a parameter." # end end unless run_stat.is_a?(Array) raise ArgumentError, "Run_Status must be an Array." else run_stat.each do | stat | unless stat.has_key?(:id) and stat.has_key?(:seed) raise ArgumentError, "Run Status must have keys, :id and :seed." end end end run_ids =[] seeds = [] run_stat.each do |run_info| run_ids << run_info[:id] seeds << run_info[:seed] end job_info ={ :job_id => job_id, :job_script_id => sprintf("j%06d",job_id), :database => File.basename( @db_folder.path_to_simulator_layer), :simulator => sim_inst.class.to_s, :sim_id => sim_id, :param_id => param_id, :params => sim_inst.param, # {:L => 256, :K => 0.22325, :tmax => 512}, :run_ids => run_ids, :seeds => seeds, :execs => seeds.map do |sed| sim_inst.simulate_command( sed).split("\n").join(' && ').sub(/;$/,'') end } path_job_script = @db_folder.path_to_job_script( job_id) unless FileTest.directory?(@db_folder.path_to_job_layer) raise "must not happen" end if FileTest.exist?(path_job_script) raise "must not happen" end File.open(path_job_script,"w") do |io| io.puts job_script_body(job_info) io.flush end return path_job_script end # parse status file -------------------- def parse_status(path_stat) unless path_stat.is_a?(String) and FileTest.exists?(path_stat) raise ArgumentError, "#{path_stat} is not valid status file." end str = "" File.open(path_stat).each do |line| str += line end header = {} body = {} footer = {} begin eval(str) rescue raise RuntimeError, "This nera_status.rb is not valid." end job_info = header.merge( footer) body.each_pair do |run_id, info| info[:real_time] = 0.0 info[:user_time] = 0.0 info[:output].each_line do |line| if line =~ /^real [-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ info[:real_time] = line.sub(/^real /,'').to_f elsif line =~ /^user [-+]?(?:[0-9]+(\.[0-9]*)?|(\.[0-9]+))([eE][-+]?[0-9]+)?/ info[:user_time] += line.sub(/^user /,'').to_f end end end return job_info, body end end end