/* * Copyright (c) 2014-2021 Intel, Inc. All rights reserved. * Copyright (c) 2015 Los Alamos National Security, LLC. All rights * reserved. * Copyright (c) Amazon.com, Inc. or its affiliates. * All Rights reserved. * $COPYRIGHT$ * * Additional copyrights may follow * * $HEADER$ */ /** * @file * Accelerator Framework * * Accelerator initialization and selection: * * During opal initialization, all available accelerator components * will be attempted to be initialized. Only the null component and * at most, one other component are expected to succeed initialization * or we will abort the accelerator initialization process. * * The framework selection function will set the global opal_accelerator * module to allow usage of the accelerator API. * * * Transfer types: * * There are five transfer types that can be passed to memory copy functions. * They are defined in the enum, opal_accelerator_transfer_type_t: * * UNSPEC - Not specified * HTOH - Host to Host * HTOD - Host to Device * DTOH - Device to Host * DTOD - Device to Device * * The UNSPEC transfer type should be used when the detection of buffer types * will be deferred to the implementation. For certain optimizations, the caller * may pass the transfer type to the memory copying functions. * * * Streams and Events: * * A stream is a sequence of operations that execute on the device in the order * in which they are issued by the host code. A single stream guarantees execution * in order, but multiple streams may have interleaved or concurrent execution. * * An event is a synchronization marker that can be used to monitor the device's * progress. They can be appended to a stream through the record_event api. * The event can then be queried for completion through the query_event api. * * For a more brute force method of synchronization, the synchronize_stream api * was added which will wait until all operations on the stream are completed * before progressing. * * * Asynchronous copies: * * Asynchronous copies are appended to a stream using the memcpy_async api. * A subsequent event can be appended to the stream for querying. * There is currently no callback functionality for asynchronous copy completion, * and thus asynchronous copy completions must be progressed manually. * * * Host register/unregister: * * Host register page-locks host register and informs the device. This allows * the device to perform fast operations using DMA (direct memory access) which * can increase the performance of certain memory copies. * */ #ifndef OPAL_ACCELERATOR_H #define OPAL_ACCELERATOR_H #include "opal/class/opal_object.h" #include "opal/mca/mca.h" BEGIN_C_DECLS #define MCA_ACCELERATOR_NO_DEVICE_ID -1 /** * Accelerator flags */ /* Unified memory buffers */ #define MCA_ACCELERATOR_FLAGS_UNIFIED_MEMORY 0x00000001 /** * Transfer types. * UNSPEC - Not specified * HTOH - Host to Host * HTOD - Host to Device * DTOH - Device to Host * DTOD - Device to Device */ typedef enum { MCA_ACCELERATOR_TRANSFER_UNSPEC = 0, MCA_ACCELERATOR_TRANSFER_HTOH, MCA_ACCELERATOR_TRANSFER_HTOD, MCA_ACCELERATOR_TRANSFER_DTOH, MCA_ACCELERATOR_TRANSFER_DTOD, } opal_accelerator_transfer_type_t; typedef uint64_t opal_accelerator_buffer_id_t; struct opal_accelerator_stream_t { opal_object_t super; /* Stream object */ void *stream; }; typedef struct opal_accelerator_stream_t opal_accelerator_stream_t; struct opal_accelerator_pci_attr_t { uint16_t domain_id; uint8_t bus_id; uint8_t device_id; uint8_t function_id; }; typedef struct opal_accelerator_pci_attr_t opal_accelerator_pci_attr_t; OBJ_CLASS_DECLARATION(opal_accelerator_stream_t); struct opal_accelerator_event_t { opal_object_t super; /* Event object */ void *event; }; typedef struct opal_accelerator_event_t opal_accelerator_event_t; OBJ_CLASS_DECLARATION(opal_accelerator_event_t); /** * Check whether a pointer belongs to an accelerator or not. * interfaces * * @param[IN] addr Pointer to check * @param[OUT] dev_id Returns the device id against which the memory was allocated * or MCA_ACCELERATOR_NO_DEVICE_ID * @param[OUT] flags Set to 0 or an Accelerator flag to indicate additional * information about the corresponding pointer * * @retval <0 An error has occurred. * @retval 0 The buffer does not belong to a managed buffer * in device memory. * @retval >0 The buffer belongs to a managed buffer in * device memory. */ typedef int (*opal_accelerator_base_module_check_addr_fn_t)( const void *addr, int *dev_id, uint64_t *flags); /** * Creates a stream for asynchonous operations. This function will allocate * memory for the object. To release the memory, call OBJ_RELEASE(*stream); * * @param[IN] dev_id Associated device for the stream or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] stream Stream to create * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_create_stream_fn_t)( int dev_id, opal_accelerator_stream_t **stream); /** * Creates an event. An event is a synchronization marker that can be * appended to a stream to monitor device progress or synchronize the * corresponding stream. This function will allocate memory for the object. * To release the memory, call OBJ_RELEASE(*event); * * @param[IN] dev_id Associated device for the event or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] event Event to create * * @return OPAL_SUCCESS or error status on failure. */ typedef int (*opal_accelerator_base_module_create_event_fn_t)( int dev_id, opal_accelerator_event_t **event); /** * Records an event on a stream. An event recorded on the stream is * a synchronization marker that can be used to monitor the device's * progress or to synchronize the corresponding stream. This API appends * the given event onto the given stream. * * @param[IN] dev_id Associated device for the event or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] event Event to record * @param[IN] stream Stream to record event for * * @return OPAL_SUCCESS or error status on failure. */ typedef int (*opal_accelerator_base_module_record_event_fn_t)( int dev_id, opal_accelerator_event_t *event, opal_accelerator_stream_t *stream); /** * Queries an event's status. This can be used to monitor the device * progress, as events placed on the stream execute in order. * * @param[IN] dev_id Associated device for the event or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] event Event to query * * @return OPAL_SUCCESS on event completion, OPAL_ERROR on error, * or OPAL_ERR_RESOURCE_BUSY if any work is incomplete. */ typedef int (*opal_accelerator_base_module_query_event_fn_t)( int dev_id, opal_accelerator_event_t *event); /** * Copies memory asynchronously from src to dest. Memory of dest and src * may not overlap. Optionally can specify the transfer type to * avoid pointer detection for performance. * * @param[IN] dest_dev_id Associated device to copy to or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] src_dev_id Associated device to copy from or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] dest Destination to copy memory to * @param[IN] src Source to copy memory from * @param[IN] size Size of memory to copy * @param[IN] stream Stream to perform asynchronous copy on * @param[IN] type Transfer type field for performance * Can be set to MCA_ACCELERATOR_TRANSFER_UNSPEC * if caller is unsure of the transfer direction. * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_memcpy_async_fn_t)( int dest_dev_id, int src_dev_id, void *dest, const void *src, size_t size, opal_accelerator_stream_t *stream, opal_accelerator_transfer_type_t type); /** * Copies memory synchronously from src to dest. Memory of dest and src * may not overlap. Optionally can specify the transfer type to * avoid pointer detection for performance. * * @param[IN] dest_dev_id Associated device to copy to or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] src_dev_id Associated device to copy from or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] dest Destination to copy memory to * @param[IN] src Source to copy memory from * @param[IN] size Size of memory to copy * @param[IN] type Transfer type field for performance * Can be set to MCA_ACCELERATOR_TRANSFER_UNSPEC * if caller is unsure of the transfer direction. * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_memcpy_fn_t)( int dest_dev_id, int src_dev_id, void *dest, const void *src, size_t size, opal_accelerator_transfer_type_t type); /** * Copies memory synchronously from src to dest. Memory of dest and src * may overlap. Optionally can specify the transfer type to * avoid pointer detection for performance. * * @param[IN] dest_dev_id Associated device to copy to or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] src_dev_id Associated device to copy from or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] dest Destination to copy memory to * @param[IN] src Source to copy memory from * @param[IN] size Size of memory to copy * @param[IN] type Transfer type field for performance * Can be set to MCA_ACCELERATOR_TRANSFER_UNSPEC * if caller is unsure of the transfer direction. * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_memmove_fn_t)( int dest_dev_id, int src_dev_id, void *dest, const void *src, size_t size, opal_accelerator_transfer_type_t type); /** * Allocates size bytes memory from the device and sets ptr to the * pointer of the allocated memory. The memory is not initialized. * * @param[IN] dev_id Associated device for the allocation or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[OUT] ptr Returns pointer to allocated memory * @param[IN] size Size of memory to allocate * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_mem_alloc_fn_t)( int dev_id, void **ptr, size_t size); /** * Frees the memory space pointed to by ptr which has been returned by * a previous call to an opal_accelerator_base_module_mem_alloc_fn_t(). * If the function is called on a ptr that has already been freed, * undefined behavior occurs. If ptr is NULL, no operation is performed, * and the function returns OPAL_SUCCESS. * * @param[IN] dev_id Associated device for the allocation or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] ptr Pointer to free * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_mem_release_fn_t)( int dev_id, void *ptr); /** * Retrieves the base address and/or size of a memory allocation of the * device. * * @param[IN] dev_id Associated device for the allocation or * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] ptr Pointer to device memory to get base/size from * @param[OUT] base Base address of the memory allocation * @param[OUT] size Size of the memory allocation * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_get_address_range_fn_t)( int dev_id, const void *ptr, void **base, size_t *size); /** * Page-locks the memory range specified by ptr and size * * @param[IN] dev_id Associated device to register host memory with * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] ptr Host pointer to memory to page-lock * @param[IN] size Size in bytes of the address range to page-lock in bytes * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_host_register_fn_t)( int dev_id, void *ptr, size_t size); /** * Unregisters a memory range that was registered with * opal_accelerator_base_module_host_register_fn_t. * * @param[IN] dev_id Associated device to deregister host memory with * MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] ptr Host pointer to memory to unregister * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_host_unregister_fn_t)( int dev_id, void *ptr); /** * Retrieves current device id for a device associated with the local process. * If MCA_ACCELERATOR_NO_DEVICE_ID is provided, there is no device/process pairing. * * @param[OUT] dev_id ID of the device or MCA_ACCELERATOR_NO_DEVICE_ID * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_get_device_fn_t)( int *dev_id); /** * Retrieves PCI attributes of an accelerator device. * * @param[int] dev_id Accelerator device id * @param[out] pci_attr PCI attributes of the requested device * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_get_device_pci_attr_fn_t)( int dev_id, opal_accelerator_pci_attr_t *pci_attr); /** * Queries if a device may directly access a peer device's memory. * * @param[OUT] access Returns 1 if dev1 can directly access memory on dev2 * Returns 0 if dev1 can not directly access memory on dev2 * @param[IN] dev1 ID of device checking if peer device memory can be accessed * @param[IN] dev2 ID of peer device on which the memory allocations * reside. * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_device_can_access_peer_fn_t)( int *access, int dev1, int dev2); /** * Retrieves current device id for a device associated with the local process. * If MCA_ACCELERATOR_NO_DEVICE_ID is provided, there is no device/process pairing. * * @param[IN] dev_id ID of the device or MCA_ACCELERATOR_NO_DEVICE_ID * @param[IN] addr Buffer pointer to check * @param[OUT] buf_id ID of the given buffer * * * @return OPAL_SUCCESS or error status on failure */ typedef int (*opal_accelerator_base_module_get_buffer_id_fn_t)( int dev_id, const void *addr, opal_accelerator_buffer_id_t *buf_id); /* * the standard public API data structure */ typedef struct { /* accelerator function table */ opal_accelerator_base_module_check_addr_fn_t check_addr; opal_accelerator_base_module_create_stream_fn_t create_stream; opal_accelerator_base_module_create_event_fn_t create_event; opal_accelerator_base_module_record_event_fn_t record_event; opal_accelerator_base_module_query_event_fn_t query_event; opal_accelerator_base_module_memcpy_async_fn_t mem_copy_async; opal_accelerator_base_module_memcpy_fn_t mem_copy; opal_accelerator_base_module_memmove_fn_t mem_move; opal_accelerator_base_module_mem_alloc_fn_t mem_alloc; opal_accelerator_base_module_mem_release_fn_t mem_release; opal_accelerator_base_module_get_address_range_fn_t get_address_range; opal_accelerator_base_module_host_register_fn_t host_register; opal_accelerator_base_module_host_unregister_fn_t host_unregister; opal_accelerator_base_module_get_device_fn_t get_device; opal_accelerator_base_module_get_device_pci_attr_fn_t get_device_pci_attr; opal_accelerator_base_module_device_can_access_peer_fn_t device_can_access_peer; opal_accelerator_base_module_get_buffer_id_fn_t get_buffer_id; } opal_accelerator_base_module_t; /** * Accelerator component initialization. * Called by MCA framework to initialize the component. * * This should initialize any component level data. * * This should discover accelerators that are available. * We assume that only one accelerator will be present * on any given node. * * @return Initialized module or NULL if init failed. */ typedef opal_accelerator_base_module_t * (*mca_accelerator_base_component_init_fn_t)(void); /** * Accelerator component finalization * Called by MCA framework to finalize the component. * * This should finalize the given accelerator component. * Any component level data should be cleaned up, including * any allocated during component_init() and data created * during the lifetime of the component, including outstanding * modules. * * @param[IN] module If the component performed allocation within * the module, allow the component the to perform * the required cleanup * * No return since error will likely be ignored anyway. */ typedef void (*mca_accelerator_base_component_fini_fn_t)(opal_accelerator_base_module_t* module); typedef struct { mca_base_component_t base_version; mca_base_component_data_t base_data; mca_accelerator_base_component_init_fn_t accelerator_init; mca_accelerator_base_component_fini_fn_t accelerator_finalize; } opal_accelerator_base_component_t; /* * Macro for use in components that are of type accelerator */ #define OPAL_ACCELERATOR_BASE_VERSION_1_0_0 OPAL_MCA_BASE_VERSION_2_1_0("accelerator", 1, 0, 0) /* Global structure for accessing accelerator functions */ OPAL_DECLSPEC extern opal_accelerator_base_module_t opal_accelerator; END_C_DECLS #endif