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/*! \file
32    \brief The parts of the runtime library common to host and target
33*/
34
35#ifndef OFFLOAD_COMMON_H_INCLUDED
36#define OFFLOAD_COMMON_H_INCLUDED
37
38#include <stdio.h>
39#include <stdlib.h>
40#include <string.h>
41#include <memory.h>
42
43#if (defined(LINUX) || defined(FREEBSD)) && !defined(__INTEL_COMPILER)
44#include <mm_malloc.h>
45#endif
46
47#include "offload.h"
48#include "offload_table.h"
49#include "offload_trace.h"
50#include "offload_timer.h"
51#include "offload_util.h"
52#include "cean_util.h"
53#include "dv_util.h"
54#include "liboffload_error_codes.h"
55
56#include <stdarg.h>
57
58// Use secure getenv if it's supported
59#ifdef HAVE_SECURE_GETENV
60  #define getenv(x)	    secure_getenv(x)
61#elif HAVE___SECURE_GETENV
62  #define getenv(x)	    __secure_getenv(x)
63#endif
64
65// The debug routines
66
67// Host console and file logging
68extern int console_enabled;
69extern int offload_report_level;
70
71#define OFFLOAD_DO_TRACE (offload_report_level == 3)
72
73extern const char *prefix;
74extern int offload_number;
75#if !HOST_LIBRARY
76extern int mic_index;
77#endif
78
79#if HOST_LIBRARY
80void Offload_Report_Prolog(OffloadHostTimerData* timer_data);
81void Offload_Report_Epilog(OffloadHostTimerData* timer_data);
82void offload_report_free_data(OffloadHostTimerData * timer_data);
83void Offload_Timer_Print(void);
84
85#ifndef TARGET_WINNT
86#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
87        __sync_add_and_fetch(&offload_number, 1)
88#else
89#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
90        _InterlockedIncrement(reinterpret_cast<long*>(&offload_number))
91#endif
92
93#define OFFLOAD_DEBUG_PRINT_TAG_PREFIX() \
94        printf("%s:  ", prefix);
95
96#define OFFLOAD_DEBUG_PRINT_PREFIX() \
97        printf("%s:  ", prefix);
98#else
99#define OFFLOAD_DEBUG_PRINT_PREFIX() \
100        printf("%s%d:  ", prefix, mic_index);
101#endif // HOST_LIBRARY
102
103#define OFFLOAD_TRACE(trace_level, ...)  \
104    if (console_enabled >= trace_level) { \
105        OFFLOAD_DEBUG_PRINT_PREFIX(); \
106        printf(__VA_ARGS__); \
107        fflush(NULL); \
108    }
109
110#if OFFLOAD_DEBUG > 0
111
112#define OFFLOAD_DEBUG_TRACE(level, ...) \
113    OFFLOAD_TRACE(level, __VA_ARGS__)
114
115#define OFFLOAD_REPORT(level, offload_number, stage, ...) \
116    if (OFFLOAD_DO_TRACE) { \
117        offload_stage_print(stage, offload_number, __VA_ARGS__); \
118        fflush(NULL); \
119    }
120
121#define OFFLOAD_DEBUG_TRACE_1(level, offload_number, stage, ...) \
122    if (OFFLOAD_DO_TRACE) { \
123        offload_stage_print(stage, offload_number, __VA_ARGS__); \
124        fflush(NULL); \
125    } \
126    if (!OFFLOAD_DO_TRACE) { \
127        OFFLOAD_TRACE(level, __VA_ARGS__) \
128    }
129
130#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b) \
131    __dump_bytes(level, a, b)
132
133extern void __dump_bytes(
134    int level,
135    const void *data,
136    int len
137);
138
139#else
140
141#define OFFLOAD_DEBUG_LOG(level, ...)
142#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b)
143
144#endif
145
146// Runtime interface
147
148#define OFFLOAD_PREFIX(a) __offload_##a
149
150#define OFFLOAD_MALLOC            OFFLOAD_PREFIX(malloc)
151#define OFFLOAD_FREE(a)           _mm_free(a)
152
153// Forward functions
154
155extern void *OFFLOAD_MALLOC(size_t size, size_t align);
156
157// The Marshaller
158
159//! \enum Indicator for the type of entry on an offload item list.
160enum OffloadItemType {
161    c_data =   1,       //!< Plain data
162    c_data_ptr,         //!< Pointer data
163    c_func_ptr,         //!< Function pointer
164    c_void_ptr,         //!< void*
165    c_string_ptr,       //!< C string
166    c_dv,               //!< Dope vector variable
167    c_dv_data,          //!< Dope-vector data
168    c_dv_data_slice,    //!< Dope-vector data's slice
169    c_dv_ptr,           //!< Dope-vector variable pointer
170    c_dv_ptr_data,      //!< Dope-vector pointer data
171    c_dv_ptr_data_slice,//!< Dope-vector pointer data's slice
172    c_cean_var,         //!< CEAN variable
173    c_cean_var_ptr,     //!< Pointer to CEAN variable
174    c_data_ptr_array,   //!< Pointer to data pointer array
175    c_func_ptr_array,   //!< Pointer to function pointer array
176    c_void_ptr_array,   //!< Pointer to void* pointer array
177    c_string_ptr_array  //!< Pointer to char* pointer array
178};
179
180#define VAR_TYPE_IS_PTR(t) ((t) == c_string_ptr || \
181                            (t) == c_data_ptr || \
182                            (t) == c_cean_var_ptr || \
183                            (t) == c_dv_ptr)
184
185#define VAR_TYPE_IS_SCALAR(t) ((t) == c_data || \
186                               (t) == c_void_ptr || \
187                               (t) == c_cean_var || \
188                               (t) == c_dv)
189
190#define VAR_TYPE_IS_DV_DATA(t) ((t) == c_dv_data || \
191                                (t) == c_dv_ptr_data)
192
193#define VAR_TYPE_IS_DV_DATA_SLICE(t) ((t) == c_dv_data_slice || \
194                                      (t) == c_dv_ptr_data_slice)
195
196
197//! \enum Specify direction to copy offloaded variable.
198enum OffloadParameterType {
199    c_parameter_unknown = -1, //!< Unknown clause
200    c_parameter_nocopy,       //!< Variable listed in "nocopy" clause
201    c_parameter_in,           //!< Variable listed in "in" clause
202    c_parameter_out,          //!< Variable listed in "out" clause
203    c_parameter_inout         //!< Variable listed in "inout" clause
204};
205
206//! An Offload Variable descriptor
207struct VarDesc {
208    //! OffloadItemTypes of source and destination
209    union {
210        struct {
211            uint8_t dst : 4; //!< OffloadItemType of destination
212            uint8_t src : 4; //!< OffloadItemType of source
213        };
214        uint8_t bits;
215    } type;
216
217    //! OffloadParameterType that describes direction of data transfer
218    union {
219        struct {
220            uint8_t in  : 1; //!< Set if IN or INOUT
221            uint8_t out : 1; //!< Set if OUT or INOUT
222        };
223        uint8_t bits;
224    } direction;
225
226    uint8_t alloc_if;        //!< alloc_if modifier value
227    uint8_t free_if;         //!< free_if modifier value
228    uint32_t align;          //!< MIC alignment requested for pointer data
229    //! Not used by compiler; set to 0
230    /*! Used by runtime as offset to data from start of MIC buffer */
231    uint32_t mic_offset;
232    //! Flags describing this variable
233    union {
234        struct {
235            //! source variable has persistent storage
236            uint32_t is_static : 1;
237            //! destination variable has persistent storage
238            uint32_t is_static_dstn : 1;
239            //! has length for c_dv && c_dv_ptr
240            uint32_t has_length : 1;
241            //! persisted local scalar is in stack buffer
242            uint32_t is_stack_buf : 1;
243            //! buffer address is sent in data
244            uint32_t sink_addr : 1;
245            //! alloc displacement is sent in data
246            uint32_t alloc_disp : 1;
247            //! source data is noncontiguous
248            uint32_t is_noncont_src : 1;
249            //! destination data is noncontiguous
250            uint32_t is_noncont_dst : 1;
251        };
252        uint32_t bits;
253    } flags;
254    //! Not used by compiler; set to 0
255    /*! Used by runtime as offset to base from data stored in a buffer */
256    int64_t offset;
257    //! Element byte-size of data to be transferred
258    /*! For dope-vector, the size of the dope-vector      */
259    int64_t size;
260    union {
261        //! Set to 0 for array expressions and dope-vectors
262        /*! Set to 1 for scalars                          */
263        /*! Set to value of length modifier for pointers  */
264        int64_t count;
265        //! Displacement not used by compiler
266        int64_t disp;
267    };
268
269    //! This field not used by OpenMP 4.0
270    /*! The alloc section expression in #pragma offload   */
271    union {
272       void *alloc;
273       int64_t ptr_arr_offset;
274    };
275
276    //! This field not used by OpenMP 4.0
277    /*! The into section expression in #pragma offload    */
278    /*! For c_data_ptr_array this is the into ptr array   */
279    void *into;
280
281    //! For an ordinary variable, address of the variable
282    /*! For c_cean_var (C/C++ array expression),
283        pointer to arr_desc, which is an array descriptor. */
284    /*! For c_data_ptr_array (array of data pointers),
285        pointer to ptr_array_descriptor,
286        which is a descriptor for pointer array transfers. */
287    void *ptr;
288};
289
290//! Auxiliary struct used when -g is enabled that holds variable names
291struct VarDesc2 {
292    const char *sname; //!< Source name
293    const char *dname; //!< Destination name (when "into" is used)
294};
295
296/*! When the OffloadItemType is c_data_ptr_array
297    the ptr field of the main descriptor points to this struct.          */
298/*! The type in VarDesc1 merely says c_cean_data_ptr, but the pointer
299    type can be c_data_ptr, c_func_ptr, c_void_ptr, or c_string_ptr.
300    Therefore the actual pointer type is in the flags field of VarDesc3. */
301/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
302    is 0 then alignment/alloc_if/free_if are specified in VarDesc1.      */
303/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
304    is 1 then align_array/alloc_if_array/free_if_array specify
305    the set of alignment/alloc_if/free_if values.                        */
306/*! For the other fields, if neither the scalar nor the array flag
307    is set, then that modifier was not specified. If the bits are set
308    they specify which modifier was set and whether it was a
309    scalar or an array expression.                                       */
310struct VarDesc3
311{
312    void *ptr_array;        //!< Pointer to arr_desc of array of pointers
313    void *align_array;      //!< Scalar value or pointer to arr_desc
314    void *alloc_if_array;   //!< Scalar value or pointer to arr_desc
315    void *free_if_array;    //!< Scalar value or pointer to arr_desc
316    void *extent_start;     //!< Scalar value or pointer to arr_desc
317    void *extent_elements;  //!< Scalar value or pointer to arr_desc
318    void *into_start;       //!< Scalar value or pointer to arr_desc
319    void *into_elements;    //!< Scalar value or pointer to arr_desc
320    void *alloc_start;      //!< Scalar value or pointer to arr_desc
321    void *alloc_elements;   //!< Scalar value or pointer to arr_desc
322    /*! Flags that describe the pointer type and whether each field
323        is a scalar value or an array expression.        */
324    /*! First 6 bits are pointer array element type:
325        c_data_ptr, c_func_ptr, c_void_ptr, c_string_ptr */
326    /*! Then single bits specify:                        */
327    /*!     align_array is an array                      */
328    /*!     alloc_if_array is an array                   */
329    /*!     free_if_array is an array                    */
330    /*!     extent_start is a scalar expression          */
331    /*!     extent_start is an array expression          */
332    /*!     extent_elements is a scalar expression       */
333    /*!     extent_elements is an array expression       */
334    /*!     into_start is a scalar expression            */
335    /*!     into_start is an array expression            */
336    /*!     into_elements is a scalar expression         */
337    /*!     into_elements is an array expression         */
338    /*!     alloc_start is a scalar expression           */
339    /*!     alloc_start is an array expression           */
340    /*!     alloc_elements is a scalar expression        */
341    /*!     alloc_elements is an array expression        */
342    uint32_t array_fields;
343};
344const int flag_align_is_array = 6;
345const int flag_alloc_if_is_array = 7;
346const int flag_free_if_is_array = 8;
347const int flag_extent_start_is_scalar = 9;
348const int flag_extent_start_is_array = 10;
349const int flag_extent_elements_is_scalar = 11;
350const int flag_extent_elements_is_array = 12;
351const int flag_into_start_is_scalar = 13;
352const int flag_into_start_is_array = 14;
353const int flag_into_elements_is_scalar = 15;
354const int flag_into_elements_is_array = 16;
355const int flag_alloc_start_is_scalar = 17;
356const int flag_alloc_start_is_array = 18;
357const int flag_alloc_elements_is_scalar = 19;
358const int flag_alloc_elements_is_array = 20;
359
360// The Marshaller
361class Marshaller
362{
363private:
364    // Start address of buffer
365    char *buffer_start;
366
367    // Current pointer within buffer
368    char *buffer_ptr;
369
370    // Physical size of data sent (including flags)
371    long long buffer_size;
372
373    // User data sent/received
374    long long tfr_size;
375
376public:
377    // Constructor
378    Marshaller() :
379        buffer_start(0), buffer_ptr(0),
380        buffer_size(0), tfr_size(0)
381    {
382    }
383
384    // Return count of user data sent/received
385    long long get_tfr_size() const
386    {
387        return tfr_size;
388    }
389
390    // Return pointer to buffer
391    char *get_buffer_start() const
392    {
393        return buffer_start;
394    }
395
396    // Return current size of data in buffer
397    long long get_buffer_size() const
398    {
399        return buffer_size;
400    }
401
402    // Set buffer pointer
403    void init_buffer(
404        char *d,
405        long long s
406    )
407    {
408        buffer_start = buffer_ptr = d;
409        buffer_size = s;
410    }
411
412    // Send data
413    void send_data(
414        const void *data,
415        int64_t length
416    );
417
418    // Receive data
419    void receive_data(
420        void *data,
421        int64_t length
422    );
423
424    // Send function pointer
425    void send_func_ptr(
426        const void* data
427    );
428
429    // Receive function pointer
430    void receive_func_ptr(
431        const void** data
432    );
433};
434
435// End of the Marshaller
436
437// The offloaded function descriptor.
438// Sent from host to target to specify which function to run.
439// Also, sets console and file tracing levels.
440struct FunctionDescriptor
441{
442    // Input data size.
443    long long in_datalen;
444
445    // Output data size.
446    long long out_datalen;
447
448    // Whether trace is requested on console.
449    // A value of 1 produces only function name and data sent/received.
450    // Values > 1 produce copious trace information.
451    uint8_t console_enabled;
452
453    // Flag controlling timing on the target side.
454    // Values > 0 enable timing on sink.
455    uint8_t timer_enabled;
456
457    int offload_report_level;
458    int offload_number;
459
460    // number of variable descriptors
461    int vars_num;
462
463    // inout data offset if data is passed as misc/return data
464    // otherwise it should be zero.
465    int data_offset;
466
467    // The name of the offloaded function
468    char data[];
469};
470
471// typedef OFFLOAD.
472// Pointer to OffloadDescriptor.
473typedef struct OffloadDescriptor *OFFLOAD;
474
475#endif // OFFLOAD_COMMON_H_INCLUDED
476