[libc-commits] [libc] 334bbc0 - [libc] Add support for the 'fread' function on the GPU

Joseph Huber via libc-commits libc-commits at lists.llvm.org
Wed Jul 26 11:51:43 PDT 2023


Author: Joseph Huber
Date: 2023-07-26T13:51:35-05:00
New Revision: 334bbc0d679de1358eb97afdc6de88fa9fa78155

URL: https://github.com/llvm/llvm-project/commit/334bbc0d679de1358eb97afdc6de88fa9fa78155
DIFF: https://github.com/llvm/llvm-project/commit/334bbc0d679de1358eb97afdc6de88fa9fa78155.diff

LOG: [libc] Add support for the 'fread' function on the GPU

This patch adds support for `fread` on the GPU via the RPC mechanism.
Here we simply pass the size of the read to the server and then copy it
back to the client via the RPC channel. This should allow us to do the
basic operations on files now. This will obviously be slow for large
sizes due ot the number of RPC calls involved, this could be optimized
further by having a special RPC call that can initiate a memcpy between
the two pointers.

Reviewed By: jdoerfert

Differential Revision: https://reviews.llvm.org/D155121

Added: 
    

Modified: 
    libc/config/gpu/entrypoints.txt
    libc/include/llvm-libc-types/rpc_opcodes_t.h
    libc/src/__support/File/gpu/file.cpp
    libc/test/src/stdio/CMakeLists.txt
    libc/test/src/stdio/fopen_test.cpp
    libc/utils/gpu/server/rpc_server.cpp

Removed: 
    


################################################################################
diff  --git a/libc/config/gpu/entrypoints.txt b/libc/config/gpu/entrypoints.txt
index e0a15cbe89f2f9..41ed2337e140c8 100644
--- a/libc/config/gpu/entrypoints.txt
+++ b/libc/config/gpu/entrypoints.txt
@@ -83,6 +83,7 @@ set(TARGET_LIBC_ENTRYPOINTS
     # stdio.h entrypoints
     libc.src.stdio.puts
     libc.src.stdio.fputs
+    libc.src.stdio.fread
     libc.src.stdio.fclose
     libc.src.stdio.fopen
     libc.src.stdio.stdin

diff  --git a/libc/include/llvm-libc-types/rpc_opcodes_t.h b/libc/include/llvm-libc-types/rpc_opcodes_t.h
index b04d0f10437d16..f28fb5babf4fcd 100644
--- a/libc/include/llvm-libc-types/rpc_opcodes_t.h
+++ b/libc/include/llvm-libc-types/rpc_opcodes_t.h
@@ -15,11 +15,13 @@ typedef enum : unsigned short {
   RPC_WRITE_TO_STDOUT = 2,
   RPC_WRITE_TO_STDERR = 3,
   RPC_WRITE_TO_STREAM = 4,
-  RPC_OPEN_FILE = 5,
-  RPC_CLOSE_FILE = 6,
-  RPC_MALLOC = 7,
-  RPC_FREE = 8,
-  RPC_HOST_CALL = 9,
+  RPC_READ_FROM_STDIN = 5,
+  RPC_READ_FROM_STREAM = 6,
+  RPC_OPEN_FILE = 7,
+  RPC_CLOSE_FILE = 8,
+  RPC_MALLOC = 9,
+  RPC_FREE = 10,
+  RPC_HOST_CALL = 11,
 } rpc_opcode_t;
 
 #endif // __LLVM_LIBC_TYPES_RPC_OPCODE_H__

diff  --git a/libc/src/__support/File/gpu/file.cpp b/libc/src/__support/File/gpu/file.cpp
index dd4ff4a2fc17a6..80cf072d0aa03c 100644
--- a/libc/src/__support/File/gpu/file.cpp
+++ b/libc/src/__support/File/gpu/file.cpp
@@ -19,6 +19,7 @@ namespace __llvm_libc {
 namespace {
 
 FileIOResult write_func(File *, const void *, size_t);
+FileIOResult read_func(File *, void *, size_t);
 int close_func(File *);
 
 } // namespace
@@ -28,7 +29,7 @@ class GPUFile : public File {
 
 public:
   constexpr GPUFile(uintptr_t file, File::ModeFlags modeflags)
-      : File(&write_func, nullptr, nullptr, &close_func, nullptr, 0, _IONBF,
+      : File(&write_func, &read_func, nullptr, &close_func, nullptr, 0, _IONBF,
              false, modeflags),
         file(file) {}
 
@@ -87,6 +88,46 @@ FileIOResult write_func(File *f, const void *data, size_t size) {
   return ret;
 }
 
+int read_from_stdin(void *buf, size_t size) {
+  int 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;
+}
+
+int read_from_stream(uintptr_t file, void *buf, size_t size) {
+  int ret = 0;
+  uint64_t recv_size;
+  // TODO: For large sizes being written to a pointer in global memory, we
+  // should be able to initiate a H2D memcpy via a separate RPC call at high
+  // bandwidth.
+  rpc::Client::Port port = rpc::client.open<RPC_READ_FROM_STREAM>();
+  port.send([=](rpc::Buffer *buffer) {
+    buffer->data[0] = size;
+    buffer->data[1] = file;
+  });
+  port.recv_n(&buf, &recv_size, [&](uint64_t) { return buf; });
+  port.recv([&](rpc::Buffer *buffer) { ret = buffer->data[0]; });
+  port.close();
+  return ret;
+}
+
+FileIOResult read_func(File *f, void *buf, size_t size) {
+  auto *gpu_file = reinterpret_cast<GPUFile *>(f);
+  int ret = 0;
+  if (gpu_file == stdin)
+    ret = read_from_stdin(buf, size);
+  else
+    ret = read_from_stream(gpu_file->get_file(), buf, size);
+  if (ret < 0)
+    return {0, -ret};
+  return ret;
+}
+
 int close_func(File *file) {
   int ret = 0;
   GPUFile *gpu_file = reinterpret_cast<GPUFile *>(file);

diff  --git a/libc/test/src/stdio/CMakeLists.txt b/libc/test/src/stdio/CMakeLists.txt
index 8ad48545080729..6e9267e7190cf9 100644
--- a/libc/test/src/stdio/CMakeLists.txt
+++ b/libc/test/src/stdio/CMakeLists.txt
@@ -227,6 +227,7 @@ add_libc_test(
   SRCS
     fopen_test.cpp
   DEPENDS
+    libc.src.stdio.fread
     libc.src.stdio.fputs
     libc.src.stdio.fclose
     libc.src.stdio.fopen

diff  --git a/libc/test/src/stdio/fopen_test.cpp b/libc/test/src/stdio/fopen_test.cpp
index 09a283ab919c41..8e8a1c9638f5be 100644
--- a/libc/test/src/stdio/fopen_test.cpp
+++ b/libc/test/src/stdio/fopen_test.cpp
@@ -10,6 +10,7 @@
 #include "src/stdio/fclose.h"
 #include "src/stdio/fopen.h"
 #include "src/stdio/fputs.h"
+#include "src/stdio/fread.h"
 
 #include "test/UnitTest/Test.h"
 
@@ -19,9 +20,20 @@ TEST(LlvmLibcFOpenTest, PrintToFile) {
   FILE *file = __llvm_libc::fopen("./testdata/test_data.txt", "w");
   ASSERT_FALSE(file == nullptr);
 
-  constexpr char another[] = "A simple string written to a file\n";
-  result = __llvm_libc::fputs(another, file);
+  static constexpr char STRING[] = "A simple string written to a file\n";
+  result = __llvm_libc::fputs(STRING, file);
   EXPECT_GE(result, 0);
 
   ASSERT_EQ(0, __llvm_libc::fclose(file));
+
+  FILE *new_file = __llvm_libc::fopen("./testdata/test_data.txt", "r");
+  ASSERT_FALSE(new_file == nullptr);
+
+  static char data[64] = {0};
+  ASSERT_EQ(__llvm_libc::fread(data, 1, sizeof(STRING) - 1, new_file),
+            sizeof(STRING) - 1);
+  data[sizeof(STRING) - 1] = '\0';
+  ASSERT_STREQ(data, STRING);
+
+  ASSERT_EQ(0, __llvm_libc::fclose(new_file));
 }

diff  --git a/libc/utils/gpu/server/rpc_server.cpp b/libc/utils/gpu/server/rpc_server.cpp
index 7ea9bbc8dd9a84..7ae14bac1c5b53 100644
--- a/libc/utils/gpu/server/rpc_server.cpp
+++ b/libc/utils/gpu/server/rpc_server.cpp
@@ -103,6 +103,26 @@ struct Server {
       }
       break;
     }
+    case RPC_READ_FROM_STREAM:
+    case RPC_READ_FROM_STDIN: {
+      uint64_t sizes[rpc::MAX_LANE_SIZE] = {0};
+      void *data[rpc::MAX_LANE_SIZE] = {nullptr};
+      uint64_t rets[rpc::MAX_LANE_SIZE] = {0};
+      port->recv([&](rpc::Buffer *buffer, uint32_t id) {
+        sizes[id] = buffer->data[0];
+        data[id] = new char[sizes[id]];
+        FILE *file = port->get_opcode() == RPC_READ_FROM_STREAM
+                         ? reinterpret_cast<FILE *>(buffer->data[1])
+                         : stdin;
+        rets[id] = fread(data[id], 1, sizes[id], file);
+      });
+      port->send_n(data, sizes);
+      port->send([&](rpc::Buffer *buffer, uint32_t id) {
+        delete[] reinterpret_cast<uint8_t *>(data[id]);
+        std::memcpy(buffer->data, &rets[id], sizeof(uint64_t));
+      });
+      break;
+    }
     case RPC_OPEN_FILE: {
       uint64_t sizes[rpc::MAX_LANE_SIZE] = {0};
       void *paths[rpc::MAX_LANE_SIZE] = {nullptr};


        


More information about the libc-commits mailing list