Class: Ikra::Translator::EnvironmentBuilder

Inherits:
Object
  • Object
show all
Defined in:
lib/translator/environment_builder.rb

Overview

Interface for transferring data to the CUDA side using FFI. Builds a struct containing all required objects (including lexical variables). Traces objects.

Defined Under Namespace

Classes: CurriedBuilder, UnionTypeStruct

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initializeEnvironmentBuilder

Returns a new instance of EnvironmentBuilder.



16
17
18
19
20
21
22
# File 'lib/translator/environment_builder.rb', line 16

def initialize
    @objects = {}
    @previous_results = {}
    @previous_results_types = {}
    @device_struct_allocation = ""
    @ffi_struct = {}
end

Instance Attribute Details

#device_struct_allocationObject

Returns the value of attribute device_struct_allocation.



13
14
15
# File 'lib/translator/environment_builder.rb', line 13

def device_struct_allocation
  @device_struct_allocation
end

#ffi_structObject

Returns the value of attribute ffi_struct.



14
15
16
# File 'lib/translator/environment_builder.rb', line 14

def ffi_struct
  @ffi_struct
end

#objectsObject

Returns the value of attribute objects.



11
12
13
# File 'lib/translator/environment_builder.rb', line 11

def objects
  @objects
end

Class Method Details

.base_identifier(command_id) ⇒ Object

Returns the name of the field containing the base array for a certain identity command.



135
136
137
# File 'lib/translator/environment_builder.rb', line 135

def self.base_identifier(command_id)
    return "b#{command_id}_base"
end

Instance Method Details

#[](command_id) ⇒ Object



236
237
238
# File 'lib/translator/environment_builder.rb', line 236

def [](command_id)
    CurriedBuilder.new(self, command_id)
end

#add_base_array(command_id, object) ⇒ Object

Adds an object as a base array



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/translator/environment_builder.rb', line 73

def add_base_array(command_id, object)
    cuda_id = "b#{command_id}_base"

    if objects.include?(cuda_id)
        # Object already present

        if !objects[cuda_id].equal?(object)
            raise AssertionError.new("Adding different base array under different name")
        end

        return cuda_id
    end

    objects[cuda_id] = object

    cuda_id_size = "b#{command_id}_size"
    if object.class == FFI::MemoryPointer
        objects[cuda_id_size] = object.size / UnionTypeStruct.size
    else
        objects[cuda_id_size] = object.size
    end

    # Generate code for copying data to global memory
    update_dev_struct_allocation(cuda_id, object)

    return cuda_id
end

#add_object(command_id, identifier, object) ⇒ Object

Adds an objects as a lexical variable.



37
38
39
40
41
42
43
44
45
46
47
# File 'lib/translator/environment_builder.rb', line 37

def add_object(command_id, identifier, object)
    cuda_id = "l#{command_id}_#{identifier}"

    if objects[cuda_id].object_id != object.object_id
        # Don't add the object multiple times
        objects[cuda_id] = object
        update_dev_struct_allocation(cuda_id, object)
    end

    return cuda_id
end

#add_previous_result(previous_command_id, pointer_to_result) ⇒ Object

Adds object to the ffi_struct which is of type unique_id => pointer in GPU



50
51
52
53
54
55
56
57
# File 'lib/translator/environment_builder.rb', line 50

def add_previous_result(previous_command_id, pointer_to_result)
    cuda_id = "prev_#{previous_command_id}"
    @previous_results[cuda_id] = pointer_to_result
    
    update_dev_struct_allocation(cuda_id, pointer_to_result)

    cuda_id
end

#add_previous_result_type(previous_command_id, type) ⇒ Object

Adds object to the ffi_struct which is of type unique_id => type of command with unique_id



65
66
67
68
69
70
# File 'lib/translator/environment_builder.rb', line 65

def add_previous_result_type(previous_command_id, type)
    cuda_id = "prev_#{previous_command_id}"
    @previous_results_types[cuda_id] = type

    cuda_id
end

#add_soa_array(name, object) ⇒ Object

Add an array for the Structure of Arrays object layout



102
103
104
105
106
107
# File 'lib/translator/environment_builder.rb', line 102

def add_soa_array(name, object)
    objects[name] = object
    objects["#{name}_size"] = object.size

    update_dev_struct_allocation(name, object)
end

#allocate_previous_pointer(previous_command_id) ⇒ Object

Adds object to the ffi_struct which is of type unique_id => 0



60
61
62
# File 'lib/translator/environment_builder.rb', line 60

def allocate_previous_pointer(previous_command_id)
    add_previous_result(previous_command_id, 0)
end

#build_environment_structObject



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
# File 'lib/translator/environment_builder.rb', line 153

def build_environment_struct
    @objects.freeze

    struct_def = "struct environment_struct\n{\n"
    @objects.each do |key, value|
        if value.class == FFI::MemoryPointer
            # TODO: can this be an extension method of FFI::MemoryPointer?
            struct_def += "    union_t * #{key};\n"
        else
            struct_def += "    #{value.ikra_type.to_c_type} #{key};\n"
        end
    end

    previous_results_types.each do |key, value|
        struct_def += "    #{value.to_c_type} *#{key};\n"
    end

    struct_def += "};\n"

    return struct_def
end

#build_environment_variableObject



139
140
141
142
143
144
145
146
147
148
149
150
151
# File 'lib/translator/environment_builder.rb', line 139

def build_environment_variable
    # Copy arrays to device side
    result = @device_struct_allocation

    # Allocate and copy over environment to device
    result = result + Translator.read_file(
        file_name: "allocate_memcpy_environment_to_device.cpp",
        replacements: {
            "dev_env" => Constants::ENV_DEVICE_IDENTIFIER,
            "host_env" => Constants::ENV_HOST_IDENTIFIER})

    return result
end

#build_ffi_objectObject



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
# File 'lib/translator/environment_builder.rb', line 199

def build_ffi_object
    struct_type = build_ffi_type
    struct = struct_type.new

    @objects.each do |key, value|
        # TODO: need proper Array handling
        if value.class == Array
            # Check first element to determine type of array
            # TODO: check for polymorphic
            inner_type = value.first.class.to_ikra_type
            array_ptr = FFI::MemoryPointer.new(value.size * inner_type.c_size)

            if inner_type == Types::PrimitiveType::Int
                array_ptr.put_array_of_int(0, value)
            elsif inner_type == Types::PrimitiveType::Float
                array_ptr.put_array_of_float(0, value)
            else
                raise NotImplementedError
            end

            struct[key.to_sym] = array_ptr
        else
            struct[key.to_sym] = value
        end
    end

    previous_results.each do |key, value|
        struct[key.to_sym] = value
    end

    struct[:dummy] = 0
    
    @ffi_struct = struct
    
    struct.to_ptr
end

#build_ffi_typeObject



175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
# File 'lib/translator/environment_builder.rb', line 175

def build_ffi_type
    struct_layout = []
    @objects.each do |key, value|
        if value.class == FFI::MemoryPointer
            # TODO: can this be an extension method of FFI::MemoryPointer?
            struct_layout += [key.to_sym, :pointer]
        else
            struct_layout += [key.to_sym, value.ikra_type.to_ffi_type]
        end
    end

    previous_results.each do |key, value|
        struct_layout += [key.to_sym, :pointer]
    end

    # Add dummy at the end of layout, because layouts cannot be empty
    struct_layout += [:dummy, :int]

    struct_type = Class.new(FFI::Struct)
    struct_type.layout(*struct_layout)

    struct_type
end

#cloneObject



255
256
257
258
259
260
# File 'lib/translator/environment_builder.rb', line 255

def clone
    result = self.class.new
    result.objects = @objects.clone
    result.device_struct_allocation = @device_struct_allocation
    result
end

#previous_resultsObject

Hash that maps the unique_id of a command on the adress of its result on the GPU. Returns a sorted version of the hash.



26
27
28
# File 'lib/translator/environment_builder.rb', line 26

def previous_results
    return Hash[@previous_results.sort]
end

#previous_results_typesObject

Hash that maps the unique_id of a command on the type of its result. Returns a sorted version of the hash.



32
33
34
# File 'lib/translator/environment_builder.rb', line 32

def previous_results_types
    return Hash[@previous_results_types.sort]
end

#update_dev_struct_allocation(field, object) ⇒ Object



109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
# File 'lib/translator/environment_builder.rb', line 109

def update_dev_struct_allocation(field, object)
    if object.class == Array
        # Allocate new array
        @device_struct_allocation += Translator.read_file(
            file_name: "env_builder_copy_array.cpp",
            replacements: { 
                "field" => field, 
                "host_env" => Constants::ENV_HOST_IDENTIFIER,
                "dev_env" => Constants::ENV_DEVICE_IDENTIFIER,
                "size_bytes" => (object.first.class.to_ikra_type.c_size * object.size).to_s})
    elsif object.class == FFI::MemoryPointer
        # This is an array of union type structs
        # Allocate new array
        @device_struct_allocation += Translator.read_file(
            file_name: "env_builder_copy_array.cpp",
            replacements: { 
                "field" => field, 
                "host_env" => Constants::ENV_HOST_IDENTIFIER,
                "dev_env" => Constants::ENV_DEVICE_IDENTIFIER,
                "size_bytes" => object.size.to_s})   
    else
        # Nothing to do, this case is handled by mem-copying the struct
    end
end