1/*
2    Copyright (c) 2014 Intel Corporation.  All Rights Reserved.
3
4    Redistribution and use in source and binary forms, with or without
5    modification, are permitted provided that the following conditions
6    are met:
7
8      * Redistributions of source code must retain the above copyright
9        notice, this list of conditions and the following disclaimer.
10      * Redistributions in binary form must reproduce the above copyright
11        notice, this list of conditions and the following disclaimer in the
12        documentation and/or other materials provided with the distribution.
13      * Neither the name of Intel Corporation nor the names of its
14        contributors may be used to endorse or promote products derived
15        from this software without specific prior written permission.
16
17    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*/
29
30
31#include "compiler_if_host.h"
32
33#include <malloc.h>
34#ifndef TARGET_WINNT
35#include <alloca.h>
36#endif // TARGET_WINNT
37
38// Global counter on host.
39// This variable is used if P2OPT_offload_do_data_persistence == 2.
40// The variable used to identify offload constructs contained in one procedure.
41// Increment of OFFLOAD_CALL_COUNT is inserted at entries of HOST routines with
42// offload constructs.
43static int offload_call_count = 0;
44
45extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE(
46    TARGET_TYPE      target_type,
47    int              target_number,
48    int              is_optional,
49    _Offload_status* status,
50    const char*      file,
51    uint64_t         line
52)
53{
54    bool retval;
55    OFFLOAD ofld;
56
57    // initialize status
58    if (status != 0) {
59        status->result = OFFLOAD_UNAVAILABLE;
60        status->device_number = -1;
61        status->data_sent = 0;
62        status->data_received = 0;
63    }
64
65    // make sure libray is initialized
66    retval = __offload_init_library();
67
68    // OFFLOAD_TIMER_INIT must follow call to __offload_init_library
69    OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);
70
71    OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);
72
73    OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
74
75    // initalize all devices is init_type is on_offload_all
76    if (retval && __offload_init_type == c_init_on_offload_all) {
77        for (int i = 0; i < mic_engines_total; i++) {
78             mic_engines[i].init();
79        }
80    }
81    OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
82
83    OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);
84
85    if (target_type == TARGET_HOST) {
86        // Host always available
87        retval = true;
88    }
89    else if (target_type == TARGET_MIC) {
90        if (target_number >= -1) {
91            if (retval) {
92                if (target_number >= 0) {
93                    // User provided the device number
94                    target_number = target_number % mic_engines_total;
95                }
96                else {
97                    // use device 0
98                    target_number = 0;
99                }
100
101                // reserve device in ORSL
102                if (is_optional) {
103                    if (!ORSL::try_reserve(target_number)) {
104                        target_number = -1;
105                    }
106                }
107                else {
108                    if (!ORSL::reserve(target_number)) {
109                        target_number = -1;
110                    }
111                }
112
113                // initialize device
114                if (target_number >= 0 &&
115                    __offload_init_type == c_init_on_offload) {
116                    OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
117                    mic_engines[target_number].init();
118                    OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
119                }
120            }
121            else {
122                // fallback to CPU
123                target_number = -1;
124            }
125
126            if (target_number < 0 || !retval) {
127                if (!is_optional && status == 0) {
128                    LIBOFFLOAD_ERROR(c_device_is_not_available);
129                    exit(1);
130                }
131
132                retval = false;
133            }
134        }
135        else {
136            LIBOFFLOAD_ERROR(c_invalid_device_number);
137            exit(1);
138        }
139    }
140
141    if (retval) {
142        ofld = new OffloadDescriptor(target_number, status,
143                                     !is_optional, false, timer_data);
144        OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);
145        Offload_Report_Prolog(timer_data);
146        OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
147                              "Starting offload: target_type = %d, "
148                              "number = %d, is_optional = %d\n",
149                              target_type, target_number, is_optional);
150
151        OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
152    }
153    else {
154        ofld = NULL;
155
156        OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
157        OFFLOAD_TIMER_STOP(timer_data, c_offload_host_total_offload);
158        offload_report_free_data(timer_data);
159    }
160
161    return ofld;
162}
163
164extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1(
165    const int*  device_num,
166    const char* file,
167    uint64_t    line
168)
169{
170    int target_number;
171
172    // make sure libray is initialized and at least one device is available
173    if (!__offload_init_library()) {
174        LIBOFFLOAD_ERROR(c_device_is_not_available);
175        exit(1);
176    }
177
178    // OFFLOAD_TIMER_INIT must follow call to __offload_init_library
179
180    OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);
181
182    OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);
183
184    OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
185
186    if (__offload_init_type == c_init_on_offload_all) {
187        for (int i = 0; i < mic_engines_total; i++) {
188             mic_engines[i].init();
189        }
190    }
191
192    OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
193
194    OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);
195
196    // use default device number if it is not provided
197    if (device_num != 0) {
198        target_number = *device_num;
199    }
200    else {
201        target_number = __omp_device_num;
202    }
203
204    // device number should be a non-negative integer value
205    if (target_number < 0) {
206        LIBOFFLOAD_ERROR(c_omp_invalid_device_num);
207        exit(1);
208    }
209
210    // should we do this for OpenMP?
211    target_number %= mic_engines_total;
212
213    // reserve device in ORSL
214    if (!ORSL::reserve(target_number)) {
215        LIBOFFLOAD_ERROR(c_device_is_not_available);
216        exit(1);
217    }
218
219    // initialize device(s)
220    OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
221
222    if (__offload_init_type == c_init_on_offload) {
223        mic_engines[target_number].init();
224    }
225
226    OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
227
228    OFFLOAD ofld =
229        new OffloadDescriptor(target_number, 0, true, true, timer_data);
230
231    OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);
232
233    Offload_Report_Prolog(timer_data);
234
235    OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
236                          "Starting OpenMP offload, device = %d\n",
237                          target_number);
238
239    OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
240
241    return ofld;
242}
243
244int offload_offload_wrap(
245    OFFLOAD ofld,
246    const char *name,
247    int is_empty,
248    int num_vars,
249    VarDesc *vars,
250    VarDesc2 *vars2,
251    int num_waits,
252    const void **waits,
253    const void **signal,
254    int entry_id,
255    const void *stack_addr
256)
257{
258    bool ret = ofld->offload(name, is_empty, vars, vars2, num_vars,
259                             waits, num_waits, signal, entry_id, stack_addr);
260    if (!ret || signal == 0) {
261        delete ofld;
262    }
263    return ret;
264}
265
266extern "C" int OFFLOAD_OFFLOAD1(
267    OFFLOAD ofld,
268    const char *name,
269    int is_empty,
270    int num_vars,
271    VarDesc *vars,
272    VarDesc2 *vars2,
273    int num_waits,
274    const void **waits,
275    const void **signal
276)
277{
278    return offload_offload_wrap(ofld, name, is_empty,
279                            num_vars, vars, vars2,
280                            num_waits, waits,
281                            signal, NULL, NULL);
282}
283
284extern "C" int OFFLOAD_OFFLOAD2(
285    OFFLOAD ofld,
286    const char *name,
287    int is_empty,
288    int num_vars,
289    VarDesc *vars,
290    VarDesc2 *vars2,
291    int num_waits,
292    const void** waits,
293    const void** signal,
294    int entry_id,
295    const void *stack_addr
296)
297{
298    return offload_offload_wrap(ofld, name, is_empty,
299                            num_vars, vars, vars2,
300                            num_waits, waits,
301                            signal, entry_id, stack_addr);
302}
303
304extern "C" int OFFLOAD_OFFLOAD(
305    OFFLOAD ofld,
306    const char *name,
307    int is_empty,
308    int num_vars,
309    VarDesc *vars,
310    VarDesc2 *vars2,
311    int num_waits,
312    const void **waits,
313    const void *signal,
314    int entry_id,
315    const void *stack_addr
316)
317{
318    // signal is passed by reference now
319    const void **signal_new = (signal != 0) ? &signal : 0;
320    const void **waits_new = 0;
321    int num_waits_new = 0;
322
323    // remove NULL values from the list of signals to wait for
324    if (num_waits > 0) {
325        waits_new = (const void**) alloca(sizeof(void*) * num_waits);
326        for (int i = 0; i < num_waits; i++) {
327            if (waits[i] != 0) {
328                waits_new[num_waits_new++] = waits[i];
329            }
330        }
331    }
332
333    return OFFLOAD_OFFLOAD1(ofld, name, is_empty,
334                            num_vars, vars, vars2,
335                            num_waits_new, waits_new,
336                            signal_new);
337}
338
339extern "C" int OFFLOAD_CALL_COUNT()
340{
341    offload_call_count++;
342    return offload_call_count;
343}
344