[libc-commits] [libc] [libc][NFC] Cleanup the GPU file I/O utility header (PR #65680)

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Thu Sep 7 14:36:59 PDT 2023


https://github.com/jhuber6 created https://github.com/llvm/llvm-project/pull/65680:

Summary:
The GPU uses separate implementations to perform file IO. This is all
done through the RPC interface and we kept it minimal such that we could
treat a `stdin`, `stdout`, or `stderr` handle from the CPU correctly on
the GPU. The RPC implementation uses different opcodes for whether or
not we are using one of the standard streams. This is so we do not need
to initialize anything to access the CPU's standard stream, because the
server knows that it should print to `stdout` if it gets the `STDOUT`
variant of the opcode. It also saves us an RPC call, which are expensive
relatively  speaking. This patch simply cleans up this interface to make
them all use a common function. This is done in preparation to implement
some more file IO functions like getc or putc.


>From d8db22711476507dbb151b512ad4c46c18627d5a Mon Sep 17 00:00:00 2001
From: Joseph Huber <jhuber6 at vols.utk.edu>
Date: Thu, 7 Sep 2023 16:33:54 -0500
Subject: [PATCH] [libc][NFC] Cleanup the GPU file I/O utility header

Summary:
The GPU uses separate implementations to perform file IO. This is all
done through the RPC interface and we kept it minimal such that we could
treat a `stdin`, `stdout`, or `stderr` handle from the CPU correctly on
the GPU. The RPC implementation uses different opcodes for whether or
not we are using one of the standard streams. This is so we do not need
to initialize anything to access the CPU's standard stream, because the
server knows that it should print to `stdout` if it gets the `STDOUT`
variant of the opcode. It also saves us an RPC call, which are expensive
relatively  speaking. This patch simply cleans up this interface to make
them all use a common function. This is done in preparation to implement
some more file IO functions like getc or putc.
---
 libc/src/stdio/gpu/file.h | 68 ++++++++++++---------------------------
 1 file changed, 20 insertions(+), 48 deletions(-)

diff --git a/libc/src/stdio/gpu/file.h b/libc/src/stdio/gpu/file.h
index 0ca1df8708a3f7e..03238463f68406b 100644
--- a/libc/src/stdio/gpu/file.h
+++ b/libc/src/stdio/gpu/file.h
@@ -1,4 +1,4 @@
-//===--- GPU helper functions--------------------===//
+//===--- GPU helper functions for file I/O using RPC ----------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -14,35 +14,16 @@
 namespace __llvm_libc {
 namespace file {
 
-LIBC_INLINE uint64_t write_to_stdout(const void *data, size_t size) {
+template <uint16_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<RPC_WRITE_TO_STDOUT>();
-  port.send_n(data, size);
-  port.recv([&](rpc::Buffer *buffer) {
-    ret = reinterpret_cast<uint64_t *>(buffer->data)[0];
-  });
-  port.close();
-  return ret;
-}
+  rpc::Client::Port port = rpc::client.open<opcode>();
 
-LIBC_INLINE uint64_t write_to_stderr(const void *data, size_t size) {
-  uint64_t ret = 0;
-  rpc::Client::Port port = rpc::client.open<RPC_WRITE_TO_STDERR>();
-  port.send_n(data, size);
-  port.recv([&](rpc::Buffer *buffer) {
-    ret = reinterpret_cast<uint64_t *>(buffer->data)[0];
-  });
-  port.close();
-  return ret;
-}
+  if constexpr (opcode == RPC_WRITE_TO_STREAM)
+    port.send([&](rpc::Buffer *buffer) {
+      buffer->data[0] = reinterpret_cast<uintptr_t>(file);
+    });
 
-LIBC_INLINE uint64_t write_to_stream(uintptr_t file, const void *data,
-                                     size_t size) {
-  uint64_t ret = 0;
-  rpc::Client::Port port = rpc::client.open<RPC_WRITE_TO_STREAM>();
-  port.send([&](rpc::Buffer *buffer) {
-    reinterpret_cast<uintptr_t *>(buffer->data)[0] = file;
-  });
   port.send_n(data, size);
   port.recv([&](rpc::Buffer *buffer) {
     ret = reinterpret_cast<uint64_t *>(buffer->data)[0];
@@ -51,33 +32,24 @@ LIBC_INLINE uint64_t write_to_stream(uintptr_t file, const void *data,
   return ret;
 }
 
-LIBC_INLINE uint64_t write(FILE *f, const void *data, size_t size) {
+LIBC_INLINE uint64_t write(::FILE *f, const void *data, size_t size) {
   if (f == stdout)
-    return write_to_stdout(data, size);
+    return write_impl<RPC_WRITE_TO_STDOUT>(f, data, size);
   else if (f == stderr)
-    return write_to_stderr(data, size);
+    return write_impl<RPC_WRITE_TO_STDERR>(f, data, size);
   else
-    return write_to_stream(reinterpret_cast<uintptr_t>(f), data, size);
-}
-
-LIBC_INLINE uint64_t read_from_stdin(void *buf, size_t size) {
-  uint64_t ret = 0;
-  uint64_t recv_size;
-  rpc::Client::Port port = rpc::client.open<RPC_READ_FROM_STDIN>();
-  port.send([=](rpc::Buffer *buffer) { buffer->data[0] = size; });
-  port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; });
-  port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
-  port.close();
-  return ret;
+    return write_impl<RPC_WRITE_TO_STREAM>(f, data, size);
 }
 
-LIBC_INLINE uint64_t read_from_stream(uintptr_t file, void *buf, size_t size) {
+template <uint16_t opcode>
+LIBC_INLINE uint64_t read_from_stream(::FILE *file, void *buf, size_t size) {
   uint64_t ret = 0;
   uint64_t recv_size;
-  rpc::Client::Port port = rpc::client.open<RPC_READ_FROM_STREAM>();
+  rpc::Client::Port port = rpc::client.open<opcode>();
   port.send([=](rpc::Buffer *buffer) {
     buffer->data[0] = size;
-    buffer->data[1] = file;
+    if constexpr (opcode == RPC_READ_FROM_STREAM)
+      buffer->data[1] = reinterpret_cast<uintptr_t>(file);
   });
   port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; });
   port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
@@ -85,11 +57,11 @@ LIBC_INLINE uint64_t read_from_stream(uintptr_t file, void *buf, size_t size) {
   return ret;
 }
 
-LIBC_INLINE uint64_t read(FILE *f, void *data, size_t size) {
+LIBC_INLINE uint64_t read(::FILE *f, void *data, size_t size) {
   if (f == stdin)
-    return read_from_stdin(data, size);
+    return read_from_stream<RPC_READ_FROM_STDIN>(f, data, size);
   else
-    return read_from_stream(reinterpret_cast<uintptr_t>(f), data, size);
+    return read_from_stream<RPC_READ_FROM_STREAM>(f, data, size);
 }
 
 } // namespace file



More information about the libc-commits mailing list