Class: Ikra::Translator::CommandTranslator::ProgramBuilder::Launcher
- Defined in:
- lib/translator/program_launcher.rb
Defined Under Namespace
Classes: CommandNotifier, FixedSizeArrayStruct, KernelResultStruct, KernelUnionResultStruct, UnionTypeStruct, UnionTypeValue
Class Attribute Summary collapse
-
.last_time_allocate_memory ⇒ Object
Returns the value of attribute last_time_allocate_memory.
-
.last_time_compiler ⇒ Object
Returns the value of attribute last_time_compiler.
-
.last_time_free_memory ⇒ Object
Returns the value of attribute last_time_free_memory.
-
.last_time_kernel ⇒ Object
Returns the value of attribute last_time_kernel.
-
.last_time_prepare_env ⇒ Object
Returns the value of attribute last_time_prepare_env.
-
.last_time_read_result_ffi ⇒ Object
Returns the value of attribute last_time_read_result_ffi.
-
.last_time_setup_cuda ⇒ Object
Returns the value of attribute last_time_setup_cuda.
-
.last_time_total_external ⇒ Object
Returns the value of attribute last_time_total_external.
-
.last_time_transfer_memory ⇒ Object
Returns the value of attribute last_time_transfer_memory.
Instance Attribute Summary collapse
-
#environment_builder ⇒ Object
readonly
Returns the value of attribute environment_builder.
-
#result_type ⇒ Object
readonly
Returns the value of attribute result_type.
-
#root_command ⇒ Object
readonly
Returns the value of attribute root_command.
-
#source ⇒ Object
readonly
Returns the value of attribute source.
Class Method Summary collapse
Instance Method Summary collapse
- #compile ⇒ Object
-
#execute ⇒ Object
Attaches the compiled shared library via Ruby FFI and invokes the kernel.
-
#initialize(source:, environment_builder:, result_type:, root_command:) ⇒ Launcher
constructor
A new instance of Launcher.
Constructor Details
#initialize(source:, environment_builder:, result_type:, root_command:) ⇒ Launcher
Returns a new instance of Launcher.
91 92 93 94 95 96 |
# File 'lib/translator/program_launcher.rb', line 91 def initialize(source:, environment_builder:, result_type:, root_command:) @source = source @environment_builder = environment_builder @result_type = result_type @root_command = root_command end |
Class Attribute Details
.last_time_allocate_memory ⇒ Object
Returns the value of attribute last_time_allocate_memory.
73 74 75 |
# File 'lib/translator/program_launcher.rb', line 73 def last_time_allocate_memory @last_time_allocate_memory end |
.last_time_compiler ⇒ Object
Returns the value of attribute last_time_compiler.
75 76 77 |
# File 'lib/translator/program_launcher.rb', line 75 def last_time_compiler @last_time_compiler end |
.last_time_free_memory ⇒ Object
Returns the value of attribute last_time_free_memory.
71 72 73 |
# File 'lib/translator/program_launcher.rb', line 71 def last_time_free_memory @last_time_free_memory end |
.last_time_kernel ⇒ Object
Returns the value of attribute last_time_kernel.
70 71 72 |
# File 'lib/translator/program_launcher.rb', line 70 def last_time_kernel @last_time_kernel end |
.last_time_prepare_env ⇒ Object
Returns the value of attribute last_time_prepare_env.
69 70 71 |
# File 'lib/translator/program_launcher.rb', line 69 def last_time_prepare_env @last_time_prepare_env end |
.last_time_read_result_ffi ⇒ Object
Returns the value of attribute last_time_read_result_ffi.
76 77 78 |
# File 'lib/translator/program_launcher.rb', line 76 def last_time_read_result_ffi @last_time_read_result_ffi end |
.last_time_setup_cuda ⇒ Object
Returns the value of attribute last_time_setup_cuda.
68 69 70 |
# File 'lib/translator/program_launcher.rb', line 68 def last_time_setup_cuda @last_time_setup_cuda end |
.last_time_total_external ⇒ Object
Returns the value of attribute last_time_total_external.
74 75 76 |
# File 'lib/translator/program_launcher.rb', line 74 def last_time_total_external @last_time_total_external end |
.last_time_transfer_memory ⇒ Object
Returns the value of attribute last_time_transfer_memory.
72 73 74 |
# File 'lib/translator/program_launcher.rb', line 72 def last_time_transfer_memory @last_time_transfer_memory end |
Instance Attribute Details
#environment_builder ⇒ Object (readonly)
Returns the value of attribute environment_builder.
64 65 66 |
# File 'lib/translator/program_launcher.rb', line 64 def environment_builder @environment_builder end |
#result_type ⇒ Object (readonly)
Returns the value of attribute result_type.
65 66 67 |
# File 'lib/translator/program_launcher.rb', line 65 def result_type @result_type end |
#root_command ⇒ Object (readonly)
Returns the value of attribute root_command.
62 63 64 |
# File 'lib/translator/program_launcher.rb', line 62 def root_command @root_command end |
#source ⇒ Object (readonly)
Returns the value of attribute source.
63 64 65 |
# File 'lib/translator/program_launcher.rb', line 63 def source @source end |
Class Method Details
.reset_time ⇒ Object
78 79 80 81 82 83 84 85 86 87 88 |
# File 'lib/translator/program_launcher.rb', line 78 def reset_time @last_time_setup_cuda = 0 @last_time_prepare_env = 0 @last_time_kernel = 0 @last_time_free_memory = 0 @last_time_transfer_memory = 0 @last_time_allocate_memory = 0 @last_time_total_external = 0 @last_time_compiler = 0 @last_time_read_result_ffi = 0 end |
Instance Method Details
#compile ⇒ Object
98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/translator/program_launcher.rb', line 98 def compile # Generate debug output with line numbers line_no_digits = Math.log(source.lines.count, 10).ceil source_with_line_numbers = source.lines.each_with_index.map do |line, num| "[#{(num + 1).to_s.rjust(line_no_digits, "0")}] #{line}" end.join("") Log.info("Generated source code:\n#{source_with_line_numbers}") # Write source code to temporary file file = Tempfile.new(["ikra_kernel", ".cu"]) file.write(source) file.close # Write to codegen_expect if Configuration.codegen_expect_file_name != nil expect_file = File.new(Configuration.codegen_expect_file_name, "w+") expect_file.write(source) expect_file.close end # Run compiler @so_filename = "#{file.path}.#{Configuration.so_suffix}" nvcc_command = Configuration.nvcc_invocation_string( file.path, @so_filename) Log.info("Compiling kernel: #{nvcc_command}") time_before = Time.now compile_status = %x(#{nvcc_command}) Log.info("Done, took #{Time.now - time_before} s") self.class.last_time_compiler = Time.now - time_before if $? != 0 Log.fatal("nvcc failed: #{compile_status}") raise RuntimeError.new("nvcc failed: #{compile_status}") else Log.info("nvcc successful: #{compile_status}") end end |
#execute ⇒ Object
Attaches the compiled shared library via Ruby FFI and invokes the kernel.
138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 |
# File 'lib/translator/program_launcher.rb', line 138 def execute if !File.exist?(@so_filename) compile end time_before = Time.now ffi_interface = Module.new ffi_interface.extend(FFI::Library) ffi_interface.ffi_lib(@so_filename) ffi_interface.attach_function(:launch_kernel, [:pointer], :pointer) environment_object = environment_builder.build_ffi_object Log.info("FFI transfer time: #{Time.now - time_before} s") time_before = Time.now kernel_result = ffi_interface.launch_kernel(environment_object) total_time_external = Time.now - time_before Log.info("Kernel time: #{total_time_external} s") # Update command root_command.accept(CommandNotifier.new(environment_builder.ffi_struct)) # TODO: Currently, this only works if result_type.is_singleton? if result_type.is_singleton? result_t_struct = KernelResultStruct.new(kernel_result) else result_t_struct = KernelUnionResultStruct.new(kernel_result) end # Extract error code and return value error_code = result_t_struct[:error_code] # Extract time measurements self.class.last_time_setup_cuda += result_t_struct[:time_setup_cuda] * 0.000001 self.class.last_time_prepare_env += result_t_struct[:time_prepare_env] * 0.000001 self.class.last_time_kernel += result_t_struct[:time_kernel] * 0.000001 self.class.last_time_free_memory += result_t_struct[:time_free_memory] * 0.000001 self.class.last_time_transfer_memory += result_t_struct[:time_transfer_memory] * 0.000001 self.class.last_time_allocate_memory += result_t_struct[:time_allocate_memory] * 0.000001 self.class.last_time_total_external += total_time_external if error_code != 0 # Kernel failed Errors.raiseCudaError(error_code) end time_before = Time.now # Check type of result: It should be one of `result_type` if result_type.is_singleton? array_type = result_type.singleton_type if !array_type.is_a?(Types::ArrayType) raise AssertionError.new( "ArrayType expected, but #{array_type} found") end result = result_t_struct[:result][:content] result_size = result_t_struct[:result][:size] else array_type = result_type.find do |sing_type| sing_type.class_id == result_t_struct[:result][:class_id] end if array_type == nil raise AssertionError.new( "Unknown class_id: #{result_t_struct[:result][:class_id]}") end if !array_type.is_a?(Types::ArrayType) raise AssertionError.new( "ArrayType expected, but #{array_type} found") end result = result_t_struct[:result][:value][:variable_size_array][:content] result_size = result_t_struct[:result][:value][:variable_size_array][:size] end inner_type = array_type.inner_type if inner_type.is_singleton? # Read in entire array if inner_type.singleton_type == Types::PrimitiveType::Int computation_result = result.read_array_of_int(result_size) elsif inner_type.singleton_type == Types::PrimitiveType::Float computation_result = result.read_array_of_float(result_size) elsif inner_type.singleton_type == Types::PrimitiveType::Bool computation_result = result.read_array_of_uint8(result_size).map do |v| v == 1 end elsif inner_type.singleton_type == Types::PrimitiveType::Nil computation_result = [nil] * result_size elsif inner_type.singleton_type.is_a?(Types::ZipStructType) result_struct_type = inner_type.singleton_type.to_ruby_type computation_result = Array.new(result_size) do |index| result_struct_type.new(result + index * result_struct_type.size) end else raise NotImplementedError.new("Type not implemented") end self.class.last_time_read_result_ffi = Time.now - time_before return computation_result else # Read union type struct # Have to read one by one and assemble object result_values = Array.new(result_size) for index in 0...result_size # TODO: Size of union type (12 bytes) should not be hard-coded here s = Constants::UNION_TYPE_SIZE o = Constants::UNION_TYPE_VALUE_OFFSET next_type = (result + (s * index)).read_int if next_type == Types::PrimitiveType::Int.class_id result_values[index] = (result + s * index + o).read_int elsif next_type == Types::PrimitiveType::Float.class_id result_values[index] = (result + s * index + o).read_float elsif next_type == Types::PrimitiveType::Bool.class_id result_values[index] = (result + s * index + o).read_uint8 == 1 elsif next_type == Types::PrimitiveType::Nil.class_id result_values[index] = nil else raise NotImplementedError.new("Implement class objs for \##{index}: #{next_type}") end end self.class.last_time_read_result_ffi = Time.now - time_before return result_values end end |