| // Copyright 2021 Google LLC |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // https://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "iree/hal/local/event_pool.h" |
| |
| #include "iree/base/debugging.h" |
| #include "iree/base/synchronization.h" |
| #include "iree/base/tracing.h" |
| |
| struct iree_hal_local_event_pool_s { |
| // Allocator used to create the event pool. |
| iree_allocator_t host_allocator; |
| // Guards the pool. Since this pool is used to get operating system-level |
| // event objects that will be signaled and waited on using syscalls it's got |
| // relatively low contention: callers are rate limited by how fast they can |
| // signal and wait on the events they get. |
| iree_slim_mutex_t mutex; |
| // Maximum number of events that will be maintained in the pool. More events |
| // may be allocated at any time but when they are no longer needed they will |
| // be disposed directly. |
| iree_host_size_t available_capacity; |
| // Total number of available |
| iree_host_size_t available_count; |
| // Dense left-aligned list of available_count events. |
| iree_event_t available_list[]; |
| }; |
| |
| iree_status_t iree_hal_local_event_pool_allocate( |
| iree_host_size_t available_capacity, iree_allocator_t host_allocator, |
| iree_hal_local_event_pool_t** out_event_pool) { |
| IREE_ASSERT_ARGUMENT(out_event_pool); |
| *out_event_pool = NULL; |
| IREE_TRACE_ZONE_BEGIN(z0); |
| |
| iree_hal_local_event_pool_t* event_pool = NULL; |
| iree_host_size_t total_size = |
| sizeof(*event_pool) + |
| available_capacity * sizeof(event_pool->available_list[0]); |
| IREE_RETURN_AND_END_ZONE_IF_ERROR( |
| z0, |
| iree_allocator_malloc(host_allocator, total_size, (void**)&event_pool)); |
| event_pool->host_allocator = host_allocator; |
| event_pool->available_capacity = available_capacity; |
| event_pool->available_count = 0; |
| |
| iree_status_t status = iree_ok_status(); |
| for (iree_host_size_t i = 0; i < available_capacity; ++i) { |
| status = iree_event_initialize( |
| /*initial_state=*/false, |
| &event_pool->available_list[event_pool->available_count++]); |
| if (!iree_status_is_ok(status)) break; |
| } |
| |
| if (iree_status_is_ok(status)) { |
| *out_event_pool = event_pool; |
| } else { |
| iree_hal_local_event_pool_free(event_pool); |
| } |
| IREE_TRACE_ZONE_END(z0); |
| return status; |
| } |
| |
| void iree_hal_local_event_pool_free(iree_hal_local_event_pool_t* event_pool) { |
| iree_allocator_t host_allocator = event_pool->host_allocator; |
| IREE_TRACE_ZONE_BEGIN(z0); |
| |
| for (iree_host_size_t i = 0; i < event_pool->available_count; ++i) { |
| iree_event_deinitialize(&event_pool->available_list[i]); |
| } |
| iree_slim_mutex_deinitialize(&event_pool->mutex); |
| iree_allocator_free(host_allocator, event_pool); |
| |
| IREE_TRACE_ZONE_END(z0); |
| } |
| |
| iree_status_t iree_hal_local_event_pool_acquire( |
| iree_hal_local_event_pool_t* event_pool, iree_host_size_t event_count, |
| iree_event_t* out_events) { |
| IREE_ASSERT_ARGUMENT(event_pool); |
| if (!event_count) return iree_ok_status(); |
| IREE_ASSERT_ARGUMENT(out_events); |
| |
| // We'll try to get what we can from the pool and fall back to initializing |
| // new events. |
| iree_host_size_t remaining_count = event_count; |
| |
| // Try first to grab from the pool. |
| iree_slim_mutex_lock(&event_pool->mutex); |
| iree_host_size_t from_pool_count = |
| iree_min(event_pool->available_count, event_count); |
| if (from_pool_count > 0) { |
| iree_host_size_t pool_base_index = |
| event_pool->available_count - from_pool_count; |
| memcpy(out_events, &event_pool->available_list[pool_base_index], |
| from_pool_count * sizeof(iree_event_t)); |
| event_pool->available_count -= from_pool_count; |
| remaining_count -= from_pool_count; |
| } |
| iree_slim_mutex_unlock(&event_pool->mutex); |
| |
| // Allocate the rest of the events. |
| if (remaining_count > 0) { |
| IREE_TRACE_ZONE_BEGIN(z0); |
| iree_status_t status = iree_ok_status(); |
| for (iree_host_size_t i = 0; i < remaining_count; ++i) { |
| status = iree_event_initialize(/*initial_state=*/false, |
| &out_events[from_pool_count + i]); |
| if (!iree_status_is_ok(status)) { |
| // Must release all events we've acquired so far. |
| iree_hal_local_event_pool_release(event_pool, from_pool_count + i, |
| out_events); |
| IREE_TRACE_ZONE_END(z0); |
| return status; |
| } |
| } |
| IREE_TRACE_ZONE_END(z0); |
| } |
| |
| return iree_ok_status(); |
| } |
| |
| void iree_hal_local_event_pool_release(iree_hal_local_event_pool_t* event_pool, |
| iree_host_size_t event_count, |
| iree_event_t* events) { |
| IREE_ASSERT_ARGUMENT(event_pool); |
| if (!event_count) return; |
| IREE_ASSERT_ARGUMENT(events); |
| |
| // We'll try to release all we can back to the pool and then deinitialize |
| // the ones that won't fit. |
| iree_host_size_t remaining_count = event_count; |
| |
| // Try first to release to the pool. |
| // Note that we reset the events we add back to the pool so that they are |
| // ready to be acquired again. |
| iree_slim_mutex_lock(&event_pool->mutex); |
| iree_host_size_t to_pool_count = |
| iree_min(event_pool->available_capacity - event_pool->available_count, |
| event_count); |
| if (to_pool_count > 0) { |
| iree_host_size_t pool_base_index = event_pool->available_count; |
| for (iree_host_size_t i = 0; i < to_pool_count; ++i) { |
| iree_event_reset(&events[i]); |
| } |
| memcpy(&event_pool->available_list[pool_base_index], events, |
| to_pool_count * sizeof(iree_event_t)); |
| event_pool->available_count += to_pool_count; |
| remaining_count -= to_pool_count; |
| } |
| iree_slim_mutex_unlock(&event_pool->mutex); |
| |
| // Deallocate the rest of the events. We don't bother resetting them as we are |
| // getting rid of them. |
| if (remaining_count > 0) { |
| IREE_TRACE_ZONE_BEGIN(z0); |
| for (iree_host_size_t i = 0; i < remaining_count; ++i) { |
| iree_event_deinitialize(&events[to_pool_count + i]); |
| } |
| IREE_TRACE_ZONE_END(z0); |
| } |
| } |