blob: 85b779e672bcd02c9e77c4cd0b747853597c7a61 [file]
// Copyright 2026 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 "iree/hal/profile_options.h"
#include <inttypes.h>
#include <string.h>
#include "iree/hal/profile_sink.h"
//===----------------------------------------------------------------------===//
// iree_hal_device_profiling_options_t
//===----------------------------------------------------------------------===//
struct iree_hal_device_profiling_options_storage_t {
// Retained sink referenced by the cloned options, or NULL.
iree_hal_profile_sink_t* sink;
};
static iree_status_t iree_hal_device_profiling_options_add_string_storage(
iree_host_size_t string_length, iree_host_size_t* inout_storage_length) {
if (string_length == 0) return iree_ok_status();
if (IREE_UNLIKELY(!iree_host_size_checked_add(
*inout_storage_length, string_length, inout_storage_length))) {
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"profiling options string storage overflow");
}
return iree_ok_status();
}
static iree_string_view_t iree_hal_device_profiling_options_clone_string_view(
iree_string_view_t source, char** inout_storage) {
if (iree_string_view_is_empty(source)) return iree_string_view_empty();
char* storage = *inout_storage;
memcpy(storage, source.data, source.size);
*inout_storage += source.size;
return iree_make_string_view(storage, source.size);
}
IREE_API_EXPORT iree_status_t iree_hal_device_profiling_options_clone(
const iree_hal_device_profiling_options_t* source_options,
iree_allocator_t host_allocator,
iree_hal_device_profiling_options_t* out_options,
iree_hal_device_profiling_options_storage_t** out_storage) {
IREE_ASSERT_ARGUMENT(source_options);
IREE_ASSERT_ARGUMENT(out_options);
IREE_ASSERT_ARGUMENT(out_storage);
*out_options = (iree_hal_device_profiling_options_t){0};
*out_storage = NULL;
iree_string_view_t executable_function_pattern = iree_string_view_empty();
if (iree_any_bit_set(
source_options->capture_filter.flags,
IREE_HAL_PROFILE_CAPTURE_FILTER_FLAG_EXECUTABLE_FUNCTION_PATTERN)) {
executable_function_pattern =
source_options->capture_filter.executable_function_pattern;
if (iree_string_view_is_empty(executable_function_pattern)) {
return iree_make_status(IREE_STATUS_INVALID_ARGUMENT,
"profile capture executable function filter must "
"not be empty");
}
}
if (source_options->counter_set_count && !source_options->counter_sets) {
return iree_make_status(
IREE_STATUS_INVALID_ARGUMENT,
"hardware counter set selections require a counter_sets array");
}
iree_host_size_t counter_name_total_count = 0;
iree_host_size_t string_storage_length = 0;
IREE_RETURN_IF_ERROR(iree_hal_device_profiling_options_add_string_storage(
executable_function_pattern.size, &string_storage_length));
for (iree_host_size_t i = 0; i < source_options->counter_set_count; ++i) {
const iree_hal_profile_counter_set_selection_t* source_counter_set =
&source_options->counter_sets[i];
if (source_counter_set->counter_name_count &&
!source_counter_set->counter_names) {
return iree_make_status(
IREE_STATUS_INVALID_ARGUMENT,
"hardware counter set %" PRIhsz
" has a counter_name_count but no counter_names array",
i);
}
if (IREE_UNLIKELY(!iree_host_size_checked_add(
counter_name_total_count, source_counter_set->counter_name_count,
&counter_name_total_count))) {
return iree_make_status(IREE_STATUS_OUT_OF_RANGE,
"hardware counter name count overflow");
}
IREE_RETURN_IF_ERROR(iree_hal_device_profiling_options_add_string_storage(
source_counter_set->name.size, &string_storage_length));
for (iree_host_size_t j = 0; j < source_counter_set->counter_name_count;
++j) {
IREE_RETURN_IF_ERROR(iree_hal_device_profiling_options_add_string_storage(
source_counter_set->counter_names[j].size, &string_storage_length));
}
}
iree_host_size_t counter_sets_offset = 0;
iree_host_size_t counter_names_offset = 0;
iree_host_size_t string_storage_offset = 0;
iree_host_size_t total_size = 0;
IREE_RETURN_IF_ERROR(IREE_STRUCT_LAYOUT(
sizeof(iree_hal_device_profiling_options_storage_t), &total_size,
IREE_STRUCT_FIELD(source_options->counter_set_count,
iree_hal_profile_counter_set_selection_t,
&counter_sets_offset),
IREE_STRUCT_FIELD(counter_name_total_count, iree_string_view_t,
&counter_names_offset),
IREE_STRUCT_FIELD(string_storage_length, char, &string_storage_offset)));
iree_hal_device_profiling_options_storage_t* storage = NULL;
IREE_RETURN_IF_ERROR(
iree_allocator_malloc(host_allocator, total_size, (void**)&storage));
memset(storage, 0, total_size);
iree_hal_device_profiling_options_t cloned_options = *source_options;
if (cloned_options.sink) {
iree_hal_profile_sink_retain(cloned_options.sink);
storage->sink = cloned_options.sink;
}
char* string_storage = (char*)storage + string_storage_offset;
cloned_options.capture_filter.executable_function_pattern =
iree_string_view_empty();
if (!iree_string_view_is_empty(executable_function_pattern)) {
cloned_options.capture_filter.executable_function_pattern =
iree_hal_device_profiling_options_clone_string_view(
executable_function_pattern, &string_storage);
}
if (source_options->counter_set_count) {
iree_hal_profile_counter_set_selection_t* counter_sets =
(iree_hal_profile_counter_set_selection_t*)((uint8_t*)storage +
counter_sets_offset);
iree_string_view_t* counter_names =
(iree_string_view_t*)((uint8_t*)storage + counter_names_offset);
for (iree_host_size_t i = 0; i < source_options->counter_set_count; ++i) {
const iree_hal_profile_counter_set_selection_t* source_counter_set =
&source_options->counter_sets[i];
counter_sets[i] = *source_counter_set;
counter_sets[i].name =
iree_hal_device_profiling_options_clone_string_view(
source_counter_set->name, &string_storage);
if (source_counter_set->counter_name_count) {
counter_sets[i].counter_names = counter_names;
for (iree_host_size_t j = 0; j < source_counter_set->counter_name_count;
++j) {
counter_names[j] =
iree_hal_device_profiling_options_clone_string_view(
source_counter_set->counter_names[j], &string_storage);
}
counter_names += source_counter_set->counter_name_count;
} else {
counter_sets[i].counter_names = NULL;
}
}
cloned_options.counter_sets = counter_sets;
} else {
cloned_options.counter_sets = NULL;
}
*out_options = cloned_options;
*out_storage = storage;
return iree_ok_status();
}
IREE_API_EXPORT void iree_hal_device_profiling_options_storage_free(
iree_hal_device_profiling_options_storage_t* storage,
iree_allocator_t host_allocator) {
if (!storage) return;
iree_hal_profile_sink_release(storage->sink);
iree_allocator_free(host_allocator, storage);
}