[libc] Increase RPC opcode to 32-bit and use a class byte (#116905)

Summary:
Currently, the RPC interface uses a basic opcode to communicate with the
server. This currently is 16 bits. There's no reason for this to be 16
bits, because on the GPU a 32-bit write is the same as a 16-bit write
performance wise.

Additionally, I am now making all the `libc` based opcodes qualified
with the 'c' type, mimiciing how Linux handles `ioctls` all coming from
the same driver. This will make it easier to extend the interface when
it's exported directly.
This commit is contained in:
Joseph Huber
2024-11-19 21:56:10 -06:00
committed by GitHub
parent 4f1b20f023
commit 27d25d1c12
7 changed files with 50 additions and 47 deletions

View File

@@ -302,6 +302,6 @@ associated with relocatable device code linking.
Extensions
----------
We describe which operation the RPC server should take with a 16-bit opcode. We
consider the first 32768 numbers to be reserved while the others are free to
use.
The opcode is a 32-bit integer that must be unique to the requested operation.
All opcodes used by ``libc`` internally have the character ``c`` in the most
significant byte.

View File

@@ -9,38 +9,41 @@
#ifndef LLVM_LIBC_TYPES_RPC_OPCODES_T_H
#define LLVM_LIBC_TYPES_RPC_OPCODES_T_H
#define LLVM_LIBC_RPC_BASE 'c'
#define LLVM_LIBC_OPCODE(n) (LLVM_LIBC_RPC_BASE << 24 | n)
typedef enum {
RPC_NOOP = 0,
RPC_EXIT,
RPC_WRITE_TO_STDOUT,
RPC_WRITE_TO_STDERR,
RPC_WRITE_TO_STREAM,
RPC_WRITE_TO_STDOUT_NEWLINE,
RPC_READ_FROM_STREAM,
RPC_READ_FGETS,
RPC_OPEN_FILE,
RPC_CLOSE_FILE,
RPC_MALLOC,
RPC_FREE,
RPC_HOST_CALL,
RPC_ABORT,
RPC_FEOF,
RPC_FERROR,
RPC_CLEARERR,
RPC_FSEEK,
RPC_FTELL,
RPC_FFLUSH,
RPC_UNGETC,
RPC_PRINTF_TO_STDOUT,
RPC_PRINTF_TO_STDERR,
RPC_PRINTF_TO_STREAM,
RPC_PRINTF_TO_STDOUT_PACKED,
RPC_PRINTF_TO_STDERR_PACKED,
RPC_PRINTF_TO_STREAM_PACKED,
RPC_REMOVE,
RPC_RENAME,
RPC_SYSTEM,
RPC_LAST = 0xFFFF,
RPC_NOOP = LLVM_LIBC_OPCODE(0),
RPC_EXIT = LLVM_LIBC_OPCODE(1),
RPC_WRITE_TO_STDOUT = LLVM_LIBC_OPCODE(2),
RPC_WRITE_TO_STDERR = LLVM_LIBC_OPCODE(3),
RPC_WRITE_TO_STREAM = LLVM_LIBC_OPCODE(4),
RPC_WRITE_TO_STDOUT_NEWLINE = LLVM_LIBC_OPCODE(5),
RPC_READ_FROM_STREAM = LLVM_LIBC_OPCODE(6),
RPC_READ_FGETS = LLVM_LIBC_OPCODE(7),
RPC_OPEN_FILE = LLVM_LIBC_OPCODE(8),
RPC_CLOSE_FILE = LLVM_LIBC_OPCODE(9),
RPC_MALLOC = LLVM_LIBC_OPCODE(10),
RPC_FREE = LLVM_LIBC_OPCODE(11),
RPC_HOST_CALL = LLVM_LIBC_OPCODE(12),
RPC_ABORT = LLVM_LIBC_OPCODE(13),
RPC_FEOF = LLVM_LIBC_OPCODE(14),
RPC_FERROR = LLVM_LIBC_OPCODE(15),
RPC_CLEARERR = LLVM_LIBC_OPCODE(16),
RPC_FSEEK = LLVM_LIBC_OPCODE(17),
RPC_FTELL = LLVM_LIBC_OPCODE(18),
RPC_FFLUSH = LLVM_LIBC_OPCODE(19),
RPC_UNGETC = LLVM_LIBC_OPCODE(20),
RPC_PRINTF_TO_STDOUT = LLVM_LIBC_OPCODE(21),
RPC_PRINTF_TO_STDERR = LLVM_LIBC_OPCODE(22),
RPC_PRINTF_TO_STREAM = LLVM_LIBC_OPCODE(23),
RPC_PRINTF_TO_STDOUT_PACKED = LLVM_LIBC_OPCODE(24),
RPC_PRINTF_TO_STDERR_PACKED = LLVM_LIBC_OPCODE(25),
RPC_PRINTF_TO_STREAM_PACKED = LLVM_LIBC_OPCODE(26),
RPC_REMOVE = LLVM_LIBC_OPCODE(27),
RPC_RENAME = LLVM_LIBC_OPCODE(28),
RPC_SYSTEM = LLVM_LIBC_OPCODE(29),
RPC_LAST = 0xFFFFFFFF,
} rpc_opcode_t;
#endif // LLVM_LIBC_TYPES_RPC_OPCODES_T_H

View File

@@ -51,7 +51,7 @@ static_assert(sizeof(Buffer) == 64, "Buffer size mismatch");
/// perform and which threads are active in the slots.
struct Header {
uint64_t mask;
uint16_t opcode;
uint32_t opcode;
};
/// The maximum number of parallel ports that the RPC interface can support.
@@ -319,11 +319,11 @@ public:
template <typename A>
LIBC_INLINE void recv_n(void **dst, uint64_t *size, A &&alloc);
LIBC_INLINE uint16_t get_opcode() const {
LIBC_INLINE uint32_t get_opcode() const {
return process.header[index].opcode;
}
LIBC_INLINE uint16_t get_index() const { return index; }
LIBC_INLINE uint32_t get_index() const { return index; }
LIBC_INLINE void close() {
// Wait for all lanes to finish using the port.
@@ -357,7 +357,7 @@ struct Client {
: process(port_count, buffer) {}
using Port = rpc::Port<false>;
template <uint16_t opcode> LIBC_INLINE Port open();
template <uint32_t opcode> LIBC_INLINE Port open();
private:
Process<false> process;
@@ -518,7 +518,7 @@ LIBC_INLINE void Port<T>::recv_n(void **dst, uint64_t *size, A &&alloc) {
/// 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>
template <uint32_t opcode>
[[clang::convergent]] LIBC_INLINE Client::Port Client::open() {
// Repeatedly perform a naive linear scan for a port that can be opened to
// send data.

View File

@@ -49,7 +49,7 @@ LIBC_INLINE ::FILE *to_stream(uintptr_t f) {
return stream;
}
template <uint16_t opcode>
template <uint32_t opcode>
LIBC_INLINE uint64_t write_impl(::FILE *file, const void *data, size_t size) {
uint64_t ret = 0;
rpc::Client::Port port = rpc::client.open<opcode>();

View File

@@ -16,7 +16,7 @@
namespace LIBC_NAMESPACE_DECL {
template <uint16_t opcode>
template <uint32_t opcode>
LIBC_INLINE int vfprintf_impl(::FILE *__restrict file,
const char *__restrict format, size_t format_size,
va_list vlist) {

View File

@@ -79,7 +79,7 @@ rpc_status_t rpc_handle_server(rpc_device_t rpc_device);
/// Register a callback to handle an opcode from the RPC client. The associated
/// data must remain accessible as long as the user intends to handle the server
/// with this callback.
rpc_status_t rpc_register_callback(rpc_device_t rpc_device, uint16_t opcode,
rpc_status_t rpc_register_callback(rpc_device_t rpc_device, uint32_t opcode,
rpc_opcode_callback_ty callback, void *data);
/// Obtain a pointer to a local client buffer that can be copied directly to the

View File

@@ -215,8 +215,8 @@ static void handle_printf(rpc::Server::Port &port, TempStorage &temp_storage) {
template <uint32_t lane_size>
rpc_status_t handle_server_impl(
rpc::Server &server,
const std::unordered_map<uint16_t, rpc_opcode_callback_ty> &callbacks,
const std::unordered_map<uint16_t, void *> &callback_data,
const std::unordered_map<uint32_t, rpc_opcode_callback_ty> &callbacks,
const std::unordered_map<uint32_t, void *> &callback_data,
uint32_t &index) {
auto port = server.try_open(lane_size, index);
if (!port)
@@ -477,8 +477,8 @@ struct Device {
void *buffer;
rpc::Server server;
rpc::Client client;
std::unordered_map<uint16_t, rpc_opcode_callback_ty> callbacks;
std::unordered_map<uint16_t, void *> callback_data;
std::unordered_map<uint32_t, rpc_opcode_callback_ty> callbacks;
std::unordered_map<uint32_t, void *> callback_data;
};
rpc_status_t rpc_server_init(rpc_device_t *rpc_device, uint64_t num_ports,
@@ -528,7 +528,7 @@ rpc_status_t rpc_handle_server(rpc_device_t rpc_device) {
}
}
rpc_status_t rpc_register_callback(rpc_device_t rpc_device, uint16_t opcode,
rpc_status_t rpc_register_callback(rpc_device_t rpc_device, uint32_t opcode,
rpc_opcode_callback_ty callback,
void *data) {
if (!rpc_device.handle)