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