Joseph Huber cd4e8884ed [libc] Improve copying system vectors to the GPU
Summary:
This implementation was buggy and inefficient. Fine-grained memory can
only be allocated on a page-level granularity. Which means that each
allocated string used about 4096 bytes. This is wasteful in general, and
also allowed for buggy behaviour. The previous copying of the
environment vector only worked because the large buffer size meant that
we would typically have a null byte after the allocated memory. However
this would break if the vector was larger than a page. This patch
allocates everything into a single buffer. It makes it easier to free,
use, and it more correct.
2023-04-03 10:10:43 -05:00

59 lines
2.0 KiB
C++

//===-- Generic device loader 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
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_LIBC_UTILS_GPU_LOADER_LOADER_H
#define LLVM_LIBC_UTILS_GPU_LOADER_LOADER_H
#include <cstdint>
#include <cstring>
#include <stddef.h>
/// Generic interface to load the \p image and launch execution of the _start
/// kernel on the target device. Copies \p argc and \p argv to the device.
/// Returns the final value of the `main` function on the device.
int load(int argc, char **argv, char **evnp, void *image, size_t size);
/// Copy the system's argument vector to GPU memory allocated using \p alloc.
template <typename Allocator>
void *copy_argument_vector(int argc, char **argv, Allocator alloc) {
size_t argv_size = sizeof(char *) * (argc + 1);
size_t str_size = 0;
for (int i = 0; i < argc; ++i)
str_size += strlen(argv[i]) + 1;
// We allocate enough space for a null terminated array and all the strings.
void *dev_argv = alloc(argv_size + str_size);
if (!dev_argv)
return nullptr;
// Store the strings linerally in the same memory buffer.
void *dev_str = reinterpret_cast<uint8_t *>(dev_argv) + argv_size;
for (int i = 0; i < argc; ++i) {
size_t size = strlen(argv[i]) + 1;
std::memcpy(dev_str, argv[i], size);
static_cast<void **>(dev_argv)[i] = dev_str;
dev_str = reinterpret_cast<uint8_t *>(dev_str) + size;
}
// Ensure the vector is null terminated.
reinterpret_cast<void **>(dev_argv)[argv_size] = nullptr;
return dev_argv;
};
/// Copy the system's environment to GPU memory allocated using \p alloc.
template <typename Allocator>
void *copy_environment(char **envp, Allocator alloc) {
int envc = 0;
for (char **env = envp; *env != 0; ++env)
++envc;
return copy_argument_vector(envc, envp, alloc);
};
#endif