Allows moving the pointer swap between server and client into reset.
Single allocation simplifies whatever allocates the client/server, currently
the libc loaders.
Reviewed By: jhuber6
Differential Revision: https://reviews.llvm.org/D150337
cpp::Atomic<uint32_t> lock[default_port_count] = {0};
/// Initialize the communication channels.
- LIBC_INLINE void reset(uint64_t port_count, uint32_t lane_size, void *inbox,
- void *outbox, void *packet) {
+ LIBC_INLINE void reset(uint64_t port_count, uint32_t lane_size, void *state) {
+ uint64_t p = memory_offset_primary_mailbox(port_count);
+ uint64_t s = memory_offset_secondary_mailbox(port_count);
this->port_count = port_count;
this->lane_size = lane_size;
- this->inbox = reinterpret_cast<cpp::Atomic<uint32_t> *>(inbox);
- this->outbox = reinterpret_cast<cpp::Atomic<uint32_t> *>(outbox);
- this->packet = reinterpret_cast<Packet *>(packet);
+ this->inbox = reinterpret_cast<cpp::Atomic<uint32_t> *>(
+ static_cast<char *>(state) + (InvertInbox ? s : p));
+ this->outbox = reinterpret_cast<cpp::Atomic<uint32_t> *>(
+ static_cast<char *>(state) + (InvertInbox ? p : s));
+ this->packet = reinterpret_cast<Packet *>(static_cast<char *>(state) +
+ memory_offset_buffer(port_count));
+ }
+
+ /// Allocate a single block of memory for use by client and server
+ /// template<size_t N>, N is generally a runtime value
+ /// struct equivalent {
+ /// atomic<uint32_t> primary[N];
+ /// atomic<uint32_t> secondary[N];
+ /// Packet buffer[N];
+ /// };
+ LIBC_INLINE static uint64_t allocation_size(uint64_t port_count,
+ uint32_t lane_size) {
+ return memory_offset_buffer(port_count) +
+ memory_allocated_buffer(port_count, lane_size);
}
/// The length of the packet is flexible because the server needs to look up
fn(&packet.payload.slot[i], i);
}
}
+
+ /// Number of bytes allocated for mailbox or buffer
+ LIBC_INLINE static uint64_t memory_allocated_mailbox(uint64_t port_count) {
+ return port_count * sizeof(cpp::Atomic<uint32_t>);
+ }
+
+ LIBC_INLINE static uint64_t memory_allocated_buffer(uint64_t port_count,
+ uint32_t lane_size) {
+#if defined(LIBC_TARGET_ARCH_IS_GPU)
+ (void)lane_size;
+ return port_count * sizeof(Packet);
+#else
+ return port_count * (sizeof(Packet) + sizeof(Buffer) * lane_size);
+#endif
+ }
+
+ /// Offset of mailbox/buffer in single allocation
+ LIBC_INLINE static uint64_t
+ memory_offset_primary_mailbox(uint64_t /*port_count*/) {
+ return 0;
+ }
+ LIBC_INLINE static uint64_t
+ memory_offset_secondary_mailbox(uint64_t port_count) {
+ return memory_allocated_mailbox(port_count);
+ }
+ LIBC_INLINE static uint64_t memory_offset_buffer(uint64_t port_count) {
+ return align_up(2 * memory_allocated_mailbox(port_count), alignof(Packet));
+ }
};
/// The port provides the interface to communicate between the multiple
} // namespace __llvm_libc
extern "C" [[gnu::visibility("protected"), clang::amdgpu_kernel]] void
-_begin(int argc, char **argv, char **env, void *in, void *out, void *buffer) {
+_begin(int argc, char **argv, char **env, void *rpc_shared_buffer) {
// We need to set up the RPC client first in case any of the constructors
// require it.
__llvm_libc::rpc::client.reset(__llvm_libc::rpc::default_port_count,
- __llvm_libc::gpu::get_lane_size(), in, out,
- buffer);
+ __llvm_libc::gpu::get_lane_size(),
+ rpc_shared_buffer);
// We want the fini array callbacks to be run after other atexit
// callbacks are run. So, we register them before running the init
} // namespace __llvm_libc
extern "C" [[gnu::visibility("protected"), clang::nvptx_kernel]] void
-_begin(int argc, char **argv, char **env, void *in, void *out, void *buffer) {
+_begin(int argc, char **argv, char **env, void *rpc_shared_buffer) {
// We need to set up the RPC client first in case any of the constructors
// require it.
__llvm_libc::rpc::client.reset(__llvm_libc::rpc::default_port_count,
- __llvm_libc::gpu::get_lane_size(), in, out,
- buffer);
+ __llvm_libc::gpu::get_lane_size(),
+ rpc_shared_buffer);
// We want the fini array callbacks to be run after other atexit
// callbacks are run. So, we register them before running the init
int argc;
void *argv;
void *envp;
- void *inbox;
- void *outbox;
- void *buffer;
+ void *rpc_shared_buffer;
};
/// The arguments to the '_start' kernel.
if (hsa_status_t err = hsa_agent_get_info(
dev_agent, HSA_AGENT_INFO_WAVEFRONT_SIZE, &wavefront_size))
handle_error(err);
- void *server_inbox;
- void *server_outbox;
- void *buffer;
- if (hsa_status_t err = hsa_amd_memory_pool_allocate(
- finegrained_pool, port_size * sizeof(__llvm_libc::cpp::Atomic<int>),
- /*flags=*/0, &server_inbox))
- handle_error(err);
- if (hsa_status_t err = hsa_amd_memory_pool_allocate(
- finegrained_pool, port_size * sizeof(__llvm_libc::cpp::Atomic<int>),
- /*flags=*/0, &server_outbox))
- handle_error(err);
- if (hsa_status_t err = hsa_amd_memory_pool_allocate(
- finegrained_pool,
- port_size *
- align_up(sizeof(__llvm_libc::rpc::Header) +
- (wavefront_size * sizeof(__llvm_libc::rpc::Buffer)),
- alignof(__llvm_libc::rpc::Packet)),
- /*flags=*/0, &buffer))
- handle_error(err);
- hsa_amd_agents_allow_access(1, &dev_agent, nullptr, server_inbox);
- hsa_amd_agents_allow_access(1, &dev_agent, nullptr, server_outbox);
- hsa_amd_agents_allow_access(1, &dev_agent, nullptr, buffer);
+
+ uint64_t rpc_shared_buffer_size =
+ __llvm_libc::rpc::Server::allocation_size(port_size, wavefront_size);
+ void *rpc_shared_buffer;
+ if (hsa_status_t err =
+ hsa_amd_memory_pool_allocate(finegrained_pool, rpc_shared_buffer_size,
+ /*flags=*/0, &rpc_shared_buffer))
+ handle_error(err);
+ hsa_amd_agents_allow_access(1, &dev_agent, nullptr, rpc_shared_buffer);
// Initialize the RPC server's buffer for host-device communication.
- server.reset(port_size, wavefront_size, server_inbox, server_outbox, buffer);
+ server.reset(port_size, wavefront_size, rpc_shared_buffer);
// Obtain a queue with the minimum (power of two) size, used to send commands
// to the HSA runtime and launch execution on the device.
handle_error(err);
LaunchParameters single_threaded_params = {1, 1, 1, 1, 1, 1};
- begin_args_t init_args = {argc, dev_argv, dev_envp,
- server_outbox, server_inbox, buffer};
+ begin_args_t init_args = {argc, dev_argv, dev_envp, rpc_shared_buffer};
if (hsa_status_t err =
launch_kernel(dev_agent, executable, kernargs_pool, queue,
single_threaded_params, "_begin.kd", init_args))
handle_error(err);
if (hsa_status_t err = hsa_amd_memory_pool_free(dev_ret))
handle_error(err);
- if (hsa_status_t err = hsa_amd_memory_pool_free(server_inbox))
- handle_error(err);
- if (hsa_status_t err = hsa_amd_memory_pool_free(server_outbox))
- handle_error(err);
- if (hsa_status_t err = hsa_amd_memory_pool_free(buffer))
+ if (hsa_status_t err = hsa_amd_memory_pool_free(rpc_shared_buffer))
handle_error(err);
if (hsa_status_t err = hsa_amd_memory_pool_free(host_ret))
handle_error(err);
uint64_t port_size = __llvm_libc::rpc::default_port_count;
uint32_t warp_size = 32;
- void *server_inbox =
- allocator(port_size * sizeof(__llvm_libc::cpp::Atomic<int>));
- void *server_outbox =
- allocator(port_size * sizeof(__llvm_libc::cpp::Atomic<int>));
- void *buffer = allocator(
- port_size * align_up(sizeof(__llvm_libc::rpc::Header) +
- (warp_size * sizeof(__llvm_libc::rpc::Buffer)),
- alignof(__llvm_libc::rpc::Packet)));
- if (!server_inbox || !server_outbox || !buffer)
+
+ uint64_t rpc_shared_buffer_size =
+ __llvm_libc::rpc::Server::allocation_size(port_size, warp_size);
+ void *rpc_shared_buffer = allocator(rpc_shared_buffer_size);
+
+ if (!rpc_shared_buffer)
handle_error("Failed to allocate memory the RPC client / server.");
// Initialize the RPC server's buffer for host-device communication.
- server.reset(port_size, warp_size, server_inbox, server_outbox, buffer);
+ server.reset(port_size, warp_size, rpc_shared_buffer);
LaunchParameters single_threaded_params = {1, 1, 1, 1, 1, 1};
// Call the kernel to
- begin_args_t init_args = {argc, dev_argv, dev_envp,
- server_outbox, server_inbox, buffer};
+ begin_args_t init_args = {argc, dev_argv, dev_envp, rpc_shared_buffer};
if (CUresult err = launch_kernel(binary, stream, single_threaded_params,
"_begin", init_args))
handle_error(err);
handle_error(err);
if (CUresult err = cuMemFreeHost(dev_argv))
handle_error(err);
- if (CUresult err = cuMemFreeHost(server_inbox))
- handle_error(err);
- if (CUresult err = cuMemFreeHost(server_outbox))
- handle_error(err);
- if (CUresult err = cuMemFreeHost(buffer))
+ if (CUresult err = cuMemFreeHost(rpc_shared_buffer))
handle_error(err);
// Destroy the context and the loaded binary.