Skip to content

Commit

Permalink
compiler kernel cache
Browse files Browse the repository at this point in the history
  • Loading branch information
Snektron committed Mar 23, 2022
1 parent ff3a61f commit ead2de6
Show file tree
Hide file tree
Showing 3 changed files with 114 additions and 4 deletions.
7 changes: 5 additions & 2 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ project(
['c', 'cpp'],
version: '0.0.0',
default_options: [
'cpp_std=c++2a',
'cpp_std=c++20',
'buildtype=debugoptimized',
]
)
Expand All @@ -14,6 +14,8 @@ add_project_arguments(
language: ['c', 'cpp'],
)

fs = import('fs')

futhark = find_program('futhark')
futhark_wrapper = find_program('src/tools/compile_futhark.py')

Expand Down Expand Up @@ -143,6 +145,7 @@ futhark_compile_command = [
'--output', '@OUTDIR@/futhark_generated',
'--dir', '@PRIVATE_DIR@',
'--main', 'src/compiler/main.fut',
'--hash', '@OUTDIR@/futhark_config.h',
]

inputs = []
Expand All @@ -158,7 +161,7 @@ inputs += grammar_fut
futhark_generated = custom_target(
'futhark',
input: inputs,
output: ['futhark_generated.c', 'futhark_generated.h'],
output: ['futhark_generated.c', 'futhark_generated.h', 'futhark_config.hash'],
command: futhark_compile_command,
)

Expand Down
91 changes: 90 additions & 1 deletion src/compiler/main.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "futhark_generated.h"
#include "futhark_config.h"
#include "pareas_grammar.hpp"

#include "pareas/compiler/futhark_interop.hpp"
Expand All @@ -17,6 +18,8 @@
#include <memory>
#include <chrono>
#include <charconv>
#include <filesystem>
#include <sstream>
#include <cstdio>
#include <cstdlib>
#include <cstdint>
Expand All @@ -42,6 +45,7 @@ struct Options {
// Options abailable for the OpenCL and CUDA backends
const char* device_name;
bool futhark_profile;
bool disable_kernel_cache;
};

void print_usage(char* progname) {
Expand All @@ -65,7 +69,6 @@ void print_usage(char* progname) {
"--check Only run check the program for validity; do not\n"
" attempt to generate code.\n"
"--verbose-tree Dump some information about the tree to stderr.\n"
" (default: 0, =disabled)\n"
"--verbose-mod Dump some information about the final module to\n"
" stderr.\n"
"--futhark-verbose Enable Futhark logging.\n"
Expand All @@ -85,10 +88,17 @@ void print_usage(char* progname) {
" This value may also be set via the PAREAS_DEVICE\n"
" environment variable.\n"
"--futhark-profile Enable Futhark profiling and print report at exit.\n"
"--disable-kernel-cache Do not cache compiled kernels.\n"
#endif
"\n"
"When <input path> and/or <output path> are '-', standard input and standard\n"
"output are used respectively.\n"
"\n"
#if defined(FUTHARK_BACKEND_opencl) || defined(FUTHARK_BACKEND_cuda)
"To reduce compiler startup time, GPU-kernels are cached by default. These are\n"
"stored in $XDG_CACHE_HOME/pareas/ or ~/cache/pareas/.\n"
"\n"
#endif
"Backend: {}\n",
progname, backend
);
Expand All @@ -101,6 +111,7 @@ bool parse_options(Options* opts, int argc, char* argv[]) {
.help = false,
.dump_dot = false,
.profile = 0,
.check = false,
.verbose_tree = false,
.verbose_mod = false,
.futhark_verbose = false,
Expand All @@ -109,6 +120,7 @@ bool parse_options(Options* opts, int argc, char* argv[]) {
.threads = 0,
.device_name = nullptr,
.futhark_profile = false,
.disable_kernel_cache = false,
};

const char* threads_arg = nullptr;
Expand Down Expand Up @@ -139,6 +151,9 @@ bool parse_options(Options* opts, int argc, char* argv[]) {
} else if (arg == "--futhark-profile") {
opts->futhark_profile = true;
continue;
} else if (arg == "--disable-kernel-cache") {
opts->disable_kernel_cache = true;
continue;
}
#endif

Expand Down Expand Up @@ -229,6 +244,75 @@ struct Free {
template <typename T>
using MallocPtr = std::unique_ptr<T, Free<T>>;

bool load_cached_kernel(futhark_context_config* cfg, const char* device_name, std::filesystem::path& cache_path) {
auto cache_home = std::filesystem::path{};

const char* xdg_cache_home = std::getenv("XDG_CACHE_HOME");
if (xdg_cache_home) {
cache_home = xdg_cache_home;
} else {
const char* home = std::getenv("HOME");
if (!home) {
fmt::print(std::cerr, "Error: $HOME not set\n");
return false;
}

cache_home = home;
cache_home /= ".cache";
}

cache_home /= "pareas";

std::error_code err;
std::filesystem::create_directories(cache_home, err);
if (err) {
fmt::print(std::cerr, "Error: Failed to create cache directory: {}\n", err.message());
return false;
}

auto cache_file_name = std::stringstream();
cache_file_name << FUTHARK_SOURCE_HASH;

if (device_name) {
cache_file_name << ':';
auto to_hex = [](int c) {
return c < 10 ? c + '0' : c + 'a';
};
for (size_t i = 0; device_name[i]; ++i) {
cache_file_name.put(to_hex(device_name[i] & 0xF));
cache_file_name.put(to_hex(device_name[i] >> 4));
}
}

#if defined(FUTHARK_BACKEND_opencl)
cache_file_name << ".bin";
#elif defined(FUTHARK_BACKEND_cuda)
cache_file_name << ".ptx";
#endif

cache_path = cache_home / cache_file_name.str();
auto status = std::filesystem::status(cache_path);

if (!std::filesystem::exists(status)) {
#if defined(FUTHARK_BACKEND_opencl)
futhark_context_config_dump_binary_to(cfg, cache_path.c_str());
#elif defined(FUTHARK_BACKEND_cuda)
futhark_context_config_dump_ptx_to(cfg, cache_path.c_str());
#endif
} else if (!std::filesystem::is_regular_file(status)) {
fmt::print(std::cerr, "Error: Cache hit is a directory\n");
return false;
} else {
#if defined(FUTHARK_BACKEND_opencl)
futhark_context_config_load_binary_from(cfg, cache_path.c_str());
#elif defined(FUTHARK_BACKEND_cuda)
futhark_context_config_load_ptx_from(cfg, cache_path.c_str());
#endif
}

return true;
}

int main(int argc, char* argv[]) {
Options opts;
if (!parse_options(&opts, argc, argv)) {
Expand Down Expand Up @@ -264,6 +348,11 @@ int main(int argc, char* argv[]) {
}

futhark_context_config_set_profiling(config.get(), opts.futhark_profile);

auto kernel_cache_path = std::filesystem::path{};
if (!opts.disable_kernel_cache && !load_cached_kernel(config.get(), device_name, kernel_cache_path)) {
return EXIT_FAILURE;
}
#endif

auto ctx = futhark::Context(futhark_context_new(config.get()));
Expand Down
20 changes: 19 additions & 1 deletion src/tools/compile_futhark.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
p.add_argument('--futhark', required=True, help='Futhark compiler binary path')
p.add_argument('--futhark-backend', required=True, help='Futhark compilation backend (cuda, opencl, multicore, c)')
p.add_argument('--output', required=True, help='Output basename')
p.add_argument('--hash', help='Compute source hash and create a configuration file to store it in')
p.add_argument('--main', required=True, help='Main futhark file (relative to --src)')
p.add_argument('-f', dest='sources', nargs=2, metavar=('src', 'relative src'), action='append', help='Source files and their path relative to --dir')

Expand All @@ -20,12 +21,29 @@
os.makedirs(os.path.dirname(dst), exist_ok=True)
shutil.copy(src, dst)

path = os.path.join(args.dir, args.main)

try:
if args.hash is not None:
result = subprocess.run(
[
args.futhark,
'hash',
path,
],
check=True,
capture_output=True,
)
with open(args.hash, 'wb') as f:
f.write(b'#define FUTHARK_SOURCE_HASH "')
f.write(bytes(result.stdout.strip()))
f.write(b'"\n')

subprocess.run(
[
args.futhark,
args.futhark_backend,
os.path.join(args.dir, args.main),
path,
'--library',
'-o', args.output,
],
Expand Down

0 comments on commit ead2de6

Please sign in to comment.