| /* | 
 |     Copyright (c) 2014-2016 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> | 
 |  | 
 | #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 | 
 |  | 
 | // Offload Library versioning | 
 | DLL_LOCAL extern int offload_version; | 
 | DLL_LOCAL extern int offload_version_count; | 
 |  | 
 | // The debug routines | 
 |  | 
 | // Host console and file logging | 
 | DLL_LOCAL extern int console_enabled; | 
 | DLL_LOCAL extern int offload_report_level; | 
 |  | 
 |  | 
 | DLL_LOCAL extern const char *prefix; | 
 | DLL_LOCAL extern int offload_number; | 
 | #if !HOST_LIBRARY | 
 | DLL_LOCAL extern int mic_index; | 
 | #define OFFLOAD_DO_TRACE (offload_report_level == 3) | 
 | #else | 
 | #define OFFLOAD_DO_TRACE (offload_report_enabled && (offload_report_level == 3)) | 
 | #endif | 
 |  | 
 | #if HOST_LIBRARY | 
 | DLL_LOCAL void Offload_Report_Prolog(OffloadHostTimerData* timer_data); | 
 | DLL_LOCAL void Offload_Report_Epilog(OffloadHostTimerData* timer_data); | 
 | DLL_LOCAL void offload_report_free_data(OffloadHostTimerData * timer_data); | 
 | DLL_LOCAL 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) | 
 |  | 
 | DLL_LOCAL 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 | 
 |  | 
 | // Flags describing an offload | 
 |  | 
 | //! Flags describing an offload | 
 | union OffloadFlags{ | 
 |     uint32_t flags; | 
 |     struct { | 
 |         uint32_t fortran_traceback : 1; //!< Fortran traceback requested | 
 |         uint32_t omp_async         : 1; //!< OpenMP asynchronous offload | 
 |     } bits; | 
 | }; | 
 |  | 
 | //! \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_extended_type,    //!< Is used to extend OffloadItemType | 
 |                         //!< Actual OffloadItemType is in the | 
 |                         //!< structure VarDescExtendedType | 
 |     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 | 
 |     c_data_ptr_ptr,     //!< Pointer to pointer to data (struct member) | 
 |     c_func_ptr_ptr,     //!< Pointer to pointer to function (struct member) | 
 |     c_void_ptr_ptr,     //!< Pointer to pointer to void* (struct member) | 
 |     c_string_ptr_ptr,   //!< Pointer to pointer to string (struct member) | 
 |     c_cean_var_ptr_ptr  //!< Pointer to pointer to cean var (struct member) | 
 | }; | 
 |  | 
 | #define TYPE_IS_PTR_TO_PTR(t) ((t) == c_string_ptr_ptr || \ | 
 |                             (t) == c_data_ptr_ptr || \ | 
 |                             (t) == c_func_ptr_ptr || \ | 
 |                             (t) == c_void_ptr_ptr || \ | 
 |                             (t) == c_cean_var_ptr_ptr) | 
 |  | 
 | #define VAR_TYPE_IS_PTR(t) ((t) == c_string_ptr || \ | 
 |                             (t) == c_data_ptr || \ | 
 |                             (t) == c_cean_var_ptr || \ | 
 |                             (t) == c_dv_ptr || \ | 
 |                             TYPE_IS_PTR_TO_PTR(t)) | 
 |  | 
 | #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 | 
 | }; | 
 |  | 
 |  | 
 | //! Flags describing an offloaded variable | 
 | union varDescFlags { | 
 |     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; | 
 |         //! "targetptr" modifier used | 
 |         uint32_t targetptr : 1; | 
 |         //! "preallocated" modifier used | 
 |         uint32_t preallocated : 1; | 
 |         //! pointer to a pointer array | 
 |         uint32_t is_pointer : 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; | 
 |  | 
 |         //! "OpenMP always" modifier used | 
 |         uint32_t always_copy : 1; | 
 |         //! "OpenMP delete" modifier used | 
 |         uint32_t always_delete : 1; | 
 |         //! structured data is noncontiguous | 
 |         uint32_t is_non_cont_struct : 1; | 
 |         //! CPU memory pinning/unpinning operation | 
 |         uint32_t pin : 1; | 
 |         //! Pointer to device memory | 
 |         uint32_t is_device_ptr : 1;     | 
 |         //! Hostpointer with associated device pointer | 
 |         uint32_t use_device_ptr : 1; | 
 |     }; | 
 |     uint32_t bits; | 
 | }; | 
 |  | 
 | //! 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 | 
 |     varDescFlags 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; | 
 |  | 
 | //! Extended Variable Descriptor.  Since VarDesc uses 16 bits for | 
 | //! OffloadItemType, we have exceeded that limit,  So any Type  | 
 | //! greater than 15 will have Type set in VarDesc as c_extended_type | 
 | //! and this structure will be used to represent those Types. | 
 | typedef struct VarDescExtendedType { | 
 |  | 
 |     // Represents overflow of OffloadItemType | 
 |     uint32_t extended_type;  | 
 |  | 
 |     //! For extended_type  | 
 |     //! address of the variable | 
 |     //! Future Types can point to other descriptors | 
 |     void *ptr;    | 
 | } VarDescExtendedType; | 
 |  | 
 | // 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; | 
 |  | 
 | // Use for setting affinity of a stream | 
 | enum affinity_type { | 
 |     affinity_compact, | 
 |     affinity_scatter | 
 | }; | 
 | struct affinity_spec { | 
 |     uint64_t sink_mask[16]; | 
 |     int affinity_type; | 
 |     int num_cores; | 
 |     int num_threads; | 
 | }; | 
 |  | 
 | #endif // OFFLOAD_COMMON_H_INCLUDED |