Mutable Command List Extension

Mutable Command List Extension#

API#

Mutable Command List#

// Discover mutable command list properties
ze_mutable_command_list_exp_properties_t mutCmdListProps = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMAND_LIST_EXP_PROPERTIES,      // stype
    nullptr,                                                    // pNext
    0,                                                          // mutableCommandListFlags
    0                                                           // mutableCommandFlags
};

ze_device_properties_t deviceProps = {
    ZE_STRUCTURE_TYPE_DEVICE_PROPERTIES
};
deviceProps.pNext = &mutCmdListProps;

zeDeviceGetProperties(hDevice, &deviceProps);

// ...

// Create a mutable command list
ze_mutable_command_list_exp_desc_t mutCmdListDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMAND_LIST_EXP_DESC,
    nullptr,
    0 // flags
};

ze_command_list_desc_t commandListDesc = {
    ZE_STRUCTURE_TYPE_COMMAND_LIST_DESC,
    &mutCmdListDesc,
    0,
    0 // flags
};

ze_command_list_handle_t hCommandList = nullptr;
zeCommandListCreate(hContext, hDevice, &commandListDesc, &hCommandList);

// [ ...create fence, signal event and wait event objects... ]
// This example assumes hFence, hSignalEvent and hWaitEvent have been created.

// Create kernel from module
ze_kernel_desc_t kernelDesc = {
    ZE_STRUCTURE_TYPE_KERNEL_DESC,
    0,
    "example"
};
ze_kernel_handle_t hKernel = nullptr;
ze_result_t result = zeKernelCreate(hModule, &kernelDesc, &hKernel);

// Set the kernel arguments
ze_group_count_t groupSize = {};
zeKernelSuggestGroupSize(hKernel, 1024, 1024, 1, &groupSize.groupCountX, &groupSize.groupCountY, &groupSize.groupCountZ);

int defaultValue = 0;
zeKernelSetArgumentValue(hKernel, 0, sizeof(int), &defaultValue);

// Get next command identifier
ze_mutable_command_id_exp_desc_t cmdIdDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMAND_ID_EXP_DESC,      // stype
    nullptr,                                            // pNext
    0                                                   // flags
};

uint64_t commandId = 0;
zeCommandListGetNextCommandIdExp(hCommandList, &cmdIdDesc, &commandId);

// Encode command into command list
zeCommandListAppendLaunchKernel(hCommandList, hKernel, &groupSize, hSignalEvent, 1, &hWaitEvent);

// Close the command list
zeCommandListClose(hCommandList);

// ...

// Execute the command list
zeCommandQueueExecuteCommandLists(hCommandQueue, 1, &hCommandList, hFence);

// ...

The application may subsequently mutate specific commands, as follows:

// Prepare to modify group count
ze_group_count_t groupCount = {
    256,                                                    // groupCountX
    256,                                                    // groupCountY
    1                                                       // groupCountZ
};

ze_mutable_group_count_exp_desc_t groupCountDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_GROUP_COUNT_EXP_DESC,         // stype
    nullptr,                                                // pNext
    commandId,                                              // commandId
    &groupCount                                             // pGroupCount
};

// Prepare to modify Kernel Argument
int argValue = 1;

ze_mutable_kernel_argument_exp_desc_t krnlArgDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_KERNEL_ARGUMENT_EXP_DESC,     // stype
    &groupCountDesc,                                        // pNext
    commandId,                                              // commandId
    0,                                                      // argIndex
    sizeof(int),                                            // argSize
    &argValue                                               // pArgValue
};

// Prepare to update mutable commands
ze_mutable_commands_exp_desc_t desc = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMANDS_EXP_DESC,            // stype
    &krnlArgDesc,                                           // pNext
    0                                                       // flags
};

// Synchronize command list execution
zeFenceHostSynchronize(hFence, UINT64_MAX);

// Update mutable commands
zeCommandListUpdateMutableCommandsExp(hCommandList, &desc);

// Update signal event for the launch kernel command
zeCommandListUpdateMutableCommandSignalEventExp(hCommandList, commandId, hNewLaunchKernelSignalEvent);

// Update the wait events for the launch kernel command
zeCommandListUpdateMutableCommandWaitEventsExp(hCommandList, commandId, 1, &hNewLaunchKernelWaitEvent);

// Close the command list
zeCommandListClose(hCommandList);

// ...

Note, the command list must be explicitly closed after updating mutable commands and events. This informs the implementation that the application has finished with updates and is ready to submit the command list. In preparation for kernel mutation user must provide all possible kernels for the command.

// define all possible kernels
ze_kernel_handle_t addKernel;
ze_kernel_handle_t mulKernel;

ze_kernel_handle_t kernels[] = {addKernel, mulKernel};

// when users want kernel mutation, they need to explicitly state this, as 0 does not include kernel instruction mutation by default
ze_mutable_command_exp_flags_t mutationFlags =
    ZE_MUTABLE_COMMAND_EXP_FLAG_KERNEL_ARGUMENTS |
    ZE_MUTABLE_COMMAND_EXP_FLAG_GROUP_COUNT |
    ZE_MUTABLE_COMMAND_EXP_FLAG_GROUP_SIZE |
    ZE_MUTABLE_COMMAND_EXP_FLAG_KERNEL_INSTRUCTION;

// Get next command identifier
ze_mutable_command_id_exp_desc_t cmdIdDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMAND_ID_EXP_DESC,      // stype
    nullptr,                                            // pNext
    mutationFlags                                       // flags
};

// retrieve id for the append operation and provide all possible kernels for this command
uint64_t mutableKernelCommandId = 0;
zeCommandListGetNextCommandIdWithKernelsExp(hCommandList, &cmdIdDesc, &mutableKernelCommandId, 2, kernels);

// Encode command into command list
zeCommandListAppendLaunchKernel(hCommandList, addKernel, &groupSize, nullptr, 0, nullptr);

// Close the command list
zeCommandListClose(hCommandList);

Mutation of kernels must obey two rules: - kernel handle mutation function must be called as first for a given command id - kernel mutation invalidates all kernel arguments and dispatch parameters, these must be provided for the new kernel

// Update mutable kernel for the command, switch from addKernel to mulKernel
zeCommandListUpdateMutableCommandKernelsExp(hCommandList, 1, &mutableKernelCommandId, &mulKernel);

// modify group count
ze_group_count_t groupCount = {
    32,                                                     // groupCountX
    1,                                                      // groupCountY
    1                                                       // groupCountZ
};

ze_mutable_group_count_exp_desc_t groupCountDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_GROUP_COUNT_EXP_DESC,         // stype
    nullptr,                                                // pNext
    mutableKernelCommandId,                                 // commandId
    &groupCount                                             // pGroupCount
};

ze_mutable_group_size_exp_desc_t groupSizeDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_GROUP_SIZE_EXP_DESC,          // stype
    &groupCountDesc,                                        // pNext
    mutableKernelCommandId,                                 // commandId
    32,                                                     // groupSizeX
    1,                                                      // groupSizeY
    1,                                                      // groupSizeZ
};

// Prepare to modify Kernel Argument
int argValue = 1;
void *usmPointer;

ze_mutable_kernel_argument_exp_desc_t krnlArgMemoryDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_KERNEL_ARGUMENT_EXP_DESC,     // stype
    &groupSizeDesc,                                         // pNext
    mutableKernelCommandId,                                 // commandId
    0,                                                      // argIndex
    sizeof(void *),                                         // argSize
    &usmPointer                                             // pArgValue
};

ze_mutable_kernel_argument_exp_desc_t krnlArgScalarDesc = {
    ZE_STRUCTURE_TYPE_MUTABLE_KERNEL_ARGUMENT_EXP_DESC,     // stype
    &krnlArgMemoryDesc,                                     // pNext
    mutableKernelCommandId,                                 // commandId
    1,                                                      // argIndex
    sizeof(int),                                            // argSize
    &argValue                                               // pArgValue
};

// Prepare to update mutable commands
ze_mutable_commands_exp_desc_t desc = {
    ZE_STRUCTURE_TYPE_MUTABLE_COMMANDS_EXP_DESC,            // stype
    &krnlArgScalarDesc,                                     // pNext
    0                                                       // flags
};

// Update mutable kernel arguments and dispatch parameters for the command
zeCommandListUpdateMutableCommandsExp(hCommandList, &desc);

// Close the command list
zeCommandListClose(hCommandList);

The command list must be explicitly closed after updating mutable commands.