Skip to content

Instantly share code, notes, and snippets.

@hannesweisbach
Created July 23, 2016 12:26
Show Gist options
  • Save hannesweisbach/4a04f8557dd1ad00723e7f3e2a1d8238 to your computer and use it in GitHub Desktop.
Save hannesweisbach/4a04f8557dd1ad00723e7f3e2a1d8238 to your computer and use it in GitHub Desktop.
Wrapper script for Fail*/L4Re
#!/usr/bin/env ruby
require 'fileutils'
require 'open3'
require 'optparse'
require 'pathname'
module ResComp
class Config
@@config = {}
def self.set(key, value)
@@config[key] = value
end
def self.get(key)
@@config[key]
end
end
class Experiment
attr_reader :id, :binary, :type, :entry, :exit
def initialize(id, binary, type = nil)
@id = id
@binary = binary
@type = type
end
def name()
if type
return id + '-' + type
end
id
end
def target()
'ResComp-' + @id
end
def iso()
'rescomp-' + @id + '.iso'
end
def entry_ip()
# objdump -hS ex_uirq |awk '/asm volatile\(\"nop\"\)/ { getline; print }' | ack -io [0-9a-f]{7}
Open3.pipeline_r("objdump -hS #{Config.get('l4::bindir') + @binary}",
"awk '/asm volatile\\(\\\"nop\\\"\\)/ { getline; print }'",
"ack -io [0-9a-f]{7}") { |o, _|
output = o.read.lines
if type == 's'
@entry = output[1]
@exit = output[0]
else
@entry = output[0]
@exit = output[1]
end
}
end
end
$experiment_conf = "
func_entry=%{entry}
func_exit=%{exit}
#default config
emul_ips=5000000
max_instr_bytes=15
campain_server=localhost
#default files
state_folder=l4sys.state
instruction_list=ip.list
golden_run=golden.out
filter=filter.list
trace=trace.bp
numinstr=0
totinstr=0
"
class Run
def initialize(prefix, experiments, kernels)
@prefix = prefix
@experiments = experiments
@kernels = kernels
end
def setup()
p "Creating directory structure"
inst_filter = @prefix + "filter.list"
if not inst_filter.exist?
File.open(inst_filter, 'w') { |file|
file.write("0xc0000000 0xffffffff")
}
end
mem_filter = @prefix + "mem_filter.list"
if not mem_filter.exist?
File.open(mem_filter, 'w') { |file|
file.write("0xeac00000 0xeac02000\n")
file.write("0xf04b8000 0xf04c0000")
}
end
bochsrc = @prefix + 'bochsrc-bd'
if not bochsrc.symlink?
bochsrc.make_symlink('../bochsrc-bd')
end
@experiments.each { |e| e.entry_ip }
@experiments.product(@kernels).collect{ |e, k|
p " #{e.name}/#{k[:name]}"
dir = @prefix + e.name + k[:name]
FileUtils.mkpath dir
system({ 'MODULE_SEARCH_PATH' => "#{k[:path]}" },
"make -C #{Config.get('l4::srcdir')} grub2iso E=#{e.target}",
{ [:err, :out] => Config.get(:log) })
FileUtils.copy(Config.get('l4::imgdir') + e.iso, dir + 'image.iso')
FileUtils.copy(k[:path] + 'fiasco.image', dir + 'fiasco.image')
File.open(dir + 'experiment.conf', 'w') { |file|
file.write($experiment_conf % { :entry => e.entry, :exit => e.exit })
}
filter_link = dir + 'filter.list'
if not filter_link.symlink?
filter_link.make_symlink('../../filter.list')
end
filter_link = dir + 'mem_filter.list'
if not filter_link.symlink?
filter_link.make_symlink('../../mem_filter.list')
end
}
# puts "Launching objdump ..."
# pids = []
# do_foreach { |dir|
# pids << Process.spawn("objdump -hS #{dir + 'fiasco.image'}",
# { :out => [dir + 'fiasco.lss', 'w'] })
# }
# puts "Waiting for objdump to finish ..."
# pids.each{ |pid| Process.wait(pid) }
end
def prepare()
pids = []
do_foreach { |dir|
pid = Process.spawn({ 'BXIMAGE' => 'image.iso', 'BXSHARE' => "#{Config.get('fail::share')}" },
"#{Config.get('fail::bindir') + 'fail-client'} " +
"-Wf,--step=all -f ../../bochsrc-bd -q ",
{ :chdir => dir, [:err, :out] => [dir + 'preparation.log', 'w'] })
pids << pid
}
puts "Waiting for preparation to finish ..."
pids.each{ |pid| Process.wait(pid) }
end
def postproc()
do_foreach { |dir|
locs = {}
s = ""
IO.binread(dir + 'ip.list').unpack('Q*').each_slice(2){ |i, c| s += "#{i.to_s(16)}\n"}
stdout, status = Open3.capture2("addr2line -e #{dir + 'fiasco.image'}", :stdin_data => s)
stdout.each_line { |loc|
loc.chomp!
if locs[loc]
locs[loc] += 1
else
locs[loc] = 1
end
}
File.open(dir + 'inst', 'w') { |file|
locs.each{ |key, value|
file.write "%12d #{key}\n" % value
}
}
}
end
def postproc2()
do_foreach { |dir|
do_load(dir)
counts = []
addrs = ""
locs = {}
Open3.popen2("mysql -N") { |stdin, stdout, wait|
stdin.print "SELECT injection_instr_absolute, tr.time1, tr.time2, tr.width "+
"FROM fsppilot pil " +
"JOIN trace tr ON pil.variant_id = tr.variant_id " +
"AND pil.instr2 = tr.instr2 AND pil.data_address = tr.data_address "+
";"
stdin.close
stdout.each_line{ |line|
result = line.scan(/\d+/).map { |x| x.to_i }
counts << (result[2] - result[1] + 1) * result[3] * 8
addrs += "#{result[0].to_s(16)}\n"
}
}
stdout, status = Open3.capture2("addr2line -e #{dir + 'fiasco.image'}", :stdin_data => addrs)
stdout.each_line { |loc|
loc.chomp!
if locs[loc]
locs[loc] += counts.shift
else
locs[loc] = counts.shift
end
}
File.open(dir + 'hist', 'w') { |file|
locs.each{ |key, value|
file.write "%12d #{key}\n" % value
}
}
}
end
def do_load(trace)
tracefile = trace + 'trace.bp'
cmd = "#{Config.get('fail::bindir') + 'import-trace'} --importer MemoryImporter " +
"-d #{Config.get('db')} " +
"-t #{tracefile} "
system(cmd, { [:err, :out] => Config.get(:log) })
system("#{Config.get('fail::bindir') + 'prune-trace'} -d #{Config.get('db')} --overwrite",
{ [:err, :out] => Config.get(:log) })
end
def load()
do_foreach { |trace| do_load(trace) }
end
def number_of_experiments()
do_foreach { |trace|
sum = 0
do_load(trace)
Open3.popen2("mysql -N") { |stdin, stdout, wait|
stdin.print "SELECT tr.time1, tr.time2, tr.width FROM fsppilot pil " +
"JOIN trace tr ON pil.variant_id = tr.variant_id " +
"AND pil.instr2 = tr.instr2 AND pil.data_address = tr.data_address;"
stdin.close
stdout.each_line{ |line|
result = line.scan(/\d+/).map { |x| x.to_i }
sum += (result[1] - result[0] + 1) * result[2] * 8
}
}
puts "%-25s: %15s" % [ trace, sum.to_s.reverse.gsub(/...(?=.)/,'\& ').reverse ]
}
end
def do_foreach(&block)
@experiments.product(@kernels).collect{ |e, k|
block.call(@prefix + e.name + k[:name])
}
end
def fi()
server = Process.spawn("#{Config.get('fail::bindir') + 'l4-sys-server'} --type mem")
#launch clients
Process.wait(server)
#tell clients to quit
@kernels.each{ |name, path|
#make_image(name, path)
#trace(name)
import(name)
}
prune()
end
end
def run_fi(experiments)
dbname='failhannes'
#$BUILDDIR/import-trace --importer $IMPORTER -e $ELF -d $DBNAME -t trace.pb
#$BUILDDIR/prune-trace -d $DBNAME --overwrite
#l4sys-server
#launch clients on taurus
end
end
ResComp::Config.set('l4::srcdir', Pathname.new('~/L4/src'))
ResComp::Config.set('l4::objdir', Pathname.new('/home/weisbach/L4/build/l4re32'))
ResComp::Config.set('l4::bindir', ResComp::Config.get('l4::objdir') + 'bin' + 'x86_586' + 'l4f')
ResComp::Config.set('l4::imgdir', ResComp::Config.get('l4::objdir') + 'images')
ResComp::Config.set('fail::dir', Pathname.new('/home/weisbach/ResComp/fail'))
ResComp::Config.set('fail::bindir', ResComp::Config.get('fail::dir') + 'build' + 'bin')
ResComp::Config.set('fail::share', ResComp::Config.get('fail::dir') + 'simulators' + 'bochs' + 'bios')
ResComp::Config.set('db', 'failhannes')
ResComp::Config.set(:log, File.open('fi.log', 'w'))
experiments = []
experiments << ResComp::Experiment.new('hello', 'hello')
experiments << ResComp::Experiment.new('ipc', 'ex_ipc1')
experiments << ResComp::Experiment.new('utcb-ipc', 'ex_utcb_ipc')
experiments << ResComp::Experiment.new('uirq', 'ex_uirq')
experiments << ResComp::Experiment.new('map-irq', 'ex_map_irq_server', 's') # vertauscht
experiments << ResComp::Experiment.new('map-irq', 'ex_map_irq_client', 'c')
experiments << ResComp::Experiment.new('clntsrv', 'ex_clntsrv-server', 's') # vertauscht
experiments << ResComp::Experiment.new('clntsrv', 'ex_clntsrv-client', 'c')
experiments << ResComp::Experiment.new('streammap', 'ex_smap-server', 's') # vertauscht
experiments << ResComp::Experiment.new('streammap', 'ex_smap-client', 'c')
experiments << ResComp::Experiment.new('shared-ds', 'ex_l4re_ds_srv', 's') # vertauscht
experiments << ResComp::Experiment.new('shared-ds', 'ex_l4re_ds_clnt', 'c')
#prefix = Pathname.new(ARGV[0])
#l4dir = Pathname.new(ARGV[1])
kernels = []
kernels << { :name => 'baseline', :path => Pathname.new('/home/weisbach/L4/build/fiasco32') }
kernels << { :name => 'v', :path => Pathname.new('/home/weisbach/L4/build/fiasco32-v') }
kernels << { :name => 'vp', :path => Pathname.new('/home/weisbach/L4/build/fiasco32-vptrparam') }
prefix = Pathname.new('data')
options = {}
OptionParser.new do |opts|
opts.banner = "Usage: fi.rb [options]"
options[:experiment] = ['hello', 'ipc', 'utcb-ipc', 'uirq',
'map-irq-c', 'map-irq-s', 'clntsrv-c', 'clntsrv-s',
'streammap-s', 'streammap-c', 'shared-ds-s', 'shared-ds-c']
options[:variant] = ['baseline', 'v', 'vp']
opts.on("-e", "--experiment Experiments", Array, "Experiment to process") do |e|
options[:experiment] = e
end
opts.on("-v", "--variant Variants", Array, "Experiment variant to run") do |v|
options[:variant] = v
end
opts.on("-s", "--setup", "(Re-)generate tree, iso-images, etc") do |s|
options[:setup] = s
end
opts.on("-p", "--prepare", "(Re-)generate traces") do |p|
options[:prepare] = p
end
opts.on("-d", "--debug", "Run debug post-processing") do |d|
options[:debug] = d
end
opts.on("-l", "--load", "Load Benchmark/Variant into mysql database") do |l|
options[:load] = l
end
opts.on("-n", "--number", "Number of experiments") do |n|
options[:number] = n
end
end.parse!
benchmarks = experiments.select { |experiment| options[:experiment].include? experiment.name }
variants = kernels.select { |variant| options[:variant].include? variant[:name] }
run = ResComp::Run.new(prefix, benchmarks, variants)
if options[:setup]
run.setup()
end
if options[:prepare]
run.prepare()
end
if options[:debug]
run.postproc()
run.postproc2()
end
if options[:load]
run.load()
end
if options[:number]
run.number_of_experiments()
end
#prepare(prefix, experiments)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment