summaryrefslogtreecommitdiff
path: root/liboffloadmic/runtime/offload_common.h
blob: 60b5045b9b560b24dbf71210cc3cb7abf43f4302 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
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
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
136
137
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
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
/*
    Copyright (c) 2014 Intel Corporation.  All Rights Reserved.

    Redistribution and use in source and binary forms, with or without
    modification, are permitted provided that the following conditions
    are met:

      * Redistributions of source code must retain the above copyright
        notice, this list of conditions and the following disclaimer.
      * Redistributions in binary form must reproduce the above copyright
        notice, this list of conditions and the following disclaimer in the
        documentation and/or other materials provided with the distribution.
      * Neither the name of Intel Corporation nor the names of its
        contributors may be used to endorse or promote products derived
        from this software without specific prior written permission.

    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
    A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
    HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
    SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
    LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
    DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
    THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
    (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
    OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/


/*! \file
    \brief The parts of the runtime library common to host and target
*/

#ifndef OFFLOAD_COMMON_H_INCLUDED
#define OFFLOAD_COMMON_H_INCLUDED

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>

#if (defined(LINUX) || defined(FREEBSD)) && !defined(__INTEL_COMPILER)
#include <mm_malloc.h>
#endif

#include "offload.h"
#include "offload_table.h"
#include "offload_trace.h"
#include "offload_timer.h"
#include "offload_util.h"
#include "cean_util.h"
#include "dv_util.h"
#include "liboffload_error_codes.h"

#include <stdarg.h>

// Use secure getenv if it's supported
#ifdef HAVE_SECURE_GETENV
  #define getenv(x)	    secure_getenv(x)
#elif HAVE___SECURE_GETENV
  #define getenv(x)	    __secure_getenv(x)
#endif

// The debug routines

// Host console and file logging
extern int console_enabled;
extern int offload_report_level;

#define OFFLOAD_DO_TRACE (offload_report_level == 3)

extern const char *prefix;
extern int offload_number;
#if !HOST_LIBRARY
extern int mic_index;
#endif

#if HOST_LIBRARY
void Offload_Report_Prolog(OffloadHostTimerData* timer_data);
void Offload_Report_Epilog(OffloadHostTimerData* timer_data);
void offload_report_free_data(OffloadHostTimerData * timer_data);
void Offload_Timer_Print(void);

#ifndef TARGET_WINNT
#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
        __sync_add_and_fetch(&offload_number, 1)
#else
#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
        _InterlockedIncrement(reinterpret_cast<long*>(&offload_number))
#endif

#define OFFLOAD_DEBUG_PRINT_TAG_PREFIX() \
        printf("%s:  ", prefix);

#define OFFLOAD_DEBUG_PRINT_PREFIX() \
        printf("%s:  ", prefix);
#else
#define OFFLOAD_DEBUG_PRINT_PREFIX() \
        printf("%s%d:  ", prefix, mic_index);
#endif // HOST_LIBRARY

#define OFFLOAD_TRACE(trace_level, ...)  \
    if (console_enabled >= trace_level) { \
        OFFLOAD_DEBUG_PRINT_PREFIX(); \
        printf(__VA_ARGS__); \
        fflush(NULL); \
    }

#if OFFLOAD_DEBUG > 0

#define OFFLOAD_DEBUG_TRACE(level, ...) \
    OFFLOAD_TRACE(level, __VA_ARGS__)

#define OFFLOAD_REPORT(level, offload_number, stage, ...) \
    if (OFFLOAD_DO_TRACE) { \
        offload_stage_print(stage, offload_number, __VA_ARGS__); \
        fflush(NULL); \
    }

#define OFFLOAD_DEBUG_TRACE_1(level, offload_number, stage, ...) \
    if (OFFLOAD_DO_TRACE) { \
        offload_stage_print(stage, offload_number, __VA_ARGS__); \
        fflush(NULL); \
    } \
    if (!OFFLOAD_DO_TRACE) { \
        OFFLOAD_TRACE(level, __VA_ARGS__) \
    }

#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b) \
    __dump_bytes(level, a, b)

extern void __dump_bytes(
    int level,
    const void *data,
    int len
);

#else

#define OFFLOAD_DEBUG_LOG(level, ...)
#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b)

#endif

// Runtime interface

#define OFFLOAD_PREFIX(a) __offload_##a

#define OFFLOAD_MALLOC            OFFLOAD_PREFIX(malloc)
#define OFFLOAD_FREE(a)           _mm_free(a)

// Forward functions

extern void *OFFLOAD_MALLOC(size_t size, size_t align);

// The Marshaller

//! \enum Indicator for the type of entry on an offload item list.
enum OffloadItemType {
    c_data =   1,       //!< Plain data
    c_data_ptr,         //!< Pointer data
    c_func_ptr,         //!< Function pointer
    c_void_ptr,         //!< void*
    c_string_ptr,       //!< C string
    c_dv,               //!< Dope vector variable
    c_dv_data,          //!< Dope-vector data
    c_dv_data_slice,    //!< Dope-vector data's slice
    c_dv_ptr,           //!< Dope-vector variable pointer
    c_dv_ptr_data,      //!< Dope-vector pointer data
    c_dv_ptr_data_slice,//!< Dope-vector pointer data's slice
    c_cean_var,         //!< CEAN variable
    c_cean_var_ptr,     //!< Pointer to CEAN variable
    c_data_ptr_array,   //!< Pointer to data pointer array
    c_func_ptr_array,   //!< Pointer to function pointer array
    c_void_ptr_array,   //!< Pointer to void* pointer array
    c_string_ptr_array  //!< Pointer to char* pointer array
};

#define VAR_TYPE_IS_PTR(t) ((t) == c_string_ptr || \
                            (t) == c_data_ptr || \
                            (t) == c_cean_var_ptr || \
                            (t) == c_dv_ptr)

#define VAR_TYPE_IS_SCALAR(t) ((t) == c_data || \
                               (t) == c_void_ptr || \
                               (t) == c_cean_var || \
                               (t) == c_dv)

#define VAR_TYPE_IS_DV_DATA(t) ((t) == c_dv_data || \
                                (t) == c_dv_ptr_data)

#define VAR_TYPE_IS_DV_DATA_SLICE(t) ((t) == c_dv_data_slice || \
                                      (t) == c_dv_ptr_data_slice)


//! \enum Specify direction to copy offloaded variable.
enum OffloadParameterType {
    c_parameter_unknown = -1, //!< Unknown clause
    c_parameter_nocopy,       //!< Variable listed in "nocopy" clause
    c_parameter_in,           //!< Variable listed in "in" clause
    c_parameter_out,          //!< Variable listed in "out" clause
    c_parameter_inout         //!< Variable listed in "inout" clause
};

//! An Offload Variable descriptor
struct VarDesc {
    //! OffloadItemTypes of source and destination
    union {
        struct {
            uint8_t dst : 4; //!< OffloadItemType of destination
            uint8_t src : 4; //!< OffloadItemType of source
        };
        uint8_t bits;
    } type;

    //! OffloadParameterType that describes direction of data transfer
    union {
        struct {
            uint8_t in  : 1; //!< Set if IN or INOUT
            uint8_t out : 1; //!< Set if OUT or INOUT
        };
        uint8_t bits;
    } direction;

    uint8_t alloc_if;        //!< alloc_if modifier value
    uint8_t free_if;         //!< free_if modifier value
    uint32_t align;          //!< MIC alignment requested for pointer data
    //! Not used by compiler; set to 0
    /*! Used by runtime as offset to data from start of MIC buffer */
    uint32_t mic_offset;
    //! Flags describing this variable
    union {
        struct {
            //! source variable has persistent storage
            uint32_t is_static : 1;
            //! destination variable has persistent storage
            uint32_t is_static_dstn : 1;
            //! has length for c_dv && c_dv_ptr
            uint32_t has_length : 1;
            //! persisted local scalar is in stack buffer
            uint32_t is_stack_buf : 1;
            //! buffer address is sent in data
            uint32_t sink_addr : 1;
            //! alloc displacement is sent in data
            uint32_t alloc_disp : 1;
            //! source data is noncontiguous
            uint32_t is_noncont_src : 1;
            //! destination data is noncontiguous
            uint32_t is_noncont_dst : 1;
        };
        uint32_t bits;
    } flags;
    //! Not used by compiler; set to 0
    /*! Used by runtime as offset to base from data stored in a buffer */
    int64_t offset;
    //! Element byte-size of data to be transferred
    /*! For dope-vector, the size of the dope-vector      */
    int64_t size;
    union {
        //! Set to 0 for array expressions and dope-vectors
        /*! Set to 1 for scalars                          */
        /*! Set to value of length modifier for pointers  */
        int64_t count;
        //! Displacement not used by compiler
        int64_t disp;
    };

    //! This field not used by OpenMP 4.0
    /*! The alloc section expression in #pragma offload   */
    union {
       void *alloc;
       int64_t ptr_arr_offset;
    };

    //! This field not used by OpenMP 4.0
    /*! The into section expression in #pragma offload    */
    /*! For c_data_ptr_array this is the into ptr array   */
    void *into;

    //! For an ordinary variable, address of the variable
    /*! For c_cean_var (C/C++ array expression),
        pointer to arr_desc, which is an array descriptor. */
    /*! For c_data_ptr_array (array of data pointers),
        pointer to ptr_array_descriptor,
        which is a descriptor for pointer array transfers. */
    void *ptr;
};

//! Auxiliary struct used when -g is enabled that holds variable names
struct VarDesc2 {
    const char *sname; //!< Source name
    const char *dname; //!< Destination name (when "into" is used)
};

/*! When the OffloadItemType is c_data_ptr_array
    the ptr field of the main descriptor points to this struct.          */
/*! The type in VarDesc1 merely says c_cean_data_ptr, but the pointer
    type can be c_data_ptr, c_func_ptr, c_void_ptr, or c_string_ptr.
    Therefore the actual pointer type is in the flags field of VarDesc3. */
/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
    is 0 then alignment/alloc_if/free_if are specified in VarDesc1.      */
/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
    is 1 then align_array/alloc_if_array/free_if_array specify
    the set of alignment/alloc_if/free_if values.                        */
/*! For the other fields, if neither the scalar nor the array flag
    is set, then that modifier was not specified. If the bits are set
    they specify which modifier was set and whether it was a
    scalar or an array expression.                                       */
struct VarDesc3
{
    void *ptr_array;        //!< Pointer to arr_desc of array of pointers
    void *align_array;      //!< Scalar value or pointer to arr_desc
    void *alloc_if_array;   //!< Scalar value or pointer to arr_desc
    void *free_if_array;    //!< Scalar value or pointer to arr_desc
    void *extent_start;     //!< Scalar value or pointer to arr_desc
    void *extent_elements;  //!< Scalar value or pointer to arr_desc
    void *into_start;       //!< Scalar value or pointer to arr_desc
    void *into_elements;    //!< Scalar value or pointer to arr_desc
    void *alloc_start;      //!< Scalar value or pointer to arr_desc
    void *alloc_elements;   //!< Scalar value or pointer to arr_desc
    /*! Flags that describe the pointer type and whether each field
        is a scalar value or an array expression.        */
    /*! First 6 bits are pointer array element type:
        c_data_ptr, c_func_ptr, c_void_ptr, c_string_ptr */
    /*! Then single bits specify:                        */
    /*!     align_array is an array                      */
    /*!     alloc_if_array is an array                   */
    /*!     free_if_array is an array                    */
    /*!     extent_start is a scalar expression          */
    /*!     extent_start is an array expression          */
    /*!     extent_elements is a scalar expression       */
    /*!     extent_elements is an array expression       */
    /*!     into_start is a scalar expression            */
    /*!     into_start is an array expression            */
    /*!     into_elements is a scalar expression         */
    /*!     into_elements is an array expression         */
    /*!     alloc_start is a scalar expression           */
    /*!     alloc_start is an array expression           */
    /*!     alloc_elements is a scalar expression        */
    /*!     alloc_elements is an array expression        */
    uint32_t array_fields;
};
const int flag_align_is_array = 6;
const int flag_alloc_if_is_array = 7;
const int flag_free_if_is_array = 8;
const int flag_extent_start_is_scalar = 9;
const int flag_extent_start_is_array = 10;
const int flag_extent_elements_is_scalar = 11;
const int flag_extent_elements_is_array = 12;
const int flag_into_start_is_scalar = 13;
const int flag_into_start_is_array = 14;
const int flag_into_elements_is_scalar = 15;
const int flag_into_elements_is_array = 16;
const int flag_alloc_start_is_scalar = 17;
const int flag_alloc_start_is_array = 18;
const int flag_alloc_elements_is_scalar = 19;
const int flag_alloc_elements_is_array = 20;

// The Marshaller
class Marshaller
{
private:
    // Start address of buffer
    char *buffer_start;

    // Current pointer within buffer
    char *buffer_ptr;

    // Physical size of data sent (including flags)
    long long buffer_size;

    // User data sent/received
    long long tfr_size;

public:
    // Constructor
    Marshaller() :
        buffer_start(0), buffer_ptr(0),
        buffer_size(0), tfr_size(0)
    {
    }

    // Return count of user data sent/received
    long long get_tfr_size() const
    {
        return tfr_size;
    }

    // Return pointer to buffer
    char *get_buffer_start() const
    {
        return buffer_start;
    }

    // Return current size of data in buffer
    long long get_buffer_size() const
    {
        return buffer_size;
    }

    // Set buffer pointer
    void init_buffer(
        char *d,
        long long s
    )
    {
        buffer_start = buffer_ptr = d;
        buffer_size = s;
    }

    // Send data
    void send_data(
        const void *data,
        int64_t length
    );

    // Receive data
    void receive_data(
        void *data,
        int64_t length
    );

    // Send function pointer
    void send_func_ptr(
        const void* data
    );

    // Receive function pointer
    void receive_func_ptr(
        const void** data
    );
};

// End of the Marshaller

// The offloaded function descriptor.
// Sent from host to target to specify which function to run.
// Also, sets console and file tracing levels.
struct FunctionDescriptor
{
    // Input data size.
    long long in_datalen;

    // Output data size.
    long long out_datalen;

    // Whether trace is requested on console.
    // A value of 1 produces only function name and data sent/received.
    // Values > 1 produce copious trace information.
    uint8_t console_enabled;

    // Flag controlling timing on the target side.
    // Values > 0 enable timing on sink.
    uint8_t timer_enabled;

    int offload_report_level;
    int offload_number;

    // number of variable descriptors
    int vars_num;

    // inout data offset if data is passed as misc/return data
    // otherwise it should be zero.
    int data_offset;

    // The name of the offloaded function
    char data[];
};

// typedef OFFLOAD.
// Pointer to OffloadDescriptor.
typedef struct OffloadDescriptor *OFFLOAD;

#endif // OFFLOAD_COMMON_H_INCLUDED