class BOAST::CKernel

Attributes

architecture[RW]
code[RW]
cost_function[RW]
includes[RW]
kernels[RW]
lang[RW]
procedure[RW]

Public Class Methods

coexecute(kernels) click to toggle source
# File lib/BOAST/Runtime/CoExecute.rb, line 29
def self.coexecute(kernels)
  semaphore = Mutex.new
  pval = FFI::MemoryPointer::new(:int)
  pval.write_int(kernels.length)
  if synchro == 'MUTEX' then
    mutex = FFI::MemoryPointer::new(128)
    Synchro.pthread_mutex_init(mutex, nil)
    condition = FFI::MemoryPointer::new(128)
    Synchro.pthread_cond_init(mutex, nil)
    sync = [pval, mutex, condition]
  else
    spinlock = FFI::MemoryPointer::new(128)
    Synchro.pthread_spin_init(spinlock, 0)
    sync = [pval, spinlock]
  end
  threads = []
  returns = []
  args = []
  kernels.each_index { |i|
    kernels[i][0].build unless kernels[i][0].methods.include?(:run)
    args[i] = kernels[i][1].dup
    if args[i].last.kind_of?( Hash ) then
      args[i][-1] = args[i].last.dup
      args[i][-1][:coexecute] = sync
    else
      args[i].push( { :coexecute => sync } )
    end
  }
  kernels.each_index { |i|
    threads << Thread::new(i) { |j|
      ret = kernels[j][0].run(*args[j])
      semaphore.synchronize {
        returns[j] = ret
      }
    }
  }
  threads.each { |thr| thr.join }
  if synchro == 'MUTEX' then
    Synchro.pthread_mutex_destroy(mutex)
    Synchro.pthread_cond_destroy(condition)
  else
    Synchro.pthread_spin_destroy(spinlock)
  end
  return returns
end
new(options={}) click to toggle source

Creates a new CKernel object. BOAST output is redirected to the CKernel. If the chain_code state is set the current BOAST output, as returned by {BOAST.get_output}, is used. @param [Hash] options contains named options @option options [StringIO] :code specify a StringIO to use rather than create a new one. @option options [Array] :kernels list of kernels this kernel depends on. The kernels will be linked at build time. @option options [Integer] :lang specify the language to use. Default is current language state as returned by {BOAST.get_lang}. @option options [Integer] :architecture specify the architecture to use. Default is the current BOAST architecture as returned by {BOAST.get_architecture}.

# File lib/BOAST/Runtime/CKernel.rb, line 34
def initialize(options={})
  if options[:code] then
    @code = options[:code]
  elsif get_chain_code
    @code = get_output
    @code.seek(0,SEEK_END)
  else
    @code = StringIO::new
  end
  set_output(@code)
  if options[:kernels] then
    @kernels = options[:kernels]
  else
    @kernels  = []
  end
  if options[:lang] then
    @lang = options[:lang]
  else
    @lang = get_lang
  end
  if options[:architecture] then
    @architecture = options[:architecture]
  else
    @architecture = get_architecture
  end
  @includes = []
  @includes = [options[:includes]].flatten if options[:includes]

  case @lang
  when CL
    extend OpenCLRuntime
  when CUDA
    extend CUDARuntime
    @probes = []
  when FORTRAN
    extend FORTRANRuntime
    extend FFIRuntime if ffi?
  else
    if @architecture == MPPA then
      extend MPPARuntime
    else
      extend CRuntime
      extend FFIRuntime if ffi?
    end
  end
end

Public Instance Methods

compare_ref(ref_outputs, outputs, epsilon = nil) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 21
def compare_ref(ref_outputs, outputs, epsilon = nil)
  res = {}
  @procedure.parameters.each_with_index { |param, indx|
    if param.direction == :in or param.constant then
      next
    end
    if param.dimension then
      outputs[indx].each { |elem|
        raise "Error! #{elem}" if elem.nan?
      }
      diff = (outputs[indx] - ref_outputs[indx]).abs
      if epsilon then
        diff.each { |elem|
          raise "Error: #{param.name} different from ref by: #{elem}!" if elem > epsilon
        }
      end
      res[param.name] = diff.max
    else
      raise "Error: #{param.name} is NaN!" if outputs[indx].nan?
      raise "Error: #{param.name} different from ref: #{outputs[indx]} != #{ref_outputs[indx]} !" if epsilon and (outputs[indx] - ref_outputs[indx]).abs > epsilon
      res[param.name] = (outputs[indx] - ref_outputs[indx]).abs
    end
  }
  return res
end
cost(*args) click to toggle source

If a cost function is provided returns the cost of running the function on the provided arguments.

# File lib/BOAST/Runtime/CKernel.rb, line 108
def cost(*args)
  @cost_function.call(*args)
end
dump_ref_inputs(values, path = ".", suffix = ".in" ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 13
def dump_ref_inputs(values, path = ".", suffix = ".in" )
  return dump_ref_files(values, path, suffix, :in )
end
dump_ref_outputs(values, path = ".", suffix = ".out" ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 17
def dump_ref_outputs(values, path = ".", suffix = ".out" )
  return dump_ref_files(values, path, suffix, :out )
end
load_ref_inputs(path = ".", suffix = ".in" ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 5
def load_ref_inputs(path = ".", suffix = ".in" )
  return load_ref_files( path, suffix, :in )
end
load_ref_outputs(path = ".", suffix = ".out" ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 9
def load_ref_outputs(path = ".", suffix = ".out" )
  return load_ref_files( path, suffix, :out )
end
method_missing(meth, *args, &block) click to toggle source

@private

Calls superclass method
# File lib/BOAST/Runtime/CKernel.rb, line 98
def method_missing(meth, *args, &block)
 if meth.to_s == "run" then
   build
   run(*args, &block)
 else
   super
 end
end
print() click to toggle source

@deprecated

to_s() click to toggle source

@return [String] source code of the kernel

# File lib/BOAST/Runtime/CKernel.rb, line 88
def to_s
  if @lang == FORTRAN then
    return line_limited_source
  else
    @code.rewind
    return code.read
  end
end

Private Instance Methods

dump_ref_files( values, path, suffix, intent ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 205
def dump_ref_files( values, path, suffix, intent )
  proc_path = path + "/#{@procedure.name}/"
  Dir.mkdir( proc_path ) unless File.exists?( proc_path )
  values.each { |key, vals|
    case_path = proc_path + "#{key}/"
    Dir.mkdir( case_path ) unless File.exists?( case_path )
    d = Pathname.new( case_path )
    @procedure.parameters.each_with_index { |param, i|
      write_param( param, vals[i], d.to_s, suffix, intent )
    }
    if @lang == CUDA or @lang == CL then
      write_gpu_dim( vals.last, d.to_s )
    end
  }
  return nil
end
get_array_type(param) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 49
def get_array_type(param)
  if param.type.class == Real then
    case param.type.size
    when 4
      type = NArray::SFLOAT
    when 8
      type = NArray::FLOAT
    else
      STDERR::puts "Unsupported Float size for NArray: #{param.type.size}, defaulting to byte" if debug?
      type = NArray::BYTE
    end
  elsif param.type.class == Int then
    case param.type.size
    when 1
      type = NArray::BYTE
    when 2
      type = NArray::SINT
    when 4
      type = NArray::INT
    else
      STDERR::puts "Unsupported Int size for NArray: #{param.type.size}, defaulting to byte" if debug?
      type = NArray::BYTE
    end
  else
    STDERR::puts "Unkown array type for NArray: #{param.type}, defaulting to byte" if debug?
    type = NArray::BYTE
  end
  return type
end
get_gpu_dim(directory) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 144
def get_gpu_dim(directory)
  f = File::new( directory + "/problem_size", "r")
  s = f.read
  local_dim, global_dim = s.scan(/<(.*?)>/)
  local_dim  = local_dim.pop.split(",").collect!{ |e| e.to_i }
  global_dim = global_dim.pop.split(",").collect!{ |e| e.to_i }
  (local_dim.length..2).each{ |i| local_dim[i] = 1 }
  (global_dim.length..2).each{ |i| global_dim[i] = 1 }
  if @lang == CL then
    local_dim.each_index { |indx| global_dim[indx] *= local_dim[indx] }
    res = { :global_work_size => global_dim, :local_work_size => local_dim }
  else
    res = { :block_number => global_dim, :block_size => local_dim }
  end
  f.close
  return res
end
get_scalar_type(param) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 79
def get_scalar_type(param)
  if param.type.class == Real then
    case param.type.size
    when 4
      type = "f"
    when 8
      type = "d"
    else
      raise "Unsupported Real scalar size: #{param.type.size}!"
    end
  elsif param.type.class == Int then
    case param.type.size
    when 1
      type = "C"
    when 2
      type = "S"
    when 4
      type = "L"
    when 8
      type = "Q"
    else
      raise "Unsupported Int scalar size: #{param.type.size}!"
    end
    if param.type.signed? then
      type.downcase!
    end
  end
  return type
end
load_ref_files( path, suffix, intent ) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 183
def load_ref_files( path, suffix, intent )
  proc_path = path + "/#{@procedure.name}/"
  res_h = {}
  begin
    dirs = Pathname.new(proc_path).children.select { |c| c.directory? }
  rescue
    return res_h
  end
  dirs.collect! { |d| d.to_s }
  dirs.each { |d|
    res = [] 
    @procedure.parameters.collect { |param|
      res.push read_param(param, d, suffix, intent)
    }
    if @lang == CUDA or @lang == CL then
      res.push get_gpu_dim(d)
    end
    res_h[d] =  res
  }
  return res_h
end
read_param(param, directory, suffix, intent) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 124
def read_param(param, directory, suffix, intent)
  if intent == :out and ( param.direction == :in or param.constant ) then
    return nil
  end
  f = File::new( directory + "/" + param.name+suffix, "rb" )
  if param.dimension or param.vector? then
    type = get_array_type(param)
    if f.size == 0 then
      res = NArray::new(type, 1)
    else
      res = NArray.to_na(f.read, type)
    end
  else
    type = get_scalar_type(param)
    res = f.read.unpack(type).first
  end
  f.close
  return res
end
write_gpu_dim(value, directory) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 162
def write_gpu_dim(value, directory)
  global_work_size = value[:global_work_size]
  block_number = value[:block_number]
  local_work_size = value[:local_work_size]
  local_work_size = value[:block_size] unless local_work_size
  (local_work_size.length..2).each{ |i| local_work_size[i] = 1 }
  if global_work_size and not block_number then
    block_number = []
    (global_work_size.length..2).each{ |i| global_work_size[i] = 1 }
    local_work_size.each_index { |i|
      block_number[i] = global_work_size[i] / local_work_size[i]
    }
  end
  (block_number.length..2).each{ |i| block_number[i] = 1 }

  File::open( directory + "/problem_size", "w") { |f|
    f.write "<#{local_work_size.join(",")}><#{block_number.join(",")}>"
  }
  return nil
end
write_param(param, value, directory, suffix, intent) click to toggle source
# File lib/BOAST/Runtime/NonRegression.rb, line 109
def write_param(param, value, directory, suffix, intent)
  if intent == :out and ( param.direction == :in or param.constant ) then
    return nil
  end
  f = File::new( directory + "/" + "#{param.name+suffix}", "wb" )
  if param.dimension or param.vector? then
    f.write value.to_s
  else
    type = get_scalar_type(param)
    f.write [value].pack(type)
  end
  f.close
  return nil
end