fi_cq(3)
π fi_cq(3) β completion queue operations π
Okay bestie, this is the Libfabric v2.5.1 page for all the completion-queue things. Buckle up, itβs giving βimportant Unix lore but make it cute.β π
NAME π
Completion queue operations β the whole squad:
fi_cq_open/fi_closeβ Open/close a completion queue.fi_controlβ Control CQ operation or attributes.fi_cq_read/fi_cq_readfrom/fi_cq_readerrβ Read a completion from a completion queue.fi_cq_sread/fi_cq_sreadfromβ A synchronous (blocking) read that waits until a specified condition has been met before reading a completion from a completion queue.fi_cq_signalβ Unblock any thread waiting infi_cq_sreadorfi_cq_sreadfrom.fi_cq_strerrorβ Converts provider specific error information into a printable string.
SYNOPSIS β¨
Include this header first, no cap:
#include <rdma/fi_domain.h>
int fi_cq_open(struct fid_domain *domain, struct fi_cq_attr *attr,
struct fid_cq **cq, void *context);
int fi_close(struct fid *cq);
int fi_control(struct fid *cq, int command, void *arg);
ssize_t fi_cq_read(struct fid_cq *cq, void *buf, size_t count);
ssize_t fi_cq_readfrom(struct fid_cq *cq, void *buf, size_t count,
fi_addr_t *src_addr);
ssize_t fi_cq_readerr(struct fid_cq *cq, struct fi_cq_err_entry *buf,
uint64_t flags);
ssize_t fi_cq_sread(struct fid_cq *cq, void *buf, size_t count,
const void *cond, int timeout);
ssize_t fi_cq_sreadfrom(struct fid_cq *cq, void *buf, size_t count,
fi_addr_t *src_addr, const void *cond, int timeout);
int fi_cq_signal(struct fid_cq *cq);
const char * fi_cq_strerror(struct fid_cq *cq, int prov_errno,
const void *err_data, char *buf, size_t len);
ARGUMENTS π
domainβ Open resource domain.cqβ Completion queue.attrβ Completion queue attributes.contextβ User specified context associated with the completion queue.bufβ For read calls, the data buffer to write completions into. For write calls, a completion to insert into the completion queue. Forfi_cq_strerror, an optional buffer that receives printable error information.countβ Number of CQ entries.lenβ Length of data buffer.src_addrβ Source address of a completed receive operation.flagsβ Additional flags to apply to the operation.commandβ Command of control operation to perform on CQ.argβ Optional control argument.condβ Condition that must be met before a completion is generated.timeoutβ Time in milliseconds to wait. A negative value indicates infinite timeout.prov_errnoβ Provider specific error value.err_dataβ Provider specific error data related to a completion.
DESCRIPTION π¦
Completion queues are used to report events associated with data transfers. They are associated with message sends and receives, RMA, atomic, tagged messages, and triggered events. Reported events are usually associated with a fabric endpoint, but may also refer to memory regions used as the target of an RMA or atomic operation. Literally the event-reporting besties of the fabric world. π
fi_cq_open π
fi_cq_open allocates a new completion queue. Unlike event queues, completion queues are associated with a resource domain and may be offloaded entirely in provider hardware. Iconic behavior, honestly.
The properties and behavior of a completion queue are defined by struct fi_cq_attr.
struct fi_cq_attr {
size_t size; /* # entries for CQ */
uint64_t flags; /* operation flags */
enum fi_cq_format format; /* completion format */
enum fi_wait_obj wait_obj; /* requested wait object */
int signaling_vector; /* interrupt affinity */
enum fi_cq_wait_cond wait_cond; /* wait condition format */
struct fid_wait *wait_set; /* optional wait set, deprecated */
};
size β Specifies the minimum size of a completion queue. A value of 0 indicates that the provider may choose a default value.
flags β Flags that control the configuration of the CQ.
FI_AFFINITYβ Indicates that thesignaling_vectorfield (see below) is valid.
format β Completion queues allow the application to select the amount of detail that it must store and report. The format attribute allows the application to select one of several completion formats, indicating the structure of the data that the completion queue should return when read. Supported formats and the structures that correspond to each are listed below. The meaning of the CQ entry fields are defined in the Completion Fields section.
FI_CQ_FORMAT_UNSPECβ If an unspecified format is requested, then the CQ will use a provider selected default format.FI_CQ_FORMAT_CONTEXTβ Provides only user specified context that was associated with the completion.
struct fi_cq_entry {
void *op_context; /* operation context */
};
FI_CQ_FORMAT_MSGβ Provides minimal data for processing completions, with expanded support for reporting information about received messages.
struct fi_cq_msg_entry {
void *op_context; /* operation context */
uint64_t flags; /* completion flags */
size_t len; /* size of received data */
};
FI_CQ_FORMAT_DATAβ Provides data associated with a completion. Includes support for received message length, remote CQ data, and multi-receive buffers.
struct fi_cq_data_entry {
void *op_context; /* operation context */
uint64_t flags; /* completion flags */
size_t len; /* size of received data */
void *buf; /* receive data buffer */
uint64_t data; /* completion data */
};
FI_CQ_FORMAT_TAGGEDβ Expands completion data to include support for the tagged message interfaces.
struct fi_cq_tagged_entry {
void *op_context; /* operation context */
uint64_t flags; /* completion flags */
size_t len; /* size of received data */
void *buf; /* receive data buffer */
uint64_t data; /* completion data */
uint64_t tag; /* received tag */
};
wait_obj β CQs may be associated with a specific wait object. Wait objects allow applications to block until the wait object is signaled, indicating that a completion is available to be read. Users may use fi_control to retrieve the underlying wait object associated with a CQ, in order to use it in other system calls. The following values may be used to specify the type of wait object associated with a CQ: FI_WAIT_NONE, FI_WAIT_UNSPEC, FI_WAIT_SET, FI_WAIT_FD, FI_WAIT_MUTEX_COND (deprecated), and FI_WAIT_YIELD. The default is FI_WAIT_NONE.
FI_WAIT_NONEβ Used to indicate that the user will not block (wait) for completions on the CQ. WhenFI_WAIT_NONEis specified, the application may not callfi_cq_sreadorfi_cq_sreadfrom.FI_WAIT_UNSPECβ Specifies that the user will only wait on the CQ using fabric interface calls, such asfi_cq_sreadorfi_cq_sreadfrom. In this case, the underlying provider may select the most appropriate or highest performing wait object available, including custom wait mechanisms. Applications that selectFI_WAIT_UNSPECare not guaranteed to retrieve the underlying wait object.FI_WAIT_SET(deprecated) β Indicates that the completion queue should use a wait set object to wait for completions. If specified, thewait_setfield must reference an existing wait set object.FI_WAIT_FDβ Indicates that the CQ should use a file descriptor as its wait mechanism. A file descriptor wait object must be usable inselect,poll, andepollroutines. However, a provider may signal an FD wait object by marking it as readable, writable, or with an error.FI_WAIT_MUTEX_COND(deprecated) β Specifies that the CQ should use a pthread mutex and cond variable as a wait object.FI_WAIT_YIELDβ Indicates that the CQ will wait without a wait object but instead yield on every wait. Allows usage offi_cq_sreadandfi_cq_sreadfromthrough a spin.
signaling_vector β If the FI_AFFINITY flag is set, this indicates the logical cpu number (0..max cpu - 1) that interrupts associated with the CQ should target. This field should be treated as a hint to the provider and may be ignored if the provider does not support interrupt affinity.
wait_cond β By default, when a completion is inserted into a CQ that supports blocking reads (fi_cq_sread/fi_cq_sreadfrom), the corresponding wait object is signaled. Users may specify a condition that must first be met before the wait is satisfied. This field indicates how the provider should interpret the cond field, which describes the condition needed to signal the wait object.
β οΈ A wait condition should be treated as an optimization. Providers are not required to meet the requirements of the condition before signaling the wait object. Applications should not rely on the condition necessarily being true when a blocking read call returns. Fr fr, donβt build your whole vibe on it.
If wait_cond is set to FI_CQ_COND_NONE, then no additional conditions are applied to the signaling of the CQ wait object, and the insertion of any new entry will trigger the wait condition. If wait_cond is set to FI_CQ_COND_THRESHOLD, then the cond field is interpreted as a size_t threshold value. The threshold indicates the number of entries that are to be queued at the CQ before the wait is satisfied.
This field is ignored if wait_obj is set to FI_WAIT_NONE.
wait_set (deprecated) β If wait_obj is FI_WAIT_SET, this field references a wait object to which the completion queue should attach. When an event is inserted into the completion queue, the corresponding wait set will be signaled if all necessary conditions are met. The use of a wait_set enables an optimized method of waiting for events across multiple event and completion queues. This field is ignored if wait_obj is not FI_WAIT_SET.
π fi_close π
Okay bestie, fi_close is the cleanup queen π β it releases all resources tied to a completion queue. And no cap: any completions still chilling on the CQ when you close it are lost. Gone. Poof. π
When you close a CQ, there must be no opened endpoints, transmit contexts, or receive contexts associated with that CQ. If stuff is still attached when you try to close, the call will return -FI_EBUSY. So likeβ¦ vibe check your resources first, fr fr π
π fi_control π
fi_control is your backstage pass to provider- or implementation-specific details of the completion queue. Lowkey important: access to the CQ should be serialized across all calls when fi_control is invoked, because it may redirect the implementation of CQ operations. Donβt let multiple threads just barge in π
These are the control commands that are usable with a CQ:
FI_GETWAIT(void **) β lets you retrieve the low-level wait object associated with the CQ. The format of the wait-object is specified during CQ creation through the CQ attributes. Thefi_controlarg parameter should be an address where a pointer to the returned wait object will be written. Seefi_eq.3for addition details usingfi_controlwithFI_GETWAIT.FI_GETWAITOBJ(enum fi_wait_obj *) β retrieves the type of wait object associated with the CQ. Thefi_controlarg parameter should be an address where the wait object type will be written.
π¦ fi_cq_read π¦
fi_cq_read does a non-blocking read of completion data from the CQ. The format of the completion event is determined using the fi_cq_format option that was specified when the CQ was opened. Multiple completions may be retrieved from a CQ in a single call. The maximum number of entries to return is limited to the specified count parameter, with the number of entries successfully read from the CQ returned by the call. (See return values section below.) A count value of 0 may be used to drive progress on associated endpoints when manual progress is enabled. Slay a little progress check β¨
CQs are optimized to report operations which have completed successfully. Operations which fail are reported out of band. Such operations are retrieved using the fi_cq_readerr function. When an operation that has completed with an unexpected error is encountered, it is placed into a temporary error queue. Attempting to read from a CQ while an item is in the error queue results in fi_cq_read failing with a return code of -FI_EAVAIL. Applications may use this return code to determine when to call fi_cq_readerr. Basically: error queue has something? -FI_EAVAIL is your little heads-up, bestie π
πΈ fi_cq_readfrom πΈ
fi_cq_readfrom behaves identical to fi_cq_read, with the exception that it allows the CQ to return source address information to the user for any received data. Source address data is only available for those endpoints configured with FI_SOURCE capability. If fi_cq_readfrom is called on an endpoint for which source addressing data is not available, the source address will be set to FI_ADDR_NOTAVAIL. Also important: the number of input src_addr entries must be the same as the count parameter. No mismatches, okay? π«Ά
Returned source addressing data is converted from the native address used by the underlying fabric into an fi_addr_t, which may be used in transmit operations. Under most circumstances, returning fi_addr_t requires that the source address already have been inserted into the address vector associated with the receiving endpoint. This is true for address vectors of type FI_AV_TABLE. In select providers when FI_AV_MAP is used, source addresses may be converted algorithmically into a usable fi_addr_t, even though the source address has not been inserted into the address vector. This is permitted by the API, as it allows the provider to avoid address look-up as part of receive message processing. In no case do providers insert addresses into an AV separate from an application calling fi_av_insert or similar call. Periodt. β¨
For endpoints allocated using the FI_SOURCE_ERR capability, if the source address cannot be converted into a valid fi_addr_t value, fi_cq_readfrom will return -FI_EAVAIL, even if the data were received successfully. The completion will then be reported through fi_cq_readerr with error code -FI_EADDRNOTAVAIL. See fi_cq_readerr for details. π
If FI_SOURCE is specified without FI_SOURCE_ERR, source addresses which cannot be mapped to a usable fi_addr_t will be reported as FI_ADDR_NOTAVAIL.
π§ fi_cq_sread / fi_cq_sreadfrom π§
The fi_cq_sread and fi_cq_sreadfrom calls are the blocking equivalent operations to fi_cq_read and fi_cq_readfrom. Their behavior is similar to the non-blocking calls, with the exception that the calls will not return until either a completion has been read from the CQ or an error or timeout occurs. Itβs giving βwait for itβ¦ wait for itβ¦β energy π
Threads blocking in this function will return to the caller if they are signaled by some external source. This is true even if the timeout has not occurred or was specified as infinite. So yes, an external signal can absolutely wake your thread up β no cap.
It is invalid for applications to call these functions if the CQ has been configured with a wait object ofFI_WAIT_NONEorFI_WAIT_SET. Like, donβt do it bestie π
π fi_cq_readerr π
The read error function, fi_cq_readerr, retrieves information regarding any asynchronous operation which has completed with an unexpected error. fi_cq_readerr is a non-blocking call, returning immediately whether an error completion was found or not. Immediate. No waiting around. β
Error information is reported to the user through struct fi_cq_err_entry. The format of this structure is defined below.
struct fi_cq_err_entry {
void *op_context; /* operation context */
uint64_t flags; /* completion flags */
size_t len; /* size of received data */
void *buf; /* receive data buffer */
uint64_t data; /* completion data */
uint64_t tag; /* message tag */
size_t olen; /* overflow length */
int err; /* positive error code */
int prov_errno; /* provider error code */
void *err_data; /* error data */
size_t err_data_size; /* size of err_data */
fi_addr_t src_addr; /* error source address */
};
The general reason for the error is provided through the err field. Provider specific error information may also be available through the prov_errno and err_data fields. Users may call fi_cq_strerror to convert provider specific error information into a printable string for debugging purposes. See field details below for more information on the use of err_data and err_data_size. Debugging era π
Note that error completions are generated for all operations, including those for which a completion was not requested (e.g. inject transfers or when an endpoint is configured with FI_SELECTIVE_COMPLETION, but the request did not have the FI_COMPLETION flag set). In such cases, providers will return as much information as made available by the underlying software and hardware about the failure, other fields will be set to NULL or 0. This includes the op_context value, which may not have been provided or was ignored on input as part of the transfer. So donβt assume every field is gonna be filled in, bestie π
Notable completion error codes are given below.
FI_EADDRNOTAVAILβ This error code is used by CQs configured withFI_SOURCE_ERRto report completions for which a usablefi_addr_tsource address could not be found. An error code ofFI_EADDRNOTAVAILindicates that the data transfer was successfully received and processed, with thefi_cq_err_entryfields containing information about the completion. Theerr_datafield will be set to the source address data. The source address will be in the same format as specified through thefi_info addr_formatfield for the opened domain. This may be passed directly into anfi_av_insertcall to add the source address to the address vector. Iconic little handoff, honestly π
For API versions 1.20 and later, if the EP is configured with FI_AV_AUTH_KEY, src_addr will be set to the fi_addr_t authorization key handle or a user-define authorization key ID corresponding to the incoming data transfer. Otherwise, the value will be set to FI_ADDR_NOTAVAIL.
π fi_cq_signal π
fi_cq_signal will unblock any thread waiting in fi_cq_sread or fi_cq_sreadfrom. This may be used to wake-up a thread that is blocked waiting to read a completion operation. The fi_cq_signal operation is only available if the CQ was configured with a wait object. Wake-up call but make it fabric-core π
β¨
π COMPLETION FIELDS π
okay so bestie, the CQ entry data structures share a lot of the same fields, and the meanings below are the same for every CQ entry structure format. no cap. π«Ά
op_contextβ the operation context is the application-specified context value that was provided with an asynchronous operation. Theop_contextfield is valid for all completions that are associated with an asynchronous operation. β¨
For completion events that are not associated with a posted operation, this field will be set to NULL. This includes completions generated at the target in response to RMA write operations that carry CQ data (FI_REMOTE_WRITE | FI_REMOTE_CQ_DATA flags set), when the FI_RX_CQ_DATA mode bit is not required.
flagsβ this specifies flags associated with the completed operation. The Completion Flags section below lists valid flag values. Flags are set for all relevant completions. πlenβ thislenfield applies to completed receive operations (e.g.fi_recv,fi_trecv, etc.) and the completed write with remote cq data on the responder side (e.g.fi_write, withFI_REMOTE_CQ_DATAflag). It indicates the size of transferred message data β i.e. how many data bytes were placed into the associated receive/target buffer by a correspondingfi_send/fi_tsend/fi_writeet al call. If an endpoint has been configured with theFI_MSG_PREFIXmode, thelenalso reflects the size of the prefix buffer. πbufβ thebuffield is only valid for completed receive operations, and only applies when the receive buffer was posted with theFI_MULTI_RECVflag. In this case,bufpoints to the starting location where the receive data was placed. πΈdataβ thedatafield is only valid if theFI_REMOTE_CQ_DATAcompletion flag is set, and only applies to receive completions. IfFI_REMOTE_CQ_DATAis set, this field will contain the completion data provided by the peer as part of their transmit request. The completion data will be given in host byte order. π¦tagβ a tag applies only to received messages that occur using the tagged interfaces. This field contains the tag that was included with the received message. The tag will be in host byte order. βolenβ theolenfield applies to received messages. It is used to indicate that a received message has overrun the available buffer space and has been truncated. Theolenspecifies the amount of data that did not fit into the available receive buffer and was discarded. πerrβ thiserrcode is a positive fabric errno associated with a completion. Theerrvalue indicates the general reason for an error, if one occurred. Seefi_errno.3for a list of possible error codes. π₯prov_errnoβ on an error,prov_errnomay contain a provider specific error code. The use of this field and its meaning is provider specific. It is intended to be used as a debugging aid. Seefi_cq_strerrorfor additional details on converting this error value into a human readable string. πerr_dataβ theerr_datafield is used to return provider specific information, if available, about the error. On input,err_datashould reference a data buffer of sizeerr_data_size. On output, the provider will fill in this buffer with any provider specific data which may help identify the cause of the error. The contents of theerr_datafield and its meaning is provider specific. It is intended to be used as a debugging aid. Seefi_cq_strerrorfor additional details on converting this error data into a human readable string. See the compatibility note below on how this field is used for older libfabric releases. πerr_data_sizeβ on input,err_data_sizeindicates the size of theerr_databuffer in bytes. On output,err_data_sizewill be set to the number of bytes copied to theerr_databuffer. Theerr_datainformation is typically used withfi_cq_strerrorto provide details about the type of error that occurred. π
π compatibility note, bestie: for compatibility purposes, the behavior of theerr_dataanderr_data_sizefields may be modified from whatβs listed above. Iferr_data_sizeis0on input, or the fabric was opened withrelease < 1.5, then any buffer referenced byerr_datawill be ignored on input. In this situation, on outputerr_datawill be set to a data buffer owned by the provider. The contents of the buffer will remain valid until a subsequent read call against the CQ. Applications must serialize access to the CQ when processing errors to ensure that the buffer referenced byerr_datadoes not change. π
src_addrβ used to return source-address related information for error events. How this field is used is error event specific. π§
π¦ COMPLETION FLAGS π¦
Completion flags provide additional details regarding the completed operation. The following completion flags are defined. π
FI_SENDβ indicates that the completion was for a send operation. This flag may be combined with anFI_MSGorFI_TAGGEDflag. π€FI_RECVβ indicates that the completion was for a receive operation. This flag may be combined with anFI_MSGorFI_TAGGEDflag. π₯FI_RMAβ indicates that an RMA operation completed. This flag may be combined with anFI_READ,FI_WRITE,FI_REMOTE_READ, orFI_REMOTE_WRITEflag. πFI_ATOMICβ indicates that an atomic operation completed. This flag may be combined with anFI_READ,FI_WRITE,FI_REMOTE_READ, orFI_REMOTE_WRITEflag. βοΈFI_MSGβ indicates that a message-based operation completed. This flag may be combined with anFI_SENDorFI_RECVflag. π¬FI_TAGGEDβ indicates that a tagged message operation completed. This flag may be combined with anFI_SENDorFI_RECVflag. π·οΈFI_MULTICASTβ indicates that a multicast operation completed. This flag may be combined withFI_MSGand relevant flags. This flag is only guaranteed to be valid for received messages if the endpoint has been configured withFI_SOURCE. π‘FI_READβ indicates that a locally initiated RMA or atomic read operation has completed. This flag may be combined with anFI_RMAorFI_ATOMICflag. πFI_WRITEβ indicates that a locally initiated RMA or atomic write operation has completed. This flag may be combined with anFI_RMAorFI_ATOMICflag. βοΈFI_REMOTE_READβ indicates that a remotely initiated RMA or atomic read operation has completed. This flag may be combined with anFI_RMAorFI_ATOMICflag. πFI_REMOTE_WRITEβ indicates that a remotely initiated RMA or atomic write operation has completed. This flag may be combined with anFI_RMAorFI_ATOMICflag. πFI_REMOTE_CQ_DATAβ this indicates that remote CQ data is available as part of the completion. πFI_MULTI_RECVβ this flag applies to receive buffers that were posted with theFI_MULTI_RECVflag set. This completion flag indicates that the original receive buffer referenced by the completion has been consumed and was released by the provider. Providers may set this flag on the last message that is received into the multi-recv buffer, or may generate a separate completion that indicates that the buffer has been released. π
Applications can distinguish between these two cases by examining the completion entry flags field. If additional flags, such as FI_RECV, are set, the completion is associated with a received message. In this case, the buf field will reference the location where the received message was placed into the multi-recv buffer. Other fields in the completion entry will be determined based on the received message. If other flag bits are zero, the provider is reporting that the multi-recv buffer has been released, and the completion entry is not associated with a received message. π
β¨ COMPLETION EVENT SEMANTICS β¨
okay so bestie, libfabric defines a bunch of completion levels, and theyβre identified with operational flags. Each flag tells you the soonest a provider may generate a completion event, plus what assumptions youβre allowed to make when you process that completion. The operational flags are defined below, and each one comes with an example of how a provider might implement the semantic. Important vibe check: a provider only has to meet the semantic, not copy the implementation. Providers can absolutely implement stronger completion semantics than necessary for a given operation, but the only thing guaranteed is the behavior defined by that completion level. periodt π
To help you feel the conceptual difference between completion levels, imagine mailing a letter. Placing the letter into the local mailbox for pick-up is similar to inject complete. Having the letter picked up and dropped off at the destination mailbox is equivalent to transmit complete. The delivery complete semantic is a stronger guarantee, with a person at the destination signing for the letter. However, the person who signed for the letter is not necessarily the intended recipient. The match complete option is similar to delivery complete, but requires the intended recipient to sign for the letter. π«Ά
The commit complete level has different semantics than the previously mentioned levels. Commit complete would be closer to the letter arriving at the destination and being placed into a fire proof safe. π₯
The operational flags for the described completion levels are defined below.
π FI_INJECT_COMPLETE π
Indicates that a completion should be generated when the source buffer(s) may be reused. A completion guarantees that the buffers will not be read from again and the application may reclaim them. No other guarantees are made with respect to the state of the operation.
Example: A provider may generate this completion event after copying the source buffer into a network buffer, either in host memory or on the NIC. An inject completion does not indicate that the data has been transmitted onto the network, and a local error could occur after the completion event has been generated that could prevent it from being transmitted. π
Inject complete allows for the fastest completion reporting (and, hence, buffer reuse), but provides the weakest guarantees against network errors.
π‘ Note: This flag is used to control when a completion entry is inserted into a completion queue. It does not apply to operations that do not generate a completion queue entry, such as thefi_injectoperation, and is not subject to theinject_sizemessage limit restriction.
π¦ FI_TRANSMIT_COMPLETE π¦
Indicates that a completion should be generated when the transmit operation has completed relative to the local provider. The exact behavior is dependent on the endpoint type.
π‘οΈ For reliable endpoints
Indicates that a completion should be generated when the operation has been delivered to the peer endpoint. A completion guarantees that the operation is no longer dependent on the fabric or local resources. The state of the operation at the peer endpoint is not defined.
Example: A provider may generate a transmit complete event upon receiving an ack from the peer endpoint. The state of the message at the peer is unknown and may be buffered in the target NIC at the time the ack has been generated.
π For unreliable endpoints
Indicates that a completion should be generated when the operation has been delivered to the fabric. A completion guarantees that the operation is no longer dependent on local resources. The state of the operation within the fabric is not defined.
π FI_DELIVERY_COMPLETE π
Indicates that a completion should not be generated until an operation has been processed by the destination endpoint(s). A completion guarantees that the result of the operation is available; however, additional steps may need to be taken at the destination to retrieve the results. For example, an application may need to provide receive buffers in order to retrieve messages that were buffered by the provider.
Delivery complete indicates that the message has been processed by the peer. If an application buffer was ready to receive the results of the message when it arrived, then delivery complete indicates that the data was placed into the applicationβs buffer.
This completion mode applies only to reliable endpoints. For operations that return data to the initiator, such as RMA read or atomic-fetch, the source endpoint is also considered a destination endpoint. This is the default completion mode for such operations.
π FI_MATCH_COMPLETE π
Indicates that a completion should be generated only after the operation has been matched with an application specified buffer. Operations using this completion semantic are dependent on the application at the target claiming the message or results. As a result, match complete may involve additional provider level acknowledgements or lengthy delays. However, this completion model enables peer applications to synchronize their execution. Many providers may not support this semantic. π
π§ FI_COMMIT_COMPLETE π§
Indicates that a completion should not be generated (locally or at the peer) until the result of an operation have been made persistent. A completion guarantees that the result is both available and durable, in the case of power failure.
This completion mode applies only to operations that target persistent memory regions over reliable endpoints.
π§ͺ This completion mode is experimental.
π FI_FENCE π
This is not a completion level, but it plays a role in the completion ordering between operations that would not normally be ordered. An operation that is marked with the FI_FENCE flag and all operations posted after the fenced operation are deferred until all previous operations targeting the same peer endpoint have completed. Additionally, the completion of the fenced operation indicates that prior operations have met the same completion level as the fenced operation. For example, if an operation is posted as FI_DELIVERY_COMPLETE | FI_FENCE, then its completion indicates prior operations have met the semantic required for FI_DELIVERY_COMPLETE. This is true even if the prior operation was posted with a lower completion level, such as FI_TRANSMIT_COMPLETE or FI_INJECT_COMPLETE.
Note that a completion generated for an operation posted prior to the fenced operation only guarantees that the completion level that was originally requested has been met. It is the completion of the fenced operation that guarantees that the additional semantics have been met. π
The above completion semantics are defined with respect to the initiator of the operation. The different semantics are useful for describing when the initiator may re-use a data buffer, and guarantees what state a transfer must reach prior to a completion being generated. This allows applications to determine appropriate error handling in case of communication failures.
πΈ TARGET COMPLETION SEMANTICS πΈ
The completion semantic at the target is used to determine when data at the target is visible to the peer application. Visibility indicates that a memory read to the same address that was the target of a data transfer will return the results of the transfer. The target of a transfer can be identified by the initiator, as may be the case for RMA and atomic operations, or determined by the target, for example by providing a matching receive buffer. Global visibility indicates that the results are available regardless of where the memory read originates. For example, the read could come from a process running on a host CPU, it may be accessed by subsequent data transfer over the fabric, or read from a peer device such as a GPU. β¨
In terms of completion semantics, visibility usually indicates that the transfer meets the FI_DELIVERY_COMPLETE requirements from the perspective of the target. The target completion semantic may be, but is not necessarily, linked with the completion semantic specified by the initiator of the transfer.
Often, target processes do not explicitly state a desired completion semantic and instead rely on the default semantic. The default behavior is based on several factors, including:
- whether a completion event is generated at the target
- the type of transfer involved (e.g. msg vs RMA)
- endpoint data and message ordering guarantees
- properties of the targeted memory buffer
- the initiatorβs specified completion semantic
Broadly, target completion semantics are grouped based on whether or not the transfer generates a completion event at the target. This includes writing a CQ entry or updating a completion counter. In common use cases, transfers that use a message interface (FI_MSG or FI_TAGGED) typically generate target events, while transfers involving an RMA interface (FI_RMA or FI_ATOMIC) often do not. There are exceptions to both these cases, depending on endpoint to CQ and counter bindings and operational flags. For example, RMA writes that carry remote CQ data will generate a completion event at the target, and are frequently used to convey visibility to the target application. The general guidelines for target side semantics are described below, followed by exceptions that modify that behavior.
By default, completions generated at the target indicate that the transferred data is immediately available to be read from the target buffer. That is, the target sees FI_DELIVERY_COMPLETE (or better) semantics, even if the initiator requested lower semantics. For applications using only data buffers allocated from host memory, this is often sufficient.
For operations that do not generate a completion event at the target, the visibility of the data at the target may need to be inferred based on subsequent operations that do generate target completions. Absent a target completion, when a completion of an operation is written at the initiator, the visibility semantic of the operation at the target aligns with the initiator completion semantic. For instance, if an RMA operation completes at the initiator as either FI_INJECT_COMPLETE or FI_TRANSMIT_COMPLETE, the data visibility at the target is not guaranteed. π
okay bestie, we are SO back for the target-completion lore πβ¨ hereβs how the target process can make absolutely sure that data from a transfer that didnβt pop a completion on its side is actually visible now. one or more of these mechanisms can be used β and like, this list is not exhaustive of every option ever, but it does define the common ones. in the descriptions below, the first transfer does not result in a completion event at the target, but it is eventually followed by a transfer that does π
- message ordering slay β if the endpoint guarantees message ordering between two transfers, the target completion of a second transfer will indicate that the data from the first transfer is available. for example, if the endpoint supports send after write ordering (
FI_ORDER_SAW), then a receive completion corresponding to the send will indicate that the write data is available. this holds independent of the initiatorβs completion semantic for either the write or send. when ordering is guaranteed, the second transfer can be queued with the provider immediately after queuing the first π - no ordering? no problem, local wait era β if the endpoint does not guarantee message ordering, the initiator must take additional steps to ensure visibility. if the initiator requests
FI_DELIVERY_COMPLETEsemantics for the first operation, the initiator can wait for the operation to complete locally. once the completion has been read, the target completion of a second transfer will indicate that the first transferβs data is visible β¨ - the fence flex β alternatively, if message ordering is not guaranteed by the endpoint, the initiator can use the
FI_FENCEandFI_DELIVERY_COMPLETEflags on the second data transfer to force the first transfers to meet theFI_DELIVERY_COMPLETEsemantics. if the second transfer generates a completion at the target, that will indicate that the data is visible. otherwise, a target completion for any transfer after the fenced operation will indicate that the data is visible π¦
the above semantics apply for transfers targeting traditional host memory buffers. however, the behavior may differ when device memory and/or persistent memory is involved (FI_HMEM and FI_PMEM capability bits). when heterogenous memory is involved, the concept of memory domains comes into play. memory domains identify the physical separation of memory, which may or may not be accessible through the same virtual address space. see the fi_mr(3) man page for further details on memory domains π§
completion ordering and data visibility are only well-defined for transfers that target the same memory domain. applications need to be aware of ordering and visibility differences when transfers target different memory domains. additionally, applications also need to be concerned with the memory domain that completions themselves are written and if it differs from the memory domain targeted by a transfer. in some situations, either the provider or application may need to call device specific APIs to synchronize or flush device memory caches in order to achieve the desired data visibility π
when heterogenous memory is in use, the default target completion semantic for transfers that generate a completion at the target is still FI_DELIVERY_COMPLETE, however, applications should be aware that there may be a negative impact on overall performance for providers to meet this requirement π
for example, a target process may be using a GPU to accelerate computations. a memory region mapping to memory on the GPU may be exposed to peers as either an RMA target or posted locally as a receive buffer. in this case, the application is concerned with two memory domains β system and GPU memory. completions are written to system memory π
continuing the example, a peer process sends a tagged message. that message is matched with the receive buffer located in GPU memory. the NIC copies the data from the network into the receive buffer and writes an entry into the completion queue. note that both memory domains were accessed as part of this transfer. the message data was directed to the GPU memory, but the completion went to host memory. because separate memory domains may not be synchronized with each other, it is possible for the host CPU to see and process the completion entry before the transfer to the GPU memory is visible to either the host GPU or even software running on the GPU. from the perspective of the provider, visibility of the completion does not imply visibility of data written to the GPUβs memory domain π
the default completion semantic at the target application for message operations is FI_DELIVERY_COMPLETE. an anticipated provider implementation in this situation is for the provider software running on the host CPU to intercept the CQ entry, detect that the data landed in heterogeneous memory, and perform the necessary device synchronization or flush operation before reporting the completion up to the application. this ensures that the data is visible to CPU and GPU software prior to the application processing the completion π
in addition to the cost of provider software intercepting completions and checking if a transfer targeted heterogenous memory, device synchronization itself may impact performance. as a result, applications can request a lower completion semantic when posting receives. that indicates to the provider that the application will be responsible for handling any device specific flush operations that might be needed. see fi_msg(3) FLAGS β
for data transfers that do not generate a completion at the target, such as RMA or atomics, it is the responsibility of the application to ensure that all target buffers meet the necessary visibility requirements of the application. the previously mentioned bulleted methods for notifying the target that the data is visible may not be sufficient, as the provider software at the target could lack the context needed to ensure visibility. this implies that the application may need to call device synchronization/flush APIs directly π
for example, a peer application could perform several RMA writes that target GPU memory buffers. if the provider offloads RMA operations into the NIC, the provider software at the target will be unaware that the RMA operations have occurred. if the peer sends a message to the target application that indicates that the RMA operations are done, the application must ensure that the RMA data is visible to the host CPU or GPU prior to executing code that accesses the data. the target completion of having received the sent message is not sufficient, even if send-after-write ordering is supported π€
most target heterogenous memory completion semantics map to FI_TRANSMIT_COMPLETE or FI_DELIVERY_COMPLETE. persistent memory (FI_PMEM capability), however, is often used with FI_COMMIT_COMPLETE semantics. heterogenous completion concepts still apply π«Ά
for transfers flagged by the initiator with FI_COMMIT_COMPLETE, a completion at the target indicates that the results are visible and durable. for transfers targeting persistent memory, but using a different completion semantic at the initiator, the visibility at the target is similar to that described above. durability is only associated with transfers marked with FI_COMMIT_COMPLETE π
for transfers targeting persistent memory that request FI_DELIVERY_COMPLETE, then a completion, at either the initiator or target, indicates that the data is visible. visibility at the target can be conveyed using one of the above describe mechanism β generating a target completion, sending a message from the initiator, etc. similarly, if the initiator requested FI_TRANSMIT_COMPLETE, then additional steps are needed to ensure visibility at the target. for example, the transfer can generate a completion at the target, which would indicate visibility, but not durability. the initiator can also follow the transfer with another operation that forces visibility, such as using FI_FENCE in conjunction with FI_DELIVERY_COMPLETE π
π NOTES π
a completion queue must be bound to at least one enabled endpoint before any operation such as fi_cq_read, fi_cq_readfrom, fi_cq_sread, fi_cq_sreadfrom etc. can be called on it. no cap, bind it first bestie π
if a completion queue has been overrun, it will be placed into an overrun state. read operations will continue to return any valid, non-corrupted completions, if available. after all valid completions have been retrieved, any attempt to read the CQ will result in it returning an FI_EOVERRUN error event. overrun completion queues are considered fatal and may not be used to report additional completions once the overrun occurs. like, genuinely do not keep using it after that π
this is one of those βthe vibes are badβ situations β an overrun CQ is fatal, periodt.
β¨ RETURN VALUES β¨
fi_cq_open / fi_cq_signal
returns 0 on success. on error, returns a negative fabric errno πΈ
fi_cq_read / fi_cq_readfrom
on success, returns the number of completions retrieved from the completion queue. on error, returns a negative fabric errno, with these two errors explicitly identified: if no completions are available to read from the CQ, returns -FI_EAGAIN. if the topmost completion is for a failed transfer (an error entry), returns -FI_EAVAIL π¦
fi_cq_sread / fi_cq_sreadfrom
on success, returns the number of completions retrieved from the completion queue. on error, returns a negative fabric errno, with these two errors explicitly identified: if the timeout expires or the calling thread is signaled and no data is available to be read from the completion queue, returns -FI_EAGAIN. if the topmost completion is for a failed transfer (an error entry), returns -FI_EAVAIL π
fi_cq_readerr
on success, returns the positive value 1 (number of error entries returned). on error, returns a negative fabric errno, with this error explicitly identified: if no error completions are available to read from the CQ, returns -FI_EAGAIN π
fi_cq_strerror
returns a character string interpretation of the provider specific error returned with a completion π
fabric errno values are defined in rdma/fi_errno.h π
π SEE ALSO π
fi_getinfo(3), fi_endpoint(3), fi_domain(3), fi_eq(3), fi_cntr(3), fi_poll(3)
π AUTHORS π
OpenFabrics.
and thatβs the whole fi_cq(3) saga, bestie β from the Libfabric Programmerβs Manual, dated 2026-02-11, page fi_cq(3). go forth and read your completions responsibly π
β¨π«Ά
π¦ where this page comes from
- centos-stream 10: libfabric-devel 2.5.1-1.el10 Β· BSD-2-Clause OR GPL-2.0-only
- π girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms