blob: a8c6cff5c1089cbb8eea263bca51166e42d1e37b [file] [log] [blame]
// Copyright 2023 The IREE Authors
//
// Licensed under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
#include <stdint.h>
#include <string.h>
#include "iree/base/api.h"
#include "iree/base/assert.h"
#include "iree/base/tracing.h"
#include "iree/hal/api.h"
#include "iree/hal/drivers/hip/api.h"
#include "iree/hal/drivers/hip/dynamic_symbols.h"
#include "iree/hal/drivers/hip/hip_device.h"
#include "iree/hal/drivers/hip/rccl_dynamic_symbols.h"
#include "iree/hal/drivers/hip/status_util.h"
// Maximum device name length supported by the HIP HAL driver.
#define IREE_HAL_HIP_MAX_DEVICE_NAME_LENGTH 128
// Utility macros to convert between hipDevice_t and iree_hal_device_id_t.
#define IREE_HIPDEVICE_TO_DEVICE_ID(device) (iree_hal_device_id_t)((device) + 1)
#define IREE_DEVICE_ID_TO_HIPDEVICE(device_id) (hipDevice_t)((device_id) - 1)
typedef struct iree_hal_hip_driver_t {
// Abstract resource used for injecting reference counting and vtable;
// must be at offset 0.
iree_hal_resource_t resource;
iree_allocator_t host_allocator;
// Identifier used for registering the driver in the IREE driver registry.
iree_string_view_t identifier;
// HIP driver API dynamic symbols to interact with the HIP system.
iree_hal_hip_dynamic_symbols_t hip_symbols;
// NCCL API dynamic symbols to use collectives (multi-gpu/multi-node).
iree_hal_hip_nccl_dynamic_symbols_t nccl_symbols;
// The default parameters for creating devices using this driver.
iree_hal_hip_device_params_t device_params;
// The index of the default HIP device to use if multiple ones are available.
int default_device_index;
} iree_hal_hip_driver_t;
static const iree_hal_driver_vtable_t iree_hal_hip_driver_vtable;
static iree_hal_hip_driver_t* iree_hal_hip_driver_cast(
iree_hal_driver_t* base_value) {
IREE_HAL_ASSERT_TYPE(base_value, &iree_hal_hip_driver_vtable);
return (iree_hal_hip_driver_t*)base_value;
}
IREE_API_EXPORT void iree_hal_hip_driver_options_initialize(
iree_hal_hip_driver_options_t* out_options) {
IREE_ASSERT_ARGUMENT(out_options);
memset(out_options, 0, sizeof(*out_options));
out_options->default_device_index = 0;
}
// Initializes the HIP system.
static iree_status_t iree_hal_hip_init(iree_hal_hip_driver_t* driver) {
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status =
IREE_HIP_CALL_TO_STATUS(&driver->hip_symbols, hipInit(0), "hipInit");
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_hal_hip_driver_create_internal(
iree_string_view_t identifier, const iree_hal_hip_driver_options_t* options,
const iree_hal_hip_device_params_t* device_params,
iree_allocator_t host_allocator, iree_hal_driver_t** out_driver) {
iree_hal_hip_driver_t* driver = NULL;
iree_host_size_t total_size = iree_sizeof_struct(*driver) + identifier.size;
IREE_RETURN_IF_ERROR(
iree_allocator_malloc(host_allocator, total_size, (void**)&driver));
iree_hal_resource_initialize(&iree_hal_hip_driver_vtable, &driver->resource);
driver->host_allocator = host_allocator;
iree_string_view_append_to_buffer(
identifier, &driver->identifier,
(char*)driver + iree_sizeof_struct(*driver));
driver->default_device_index = options->default_device_index;
iree_status_t status = iree_hal_hip_dynamic_symbols_initialize(
host_allocator, options->hip_lib_search_path_count,
options->hip_lib_search_paths, &driver->hip_symbols);
if (iree_status_is_ok(status)) {
// Try to dynamically load NCCL. This will fail if NCCL is unavailable or
// incompatible. We only fail on unavailability when the user tries to
// create a channel and otherwise defer reporting.
status = iree_hal_hip_nccl_dynamic_symbols_initialize(
host_allocator, &driver->hip_symbols, &driver->nccl_symbols);
if (iree_status_is_unavailable(status)) status = iree_status_ignore(status);
}
memcpy(&driver->device_params, device_params, sizeof(driver->device_params));
if (iree_status_is_ok(status)) {
status = iree_hal_hip_init(driver);
}
if (iree_status_is_ok(status)) {
*out_driver = (iree_hal_driver_t*)driver;
} else {
iree_hal_driver_release((iree_hal_driver_t*)driver);
}
return status;
}
IREE_API_EXPORT iree_status_t iree_hal_hip_driver_create(
iree_string_view_t identifier, const iree_hal_hip_driver_options_t* options,
const iree_hal_hip_device_params_t* device_params,
iree_allocator_t host_allocator, iree_hal_driver_t** out_driver) {
IREE_ASSERT_ARGUMENT(options);
IREE_ASSERT_ARGUMENT(device_params);
IREE_ASSERT_ARGUMENT(out_driver);
IREE_TRACE_ZONE_BEGIN(z0);
iree_status_t status = iree_hal_hip_driver_create_internal(
identifier, options, device_params, host_allocator, out_driver);
IREE_TRACE_ZONE_END(z0);
return status;
}
static void iree_hal_hip_driver_destroy(iree_hal_driver_t* base_driver) {
IREE_ASSERT_ARGUMENT(base_driver);
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
iree_allocator_t host_allocator = driver->host_allocator;
IREE_TRACE_ZONE_BEGIN(z0);
iree_hal_hip_nccl_dynamic_symbols_deinitialize(&driver->nccl_symbols);
iree_hal_hip_dynamic_symbols_deinitialize(&driver->hip_symbols);
iree_allocator_free(host_allocator, driver);
IREE_TRACE_ZONE_END(z0);
}
// Populates device information from the given HIP physical device handle.
// |out_device_info| must point to valid memory and additional data will be
// appended to |buffer_ptr| and the new pointer is returned.
static iree_status_t iree_hal_hip_populate_device_info(
hipDevice_t device, iree_hal_hip_dynamic_symbols_t* syms,
uint8_t* buffer_ptr, uint8_t** out_buffer_ptr,
iree_hal_device_info_t* out_device_info) {
*out_buffer_ptr = buffer_ptr;
char device_name[IREE_HAL_HIP_MAX_DEVICE_NAME_LENGTH];
IREE_HIP_RETURN_IF_ERROR(
syms, hipDeviceGetName(device_name, sizeof(device_name), device),
"hipDeviceGetName");
memset(out_device_info, 0, sizeof(*out_device_info));
out_device_info->device_id = IREE_HIPDEVICE_TO_DEVICE_ID(device);
hipUUID device_uuid;
IREE_HIP_RETURN_IF_ERROR(syms, hipDeviceGetUuid(&device_uuid, device),
"hipDeviceGetUuid");
char device_path_str[4 + 36 + 1] = {0};
snprintf(device_path_str, sizeof(device_path_str),
"GPU-"
"%02x%02x%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x%02x%02x%02x%02x",
(uint8_t)device_uuid.bytes[0], (uint8_t)device_uuid.bytes[1],
(uint8_t)device_uuid.bytes[2], (uint8_t)device_uuid.bytes[3],
(uint8_t)device_uuid.bytes[4], (uint8_t)device_uuid.bytes[5],
(uint8_t)device_uuid.bytes[6], (uint8_t)device_uuid.bytes[7],
(uint8_t)device_uuid.bytes[8], (uint8_t)device_uuid.bytes[9],
(uint8_t)device_uuid.bytes[10], (uint8_t)device_uuid.bytes[11],
(uint8_t)device_uuid.bytes[12], (uint8_t)device_uuid.bytes[13],
(uint8_t)device_uuid.bytes[14], (uint8_t)device_uuid.bytes[15]);
buffer_ptr += iree_string_view_append_to_buffer(
iree_make_string_view(device_path_str,
IREE_ARRAYSIZE(device_path_str) - 1),
&out_device_info->path, (char*)buffer_ptr);
iree_string_view_t device_name_str =
iree_make_string_view(device_name, strlen(device_name));
buffer_ptr += iree_string_view_append_to_buffer(
device_name_str, &out_device_info->name, (char*)buffer_ptr);
*out_buffer_ptr = buffer_ptr;
return iree_ok_status();
}
static iree_status_t iree_hal_hip_driver_query_available_devices(
iree_hal_driver_t* base_driver, iree_allocator_t host_allocator,
iree_host_size_t* out_device_info_count,
iree_hal_device_info_t** out_device_infos) {
IREE_ASSERT_ARGUMENT(base_driver);
IREE_ASSERT_ARGUMENT(out_device_info_count);
IREE_ASSERT_ARGUMENT(out_device_infos);
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
IREE_TRACE_ZONE_BEGIN(z0);
// Query the number of available HIP devices.
int device_count = 0;
IREE_HIP_RETURN_AND_END_ZONE_IF_ERROR(z0, &driver->hip_symbols,
hipGetDeviceCount(&device_count),
"hipGetDeviceCount");
// Allocate the return infos and populate with the devices.
iree_hal_device_info_t* device_infos = NULL;
iree_host_size_t total_size =
device_count * (sizeof(iree_hal_device_info_t) +
IREE_HAL_HIP_MAX_DEVICE_NAME_LENGTH * sizeof(char));
iree_status_t status =
iree_allocator_malloc(host_allocator, total_size, (void**)&device_infos);
int valid_device_count = 0;
if (iree_status_is_ok(status)) {
uint8_t* buffer_ptr =
(uint8_t*)device_infos + device_count * sizeof(*device_infos);
for (iree_host_size_t i = 0; i < device_count; ++i) {
hipDevice_t device = 0;
status = IREE_HIP_CALL_TO_STATUS(
&driver->hip_symbols, hipDeviceGet(&device, i), "hipDeviceGet");
if (!iree_status_is_ok(status)) break;
status = iree_hal_hip_populate_device_info(
device, &driver->hip_symbols, buffer_ptr, &buffer_ptr,
&device_infos[valid_device_count]);
if (!iree_status_is_ok(status)) break;
++valid_device_count;
}
}
if (iree_status_is_ok(status)) {
*out_device_info_count = valid_device_count;
*out_device_infos = device_infos;
} else {
iree_allocator_free(host_allocator, device_infos);
}
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_hal_hip_driver_dump_device_info(
iree_hal_driver_t* base_driver, iree_hal_device_id_t device_id,
iree_string_builder_t* builder) {
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
// Report path to the runtime library.
iree_string_builder_t path_builder;
iree_string_builder_initialize(builder->allocator, &path_builder);
iree_status_t status = iree_hal_hip_dynamic_symbols_append_path_to_builder(
&driver->hip_symbols, &path_builder);
if (iree_status_is_ok(status)) {
status = iree_string_builder_append_format(
builder, "\n- amdhip64_dylib_path: %s", path_builder.buffer);
iree_string_builder_deinitialize(&path_builder);
IREE_RETURN_IF_ERROR(status);
}
hipDevice_t device = IREE_DEVICE_ID_TO_HIPDEVICE(device_id);
hipDeviceProp_tR0000 prop;
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols,
hipGetDeviceProperties(&prop, device),
"hipGetDeviceProperties");
// GPU capabilities and architecture.
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-compute-capability: %d.%d", prop.major, prop.minor));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-arch-name: %s", prop.gcnArchName));
// Launch configuration limits.
IREE_RETURN_IF_ERROR(iree_string_builder_append_cstring(builder, "\n"));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- launch-max-block-dims: (%d, %d, %d)", prop.maxThreadsDim[0],
prop.maxThreadsDim[1], prop.maxThreadsDim[2]));
int shared_memory_kb = prop.sharedMemPerBlock / 1024;
IREE_RETURN_IF_ERROR(iree_string_builder_append_cstring(builder, "\n"));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- block-max-thread-count: %d", prop.maxThreadsPerBlock));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- block-max-32-bit-register-count: %d", prop.regsPerBlock));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- block-max-shared-memory: %d KB", shared_memory_kb));
// Memory hierarchy related information.
int const_memory_mb = prop.totalConstMem / 1024 / 1024;
int global_memory_mb = prop.totalGlobalMem / 1024 / 1024;
IREE_RETURN_IF_ERROR(iree_string_builder_append_cstring(builder, "\n"));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- memory-is-integrated-memory: %d", prop.integrated));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- memory-supports-managed-memory: %d", prop.managedMemory));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- memory-total-const-memory-size: %d MB", const_memory_mb));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- memory-total-global-memory-size: %d MB", global_memory_mb));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- memory-l2-cache-size: %d bytes", prop.l2CacheSize));
// GPU related information.
int compute_clock_mhz = prop.clockRate / 1000;
int memory_clock_mhz = prop.memoryClockRate / 1000;
IREE_RETURN_IF_ERROR(iree_string_builder_append_cstring(builder, "\n"));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-compute-unit-count: %d", prop.multiProcessorCount));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-compute-max-clock-rate: %d mHz", compute_clock_mhz));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-memory-max-clock-rate: %d mHz", memory_clock_mhz));
IREE_RETURN_IF_ERROR(iree_string_builder_append_format(
builder, "\n- gpu-warp-size: %d", prop.warpSize));
IREE_RETURN_IF_ERROR(iree_string_builder_append_cstring(builder, "\n"));
return iree_ok_status();
}
static iree_status_t iree_hal_hip_driver_select_default_device(
iree_hal_driver_t* base_driver, iree_hal_hip_dynamic_symbols_t* syms,
int default_device_index, iree_allocator_t host_allocator,
hipDevice_t* out_device) {
iree_hal_device_info_t* device_infos = NULL;
iree_host_size_t device_count = 0;
IREE_RETURN_IF_ERROR(iree_hal_hip_driver_query_available_devices(
base_driver, host_allocator, &device_count, &device_infos));
iree_status_t status = iree_ok_status();
if (device_count == 0) {
status = iree_make_status(IREE_STATUS_UNAVAILABLE,
"no compatible HIP devices were found");
} else if (default_device_index >= device_count) {
status = iree_make_status(IREE_STATUS_NOT_FOUND,
"default device %d not found (of %" PRIhsz
" enumerated)",
default_device_index, device_count);
} else {
*out_device = IREE_DEVICE_ID_TO_HIPDEVICE(
device_infos[default_device_index].device_id);
}
iree_allocator_free(host_allocator, device_infos);
return status;
}
static iree_status_t iree_hal_hip_driver_create_device_by_id(
iree_hal_driver_t* base_driver, iree_hal_device_id_t device_id,
iree_host_size_t param_count, const iree_string_pair_t* params,
iree_allocator_t host_allocator, iree_hal_device_t** out_device) {
IREE_ASSERT_ARGUMENT(base_driver);
IREE_ASSERT_ARGUMENT(out_device);
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
IREE_TRACE_ZONE_BEGIN(z0);
// Use either the specified device (enumerated earlier) or whatever default
// one was specified when the driver was created.
hipDevice_t device = 0;
if (device_id == IREE_HAL_DEVICE_ID_DEFAULT) {
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, iree_hal_hip_driver_select_default_device(
base_driver, &driver->hip_symbols, driver->default_device_index,
host_allocator, &device));
} else {
device = IREE_DEVICE_ID_TO_HIPDEVICE(device_id);
}
iree_string_view_t device_name = iree_make_cstring_view("hip");
// Attempt to create the device now.
iree_status_t status = iree_hal_hip_device_create(
base_driver, device_name, &driver->device_params, &driver->hip_symbols,
&driver->nccl_symbols, 1, &device, host_allocator, out_device);
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_hal_hip_driver_get_device_id_by_uuid(
iree_hal_driver_t* base_driver, iree_string_view_t device_path,
iree_hal_device_id_t* out_id) {
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
// Ensure HIP is initialized before querying it.
if (!iree_string_view_consume_prefix(&device_path, IREE_SV("GPU-"))) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"device path is not a UUID");
}
// UUID as returned by hipDeviceGetUuid.
hipUUID device_uuid;
if (!iree_string_view_parse_hex_bytes(device_path,
IREE_ARRAYSIZE(device_uuid.bytes),
(uint8_t*)device_uuid.bytes)) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"invalid GPU UUID: '%.*s'", (int)device_path.size,
device_path.data);
}
// HIP doesn't have an API to do this so we need to scan all devices to
// find the one with the matching UUID.
int device_count = 0;
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols,
hipGetDeviceCount(&device_count),
"hipGetDeviceCount");
hipDevice_t device = 0;
bool found_device = false;
for (int i = 0; i < device_count; i++) {
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols, hipDeviceGet(&device, i),
"hipDeviceGet");
hipUUID query_uuid;
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols,
hipDeviceGetUuid(&query_uuid, device),
"hipDeviceGetUuid");
if (memcmp(&device_uuid.bytes[0], &query_uuid.bytes[0],
sizeof(device_uuid)) == 0) {
found_device = true;
break;
}
}
if (!found_device) {
return iree_make_status(
IREE_STATUS_NOT_FOUND,
"HIP device with UUID GPU-"
"%02x%02x%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x-"
"%02x%02x%02x%02x%02x%02x"
" not found",
(uint8_t)device_uuid.bytes[0], (uint8_t)device_uuid.bytes[1],
(uint8_t)device_uuid.bytes[2], (uint8_t)device_uuid.bytes[3],
(uint8_t)device_uuid.bytes[4], (uint8_t)device_uuid.bytes[5],
(uint8_t)device_uuid.bytes[6], (uint8_t)device_uuid.bytes[7],
(uint8_t)device_uuid.bytes[8], (uint8_t)device_uuid.bytes[9],
(uint8_t)device_uuid.bytes[10], (uint8_t)device_uuid.bytes[11],
(uint8_t)device_uuid.bytes[12], (uint8_t)device_uuid.bytes[13],
(uint8_t)device_uuid.bytes[14], (uint8_t)device_uuid.bytes[15]);
}
*out_id = IREE_HIPDEVICE_TO_DEVICE_ID(device);
return iree_ok_status();
}
static iree_status_t iree_hal_hip_driver_get_device_id_by_index(
iree_hal_driver_t* base_driver, iree_string_view_t device_path,
iree_hal_device_id_t* out_id) {
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
int32_t device_index = 0;
if (!iree_string_view_atoi_int32(device_path, &device_index)) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"device path is not an index");
}
// Query the number of available HIP devices.
int device_count = 0;
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols,
hipGetDeviceCount(&device_count),
"hipGetDeviceCount");
if (device_index >= device_count) {
return iree_make_status(IREE_STATUS_NOT_FOUND,
"device %d not found (of %d enumerated)",
device_index, device_count);
}
hipDevice_t device = 0;
IREE_HIP_RETURN_IF_ERROR(&driver->hip_symbols,
hipDeviceGet(&device, device_index), "hipDeviceGet");
*out_id = IREE_HIPDEVICE_TO_DEVICE_ID(device);
return iree_ok_status();
}
static bool iree_hal_hip_driver_is_path_uuid(iree_string_view_t device_path) {
return iree_string_view_starts_with(device_path, IREE_SV("GPU-"));
}
static bool iree_hal_hip_driver_is_path_index(iree_string_view_t device_path) {
uint32_t unused_device_index = 0;
return iree_string_view_atoi_int32(device_path, &unused_device_index);
}
static iree_status_t iree_hal_hip_driver_get_device_id_by_path(
iree_hal_driver_t* base_driver, iree_string_view_t device_path,
iree_hal_device_id_t* out_id) {
if (iree_hal_hip_driver_is_path_uuid(device_path)) {
return iree_hal_hip_driver_get_device_id_by_uuid(base_driver, device_path,
out_id);
}
if (iree_hal_hip_driver_is_path_index(device_path)) {
return iree_hal_hip_driver_get_device_id_by_index(base_driver, device_path,
out_id);
}
return iree_make_status(IREE_STATUS_UNIMPLEMENTED, "unsupported device path");
}
static iree_status_t iree_hal_hip_driver_create_multi_queue_device_by_ids(
iree_hal_driver_t* base_driver, iree_hal_device_id_t* device_ids,
iree_host_size_t device_count, iree_host_size_t param_count,
const iree_string_pair_t* params, iree_allocator_t host_allocator,
iree_hal_device_t** out_device) {
IREE_ASSERT_ARGUMENT(base_driver);
IREE_ASSERT_ARGUMENT(out_device);
iree_hal_hip_driver_t* driver = iree_hal_hip_driver_cast(base_driver);
IREE_TRACE_ZONE_BEGIN(z0);
if (device_count > IREE_HAL_MAX_QUEUES) {
IREE_TRACE_ZONE_END(z0);
return iree_make_status(
IREE_STATUS_INVALID_ARGUMENT,
"too many physical devices allocated for this logical device");
}
hipDevice_t* devices =
(hipDevice_t*)iree_alloca(sizeof(*devices) * device_count);
for (iree_host_size_t i = 0; i < device_count; ++i) {
if (device_ids[i] == IREE_HAL_DEVICE_ID_DEFAULT) {
IREE_TRACE_ZONE_END(z0);
return iree_make_status(
IREE_STATUS_INVALID_ARGUMENT,
"invalid to create a device group with the default device id");
} else {
devices[i] = IREE_DEVICE_ID_TO_HIPDEVICE(device_ids[i]);
}
}
iree_string_view_t device_name = iree_make_cstring_view("hip");
// Attempt to create the device now.
iree_status_t status = iree_hal_hip_device_create(
base_driver, device_name, &driver->device_params, &driver->hip_symbols,
&driver->nccl_symbols, device_count, devices, host_allocator, out_device);
IREE_TRACE_ZONE_END(z0);
return status;
}
static iree_status_t iree_hal_hip_driver_create_multi_queue_device_by_path(
iree_hal_driver_t* base_driver, iree_string_view_t driver_name,
iree_string_view_t device_path, iree_host_size_t param_count,
const iree_string_pair_t* params, iree_allocator_t host_allocator,
iree_hal_device_t** out_device) {
IREE_ASSERT_ARGUMENT(base_driver);
IREE_ASSERT_ARGUMENT(out_device);
iree_host_size_t multi_count = 0;
for (iree_host_size_t offs = 0; offs < device_path.size;) {
iree_host_size_t comma_pos =
iree_string_view_find_char(device_path, ',', offs);
if (comma_pos == IREE_STRING_VIEW_NPOS) {
comma_pos = device_path.size;
}
offs = comma_pos + 1;
++multi_count;
}
iree_hal_device_id_t* device_ids = NULL;
IREE_RETURN_IF_ERROR(iree_allocator_malloc(
host_allocator, sizeof(*device_ids) * multi_count, (void**)&device_ids));
iree_host_size_t device_index = 0;
for (iree_host_size_t offset = 0; offset < device_path.size;) {
iree_host_size_t comma_pos =
iree_string_view_find_char(device_path, ',', offset);
if (comma_pos == IREE_STRING_VIEW_NPOS) {
comma_pos = device_path.size;
}
iree_string_view_t this_device_path =
iree_string_view_substr(device_path, offset, comma_pos - offset);
iree_status_t status = iree_hal_hip_driver_get_device_id_by_path(
base_driver, this_device_path, &device_ids[device_index]);
if (IREE_UNLIKELY(!iree_status_is_ok(status))) {
iree_allocator_free(host_allocator, device_ids);
return status;
}
offset = comma_pos + 1;
++device_index;
}
iree_status_t status = iree_hal_hip_driver_create_multi_queue_device_by_ids(
base_driver, device_ids, device_index, param_count, params,
host_allocator, out_device);
iree_allocator_free(host_allocator, device_ids);
return status;
}
static iree_status_t iree_hal_hip_driver_create_device_by_path(
iree_hal_driver_t* base_driver, iree_string_view_t driver_name,
iree_string_view_t device_path, iree_host_size_t param_count,
const iree_string_pair_t* params, iree_allocator_t host_allocator,
iree_hal_device_t** out_device) {
IREE_ASSERT_ARGUMENT(base_driver);
IREE_ASSERT_ARGUMENT(out_device);
if (iree_string_view_is_empty(device_path)) {
return iree_hal_hip_driver_create_device_by_id(
base_driver, IREE_HAL_DEVICE_ID_DEFAULT, param_count, params,
host_allocator, out_device);
}
if (iree_string_view_find_char(device_path, ',', 0) !=
IREE_STRING_VIEW_NPOS) {
return iree_hal_hip_driver_create_multi_queue_device_by_path(
base_driver, driver_name, device_path, param_count, params,
host_allocator, out_device);
}
iree_hal_device_id_t id;
IREE_RETURN_IF_ERROR(
iree_hal_hip_driver_get_device_id_by_path(base_driver, device_path, &id));
return iree_hal_hip_driver_create_device_by_id(
base_driver, id, param_count, params, host_allocator, out_device);
}
static const iree_hal_driver_vtable_t iree_hal_hip_driver_vtable = {
.destroy = iree_hal_hip_driver_destroy,
.query_available_devices = iree_hal_hip_driver_query_available_devices,
.dump_device_info = iree_hal_hip_driver_dump_device_info,
.create_device_by_id = iree_hal_hip_driver_create_device_by_id,
.create_device_by_path = iree_hal_hip_driver_create_device_by_path,
};