Skip to content

Commit

Permalink
[libc] Export the RPC interface from libc
Browse files Browse the repository at this point in the history
Summary:
This patch adds new extensions that allow us to export the RPC interface
from `libc` to other programs. This should allow external users of the
GPU `libc` to interface with the RPC client (which more or less behaves
like syscalls in this context). This is done by wrapping the interface
into a C-style function call.

Obviously, this approach is far less safe than the carefully crafted C++
interface. For example, we now expose the internal packet buffer, and it
is theoretically possible to open a single port with conflicting opcodes
and break the whole interface. So, extra care will be needed when
interacting with this. However, the usage is very similar as shown by
the new test.

This somewhat stretches the concept of `libc` just doing `libc` things,
but I think this is important enough to justify it. It is difficult to
split this out, as we do not want to have the situation where we have
multiple RPC clients running at one time, so for now it makes sense to
just leave it in `libc`.
  • Loading branch information
jhuber6 committed Mar 11, 2024
1 parent 9bc294f commit 6820c7a
Show file tree
Hide file tree
Showing 20 changed files with 384 additions and 6 deletions.
4 changes: 4 additions & 0 deletions libc/config/gpu/entrypoints.txt
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,10 @@ set(TARGET_LIBC_ENTRYPOINTS

# gpu/rpc.h entrypoints
libc.src.gpu.rpc_host_call
libc.src.gpu.rpc_open_port
libc.src.gpu.rpc_send_n
libc.src.gpu.rpc_recv_n
libc.src.gpu.rpc_close_port
)

set(TARGET_LIBM_ENTRYPOINTS
Expand Down
1 change: 1 addition & 0 deletions libc/include/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -604,6 +604,7 @@ if(LIBC_TARGET_OS_IS_GPU)
DEPENDS
.llvm_libc_common_h
.llvm-libc-types.rpc_opcodes_t
.llvm-libc-types.rpc_port_t
)
endif()

Expand Down
3 changes: 3 additions & 0 deletions libc/include/gpu/rpc.h.def
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,10 @@

#include <__llvm-libc-common.h>

#include <llvm-libc-types/size_t.h>

#include <llvm-libc-types/rpc_opcodes_t.h>
#include <llvm-libc-types/rpc_port_t.h>

%%public_api()

Expand Down
1 change: 1 addition & 0 deletions libc/include/llvm-libc-types/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ add_header(socklen_t HDR socklen_t.h)
add_header(struct_sockaddr_un HDR struct_sockaddr_un.h)
add_header(struct_sockaddr HDR struct_sockaddr.h)
add_header(rpc_opcodes_t HDR rpc_opcodes_t.h)
add_header(rpc_port_t HDR rpc_port_t.h)
add_header(ACTION HDR ACTION.h)
add_header(ENTRY HDR ENTRY.h)
add_header(struct_hsearch_data HDR struct_hsearch_data.h)
Expand Down
16 changes: 16 additions & 0 deletions libc/include/llvm-libc-types/rpc_port_t.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
//===-- Definition of type rpc_port_t -------------------------------------===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef __LLVM_LIBC_TYPES_RPC_PORT_T_H__
#define __LLVM_LIBC_TYPES_RPC_PORT_T_H__

typedef struct {
__UINT8_TYPE__ reserved[32];
} rpc_port_t;

#endif // __LLVM_LIBC_TYPES_RPC_PORT_T_H__
1 change: 1 addition & 0 deletions libc/include/llvm-libc-types/test_rpc_opcodes_t.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ typedef enum : unsigned short {
RPC_TEST_NOOP = 1 << 15,
RPC_TEST_INCREMENT,
RPC_TEST_INTERFACE,
RPC_TEST_EXTERNAL,
RPC_TEST_STREAM,
} rpc_test_opcode_t;

Expand Down
25 changes: 24 additions & 1 deletion libc/spec/gpu_ext.td
Original file line number Diff line number Diff line change
@@ -1,15 +1,38 @@
def RPCPortT : NamedType<"rpc_port_t">;
def RPCPortPtrT : PtrType<RPCPortT>;

def GPUExtensions : StandardSpec<"GPUExtensions"> {
HeaderSpec RPC = HeaderSpec<
"gpu/rpc.h",
[], // Macros
[], // Types
[RPCPortT, SizeTType], // Types
[], // Enumerations
[
FunctionSpec<
"rpc_host_call",
RetValSpec<VoidType>,
[ArgSpec<VoidPtr>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
>,
FunctionSpec<
"rpc_open_port",
RetValSpec<RPCPortT>,
[ArgSpec<UnsignedIntType>]
>,
FunctionSpec<
"rpc_send_n",
RetValSpec<VoidType>,
[ArgSpec<RPCPortPtrT>, ArgSpec<VoidPtr>, ArgSpec<SizeTType>]
>,
FunctionSpec<
"rpc_recv_n",
RetValSpec<VoidType>,
[ArgSpec<RPCPortPtrT>, ArgSpec<VoidPtr>, ArgSpec<SizeTPtr>]
>,
FunctionSpec<
"rpc_close_port",
RetValSpec<VoidType>,
[ArgSpec<RPCPortPtrT>]
>,
]
>;
let Headers = [
Expand Down
19 changes: 15 additions & 4 deletions libc/src/__support/RPC/rpc.h
Original file line number Diff line number Diff line change
Expand Up @@ -323,6 +323,7 @@ template <bool T> struct Port {
LIBC_INLINE void send_n(const void *src, uint64_t size);
template <typename A>
LIBC_INLINE void recv_n(void **dst, uint64_t *size, A &&alloc);
LIBC_INLINE void recv_n(void *dst, uint64_t *size);

LIBC_INLINE uint16_t get_opcode() const {
return process.header[index].opcode;
Expand Down Expand Up @@ -359,7 +360,9 @@ struct Client {
: process(port_count, buffer) {}

using Port = rpc::Port<false>;
template <uint16_t opcode> LIBC_INLINE Port open();

template <uint16_t opcode> LIBC_INLINE Port open() { return open(opcode); }
LIBC_INLINE Port open(uint16_t opcode);

private:
Process<false> process;
Expand Down Expand Up @@ -484,6 +487,14 @@ LIBC_INLINE void Port<T>::send_n(const void *const *src, uint64_t *size) {
}
}

/// Helper routine to simplify the interface when recieving from the GPU using
/// thread private pointers to the underly value and the destination pointer
/// contains enough data to recieve the values.
template <bool T> LIBC_INLINE void Port<T>::recv_n(void *dst, uint64_t *size) {
void **dst_ptr = &dst;
recv_n(dst_ptr, size, [=](uint64_t) { return dst; });
}

/// Receives an arbitrarily sized data buffer across the shared channel in
/// multiples of the packet length. The \p alloc function is called with the
/// size of the data so that we can initialize the size of the \p dst buffer.
Expand Down Expand Up @@ -522,9 +533,9 @@ LIBC_INLINE void Port<T>::recv_n(void **dst, uint64_t *size, A &&alloc) {
/// is, there are send operations pending that haven't been serviced on this
/// port. Each port instance uses an associated \p opcode to tell the server
/// what to do. The Client interface provides the appropriate lane size to the
/// port using the platform's returned value.
template <uint16_t opcode>
[[clang::convergent]] LIBC_INLINE Client::Port Client::open() {
/// port using the platform's returned value. It is required that \p opcode is
/// uniform between all the lanes for this to work.
[[clang::convergent]] LIBC_INLINE Client::Port Client::open(uint16_t opcode) {
// Repeatedly perform a naive linear scan for a port that can be opened to
// send data.
for (uint32_t index = gpu::get_cluster_id();; ++index) {
Expand Down
55 changes: 55 additions & 0 deletions libc/src/gpu/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,58 @@ add_entrypoint_object(
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)

add_entrypoint_object(
rpc_open_port
SRCS
rpc_open_port.cpp
HDRS
rpc_open_port.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)

add_entrypoint_object(
rpc_close_port
SRCS
rpc_close_port.cpp
HDRS
rpc_close_port.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)

add_entrypoint_object(
rpc_get_buffer
SRCS
rpc_get_buffer.cpp
HDRS
rpc_get_buffer.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)

add_entrypoint_object(
rpc_send_n
SRCS
rpc_send_n.cpp
HDRS
rpc_send_n.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)

add_entrypoint_object(
rpc_recv_n
SRCS
rpc_recv_n.cpp
HDRS
rpc_recv_n.h
DEPENDS
libc.src.__support.RPC.rpc_client
libc.src.__support.GPU.utils
)
24 changes: 24 additions & 0 deletions libc/src/gpu/rpc_close_port.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
//===---------- GPU implementation of the external RPC port interface -----===//
//
// Part of the LLVM Project, 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 "src/gpu/rpc_close_port.h"

#include "src/__support/GPU/utils.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

static_assert(sizeof(rpc_port_t) == sizeof(rpc::Client::Port), "ABI mismatch");

LLVM_LIBC_FUNCTION(void, rpc_close_port, (rpc_port_t * handle)) {
rpc::Client::Port *port = reinterpret_cast<rpc::Client::Port *>(handle);
port->close();
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/gpu/rpc_close_port.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for RPC functions -----------------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_GPU_RPC_CLOSE_PORT_H
#define LLVM_LIBC_SRC_GPU_RPC_CLOSE_PORT_H

#include <gpu/rpc.h>

namespace LIBC_NAMESPACE {

void rpc_close_port(rpc_port_t *handle);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_GPU_RPC_CLOSE_PORT_H
26 changes: 26 additions & 0 deletions libc/src/gpu/rpc_open_port.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===---------- GPU implementation of the external RPC port interface -----===//
//
// Part of the LLVM Project, 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 "src/gpu/rpc_open_port.h"

#include "src/__support/CPP/bit.h"
#include "src/__support/GPU/utils.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

static_assert(sizeof(rpc_port_t) == sizeof(rpc::Client::Port), "ABI mismatch");

LLVM_LIBC_FUNCTION(rpc_port_t, rpc_open_port, (unsigned opcode)) {
uint32_t uniform = gpu::broadcast_value(gpu::get_lane_mask(), opcode);
rpc::Client::Port port = rpc::client.open(static_cast<uint16_t>(uniform));
return cpp::bit_cast<rpc_port_t>(port);
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/gpu/rpc_open_port.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for RPC functions -----------------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_GPU_RPC_OPEN_PORT_H
#define LLVM_LIBC_SRC_GPU_RPC_OPEN_PORT_H

#include <gpu/rpc.h>

namespace LIBC_NAMESPACE {

rpc_port_t rpc_open_port(unsigned opcode);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_GPU_RPC_OPEN_PORT_H
26 changes: 26 additions & 0 deletions libc/src/gpu/rpc_recv_n.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//===---------- GPU implementation of the external RPC port interface -----===//
//
// Part of the LLVM Project, 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 "src/gpu/rpc_recv_n.h"

#include "src/__support/GPU/utils.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

static_assert(sizeof(rpc_port_t) == sizeof(rpc::Client::Port), "ABI mismatch");
static_assert(sizeof(size_t) == sizeof(uint64_t), "Size mismatch");

LLVM_LIBC_FUNCTION(void, rpc_recv_n,
(rpc_port_t * handle, void *dst, size_t *size)) {
rpc::Client::Port *port = reinterpret_cast<rpc::Client::Port *>(handle);
port->recv_n(dst, reinterpret_cast<uint64_t *>(size));
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/gpu/rpc_recv_n.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for RPC functions -----------------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_GPU_RPC_RECV_H
#define LLVM_LIBC_SRC_GPU_RPC_RECV_H

#include <gpu/rpc.h>

namespace LIBC_NAMESPACE {

void rpc_recv_n(rpc_port_t *handle, void *dst, size_t *size);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_GPU_RPC_RECV_H
25 changes: 25 additions & 0 deletions libc/src/gpu/rpc_send_n.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
//===---------- GPU implementation of the external RPC port interface -----===//
//
// Part of the LLVM Project, 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 "src/gpu/rpc_send_n.h"

#include "src/__support/GPU/utils.h"
#include "src/__support/RPC/rpc_client.h"
#include "src/__support/common.h"

namespace LIBC_NAMESPACE {

static_assert(sizeof(rpc_port_t) == sizeof(rpc::Client::Port), "ABI mismatch");

LLVM_LIBC_FUNCTION(void, rpc_send_n,
(rpc_port_t * handle, const void *src, size_t size)) {
rpc::Client::Port *port = reinterpret_cast<rpc::Client::Port *>(handle);
port->send_n(src, size);
}

} // namespace LIBC_NAMESPACE
20 changes: 20 additions & 0 deletions libc/src/gpu/rpc_send_n.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//===-- Implementation header for RPC functions -----------------*- C++ -*-===//
//
// Part of the LLVM Project, 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_LIBC_SRC_GPU_RPC_SEND_H
#define LLVM_LIBC_SRC_GPU_RPC_SEND_H

#include <gpu/rpc.h>

namespace LIBC_NAMESPACE {

void rpc_send_n(rpc_port_t *handle, const void *src, size_t size);

} // namespace LIBC_NAMESPACE

#endif // LLVM_LIBC_SRC_GPU_RPC_SEND_H
Loading

0 comments on commit 6820c7a

Please sign in to comment.