[Runtime] Align `iree_async_posix_worker_t` (#24589)
Fix #24578
The fix includes aligning `iree_async_posix_worker_t` to
`iree_hardware_constructive_interference_size`.
Pertaining to the concern of possible improper offset via pointer
casting mentioned in this
[comment](https://github.com/iree-org/iree/issues/24578#issuecomment-4646834986)
, it comes from line 179 in file
`runtime\src\iree\async\platform\posix\proactor.c`:
```cpp
// Set up pointers into trailing data.
proactor->workers =
(iree_async_posix_worker_t*)((uint8_t*)proactor + workers_offset); // <- This
proactor->worker_count = worker_count;
```
The worker offset is calculated from line 148 in the same file:
```cpp
IREE_RETURN_AND_END_ZONE_IF_ERROR(
z0, IREE_STRUCT_LAYOUT(
sizeof(iree_async_proactor_posix_t), &total_size,
IREE_STRUCT_FIELD_ALIGNED(
worker_count, iree_async_posix_worker_t,
iree_hardware_destructive_interference_size, &workers_offset), // <- This
IREE_STRUCT_FIELD_ALIGNED(
ready_pool_capacity, iree_async_posix_ready_op_t,
iree_hardware_destructive_interference_size,
&ready_entries_offset),
IREE_STRUCT_FIELD(completion_pool_capacity,
iree_async_posix_completion_t,
&completion_entries_offset),
IREE_STRUCT_FIELD(message_pool_capacity,
iree_async_message_pool_entry_t,
&message_entries_offset)))
```
From what I read, `IREE_STRUCT_FIELD_ALIGNED` considers the alignment. I
supposed the offset calculation should be correct, especially with the
alignment to be the same.
Moreover, I've also saw some manual padding in the struct via
`_padding`. I remove such padding as I suppose the alignment will pad
for us.
---------
Signed-off-by: Rechie Kho <50512341+RechieKho@users.noreply.github.com>diff --git a/runtime/src/iree/async/platform/posix/proactor.c b/runtime/src/iree/async/platform/posix/proactor.c
index 81f821b..b3a8fc5 100644
--- a/runtime/src/iree/async/platform/posix/proactor.c
+++ b/runtime/src/iree/async/platform/posix/proactor.c
@@ -160,7 +160,10 @@
// Single allocation for everything.
iree_async_proactor_posix_t* proactor = NULL;
IREE_RETURN_AND_END_ZONE_IF_ERROR(
- z0, iree_allocator_malloc(allocator, total_size, (void**)&proactor));
+ z0,
+ iree_allocator_malloc_aligned(allocator, total_size,
+ iree_hardware_destructive_interference_size,
+ 0, (void**)&proactor));
memset(proactor, 0, total_size);
// Initialize base proactor.
@@ -348,7 +351,7 @@
// Free the single allocation.
iree_allocator_t allocator = proactor->base.allocator;
- iree_allocator_free(allocator, proactor);
+ iree_allocator_free_aligned(allocator, proactor);
IREE_TRACE_ZONE_END(z0);
}
diff --git a/runtime/src/iree/async/platform/posix/worker.h b/runtime/src/iree/async/platform/posix/worker.h
index 3eca7fc..3c546f4 100644
--- a/runtime/src/iree/async/platform/posix/worker.h
+++ b/runtime/src/iree/async/platform/posix/worker.h
@@ -51,7 +51,11 @@
// Workers share proactor->ready_notification for work-stealing: all workers
// wait on the same notification, and enqueue_for_execution posts to it to
// wake exactly one idle worker.
-typedef struct iree_async_posix_worker_t {
+//
+// Alignment is added to ensure struct spans at least one cache line (64 bytes)
+// to minimize false sharing when workers are stored in a contiguous array.
+typedef struct iree_alignas(iree_hardware_destructive_interference_size)
+ iree_async_posix_worker_t {
// Current state (atomic for cross-thread visibility).
// Written by request_exit, read by worker loop.
iree_atomic_int32_t state;
@@ -71,18 +75,8 @@
// Thread handle (owned, released in deinitialize).
iree_thread_t* thread;
-
- // Padding to ensure struct spans at least one cache line (64 bytes) to
- // minimize false sharing when workers are stored in a contiguous array.
- uint8_t _padding[24];
} iree_async_posix_worker_t;
-// Verify worker struct spans at least one cache line to minimize false sharing
-// when workers are stored in a contiguous array.
-static_assert(sizeof(iree_async_posix_worker_t) >=
- iree_hardware_constructive_interference_size,
- "worker struct should span at least one cache line");
-
// Initializes a worker and starts its thread.
// |out_worker| must point to caller-allocated storage (typically in the
// proactor's trailing data array).