Commit c93a18db authored by Cianciosa, Mark's avatar Cianciosa, Mark
Browse files

Merge branch 'llvm' into 'main'

Fix problems with LLVM JIT on Linux. Adjust unit test tolarance to account for...

See merge request !26
parents 998523a9 c568fa66
Loading
Loading
Loading
Loading
+108 −0
Original line number Diff line number Diff line
@@ -16,6 +16,9 @@ set (CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH};${CMAKE_CURRENT_SOURCE_DIR}/cmake)
#-------------------------------------------------------------------------------
#  Setup build types
#-------------------------------------------------------------------------------
if (NOT CMAKE_BUILD_TYPE)
    set (CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
endif ()
set_property (CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS
              Debug
              Release
@@ -117,6 +120,111 @@ target_link_options (sanitizer
                     $<$<AND:$<CONFIG:Sanitized>,$<PLATFORM_ID:Darwin>>:-fsanitize-trap=all>
)

#-------------------------------------------------------------------------------
#  Setup access method.
#-------------------------------------------------------------------------------
option (USE_SSH "Use ssh to access git repos" OFF)
if (${USE_SSH})
    set (URL_PROTO "git@")
    set (URL_SEP ":")
else ()
    set (URL_PROTO "https://")
    set (URL_SEP "/")
endif ()

#-------------------------------------------------------------------------------
#  Define a macro to register new projects.
#-------------------------------------------------------------------------------
include (FetchContent)
find_package (Git)

function (register_project reg_name dir url default_tag sub_dir)
    set (BUILD_TAG_${dir} ${default_tag} CACHE STRING "Name of the tag to checkout.")

# Anything after the tag is assumed to be a project setting.
    foreach (i RANGE 6 ${ARGC} 3)
        math (EXPR key "${i} - 1" OUTPUT_FORMAT DECIMAL)
        math (EXPR type "${i} + 1" OUTPUT_FORMAT DECIMAL)
        set (${ARGV${key}} ${ARGV${i}} CACHE ${ARGV${type}} "" FORCE)
    endforeach ()

    FetchContent_Declare (
        ${reg_name}
        GIT_REPOSITORY ${url}
        GIT_TAG origin/${BUILD_TAG_${dir}}
        SOURCE_DIR ${CMAKE_CURRENT_SOURCE_DIR}/${dir}
        SOURCE_SUBDIR ${sub_dir}
    )

    FetchContent_MakeAvailable (${reg_name})

    if (${GIT_FOUND})
#  By default cmake clones projects in a headless state. After the repo is
#  cloned checkout the requested tag so repo is in a working state.
        execute_process (
            COMMAND ${GIT_EXECUTABLE} checkout ${BUILD_TAG_${dir}}
            WORKING_DIRECTORY ${${reg_name}_SOURCE_DIR}
        )

#  Add a taraget to pull the latest version before building. Note dependency is
#  registered in the sub project CMakeList.txt. Not sure how this should handle
#  multiple targets in a project yet. Name must match the subproject pull_
#  dependency.
        add_custom_target (
            pull_${reg_name}
            ALL
            COMMAND ${GIT_EXECUTABLE} pull
            WORKING_DIRECTORY ${${reg_name}_SOURCE_DIR}
        )
    endif ()
endfunction ()

register_project (llvm
                  LLVM
                  ${URL_PROTO}github.com${URL_SEP}llvm/llvm-project.git
                  main
                  llvm
                  LLVM_BUILD_LLVM_DYLIB ON BOOL
                  LLVM_TARGETS_TO_BUILD Native STRING
)

#-------------------------------------------------------------------------------
#  Define an llvm dependency target
#-------------------------------------------------------------------------------
FetchContent_GetProperties (
    llvm
    BINARY_DIR llvm_binary_dir
    SOURCE_DIR llvm_source_dir
)

#  Do not build llvm until pull command is finished.
add_dependencies (LLVMHello pull_llvm)
add_dependencies (LLVMHello_exports pull_llvm)
add_dependencies (LLVMDemangle pull_llvm)
add_dependencies (Remarks_exports pull_llvm)
add_dependencies (LLVMSupportBlake3 pull_llvm)
add_dependencies (BugpointPasses_exports pull_llvm)
add_dependencies (LTO_exports pull_llvm)
add_dependencies (llvm-PerfectShuffle pull_llvm)
add_dependencies (SecondLib pull_llvm)
add_dependencies (DynamicLibraryLib pull_llvm)
add_dependencies (PipSqueak pull_llvm)
add_dependencies (obj.LLVMTableGenCommon pull_llvm)
add_dependencies (llvm_vcsrevision_h pull_llvm)
add_dependencies (benchmark pull_llvm)
add_dependencies (benchmark_main pull_llvm)

add_library (llvm_dep INTERFACE)
target_include_directories (llvm_dep
                            INTERFACE
                            $<BUILD_INTERFACE:${llvm_source_dir}/llvm/include>
                            $<BUILD_INTERFACE:${llvm_binary_dir}/include>
)
target_link_libraries (llvm_dep
                       INTERFACE
                       LLVM
)

#-------------------------------------------------------------------------------
#  Setup targets
#-------------------------------------------------------------------------------
+18 −2
Original line number Diff line number Diff line
@@ -1349,7 +1349,10 @@
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				HEADER_SEARCH_PATHS = /usr/local/include;
				LIBRARY_SEARCH_PATHS = /usr/local/lib;
				LIBRARY_SEARCH_PATHS = (
					/usr/local/lib,
					"build/_deps/llvm-build/lib",
				);
				MACOSX_DEPLOYMENT_TARGET = 14.0;
				MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
				MTL_FAST_MATH = YES;
@@ -1360,8 +1363,13 @@
					"-ld_classic",
					"-rpath",
					/usr/local/lib,
					"-lLLVM",
				);
				SDKROOT = macosx;
				USER_HEADER_SEARCH_PATHS = (
					LLVM/llvm/include,
					"build/_deps/llvm-build/include",
				);
			};
			name = Debug;
		};
@@ -1421,7 +1429,10 @@
				GCC_WARN_UNUSED_FUNCTION = YES;
				GCC_WARN_UNUSED_VARIABLE = YES;
				HEADER_SEARCH_PATHS = /usr/local/include;
				LIBRARY_SEARCH_PATHS = /usr/local/lib;
				LIBRARY_SEARCH_PATHS = (
					/usr/local/lib,
					"build/_deps/llvm-build/lib",
				);
				MACOSX_DEPLOYMENT_TARGET = 14.0;
				MTL_ENABLE_DEBUG_INFO = NO;
				MTL_FAST_MATH = YES;
@@ -1432,8 +1443,13 @@
					"-ld_classic",
					"-rpath",
					/usr/local/lib,
					"-lLLVM",
				);
				SDKROOT = macosx;
				USER_HEADER_SEARCH_PATHS = (
					LLVM/llvm/include,
					"build/_deps/llvm-build/include",
				);
			};
			name = Release;
		};
+4 −2
Original line number Diff line number Diff line
@@ -13,13 +13,14 @@ target_compile_definitions (rays
                            INTERFACE
                            $<$<PLATFORM_ID:Darwin>:CXX="${CMAKE_CXX_COMPILER} -isysroot ${CMAKE_OSX_SYSROOT} -I${CMAKE_CURRENT_SOURCE_DIR} -std=gnu++2a">
                            $<$<PLATFORM_ID:Darwin>:CXX_FLAGS="-g -fsanitize=undefined -fsanitize=float-divide-by-zero -fsanitize-trap=all">
                            $<$<PLATFORM_ID:Linux>:CXX="${CMAKE_CXX_COMPILER} -I${CMAKE_CURRENT_SOURCE_DIR} -std=gnu++2a">
                            $<$<PLATFORM_ID:Linux>:CXX_FLAGS="-g -fsanitize=undefined -fsanitize=float-divide-by-zero">
                            $<$<PLATFORM_ID:Linux>:CXX="${CMAKE_CXX_COMPILER} -I${CMAKE_CURRENT_SOURCE_DIR} -std=gnu++2a -fPIC -fno-use-cxa-atexit">
                            $<$<PLATFORM_ID:Linux>:CXX_FLAGS="-g"> #-fsanitize=undefined -fsanitize=float-divide-by-zero">
                            EFIT_FILE="${CMAKE_CURRENT_SOURCE_DIR}/../graph_tests/efit.nc"
                            VMEC_FILE="${CMAKE_CURRENT_SOURCE_DIR}/../graph_tests/vmec.nc"
                            $<$<BOOL:${USE_CUDA}>:HEADER_DIR="$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>">
                            $<$<BOOL:${USE_STATIC}>:STATIC>
)

target_include_directories (rays
                            INTERFACE
                            $<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR}>
@@ -31,6 +32,7 @@ target_link_libraries (rays
                       NetCDF::NetCDF
                       $<$<PLATFORM_ID:Linux>:${CMAKE_DL_LIBS}>
                       $<$<PLATFORM_ID:Linux>:pthread>
                       llvm_dep
)
target_precompile_headers (rays
                           INTERFACE
+6 −5
Original line number Diff line number Diff line
@@ -143,11 +143,12 @@ namespace absorption {
            inputs.push_back(graph::variable_cast(this->t));
            inputs.push_back(graph::variable_cast(this->w));

            dispersion::dispersion_interface<DISPERSION_FUNCTION> D(w, 
            auto D = DISPERSION_FUNCTION().D(w,
                                             kx + kx_amp,
                                             ky + ky_amp,
                                             kz + kz_amp,
                                             x, y, z, t, eq);

            solver::newton(work, {kamp}, inputs, {D.get_d()});

            inputs = {
+43 −32
Original line number Diff line number Diff line
@@ -13,12 +13,14 @@
#include <cstring>
#include <thread>

#include <dlfcn.h>
#include <unistd.h>
#include <sys/wait.h>

#include "node.hpp"

#include "llvm/Support/TargetSelect.h"
#include "llvm/ExecutionEngine/Orc/LLJIT.h"

namespace gpu {
//------------------------------------------------------------------------------
///  @brief Split a string by the space delimiter.
@@ -71,10 +73,10 @@ namespace gpu {
    template<jit::float_scalar T, bool SAFE_MATH=false>
    class cpu_context {
    private:
///  Library name.
        std::string library_name;
///  Code object name.
        std::string object_name;
///  Handle for the dynamic library.
        void *lib_handle;
        std::unique_ptr<llvm::orc::LLJIT> jit;
///  Argument map.
        std::map<graph::leaf_node<T, SAFE_MATH> *, std::vector<T>> kernel_arguments;
///  Host buffer map.
@@ -104,22 +106,22 @@ namespace gpu {
///
///  @params[in] index Concurrent index. Not used.
//------------------------------------------------------------------------------
        cpu_context(const size_t index) {}
        cpu_context(const size_t index) {
            llvm::InitializeNativeTarget();
        }

//------------------------------------------------------------------------------
///  @brief Destruct a cpu context.
//------------------------------------------------------------------------------
        ~cpu_context() {
            dlclose(lib_handle);

            if (!library_name.empty()) {
//  A new instance of the class can be created before the library is deleted.
            if (!object_name.empty()) {
//  A new instance of the class can be created before the object is deleted.
//  Wait for the fork to finish before the destructor exits. This could cause a
//  problem where the new library gets deleted before the context tries to load
//  problem where the new object gets deleted before the context tries to load
//  it.
                auto pid = fork();
                if (pid == 0) {
                    execlp("rm", "rm", library_name.c_str(), NULL);
                    execlp("rm", "rm", object_name.c_str(), NULL);
                    exit(0);
                }
                int error = 0;
@@ -155,22 +157,18 @@ namespace gpu {
            temp_stream.str(std::string());
            temp_stream.clear();

            temp_stream << "./" << filename << ".so";
            library_name = temp_stream.str();
            temp_stream << "temp_" << thread_id << ".o";
            object_name = temp_stream.str();

            temp_stream.str(std::string());
            temp_stream.clear();
#ifdef __APPLE__
            temp_stream << CXX << " -dynamiclib -flat_namespace ";
#else
            temp_stream << CXX << " -fPIC -shared ";
#endif
            temp_stream << CXX << " ";
#ifndef NDEBUG
            temp_stream << CXX_FLAGS << " ";
#else
            temp_stream << "-O3 ";
#endif
            temp_stream << filename << " -o " << library_name;
            temp_stream << "-c " << filename;

            if (jit::verbose) {
                std::cout << "CPU info." << std::endl;
@@ -190,28 +188,39 @@ namespace gpu {
            if (error) {
                std::cerr << "Failed to compile cpu kernel. Check source code in "
                          << filename << std::endl;
                exit(error);
                exit(-1);
            }

#ifdef NDEBUG
            if (fork() == 0) {
            pid = fork();
            if (pid == 0) {
                execlp("rm", "rm", filename.c_str(), NULL);
                exit(0);
            }
#endif

            lib_handle = dlopen(library_name.c_str(), RTLD_LAZY);
            if (!lib_handle) {
                std::cout << "Failed to load library. " << library_name
                          << std::endl;
                std::cout << dlerror() << std::endl;
                exit(1);
            auto object = llvm::MemoryBuffer::getFileAsStream(object_name);

            auto jit_try = llvm::orc::LLJITBuilder().create();
            if (auto jiterror = jit_try.takeError()) {
                std::cerr << "Failed to build JIT : " << toString(std::move(jiterror)) << std::endl;
                exit(-1);
            }
            jit = std::move(jit_try.get());

            jit->addObjectFile(std::move(object.get()));

            if (jit::verbose) {
                std::cout << "  Library name    : " << library_name << std::endl;
                std::cout << "  Library handle  : " << reinterpret_cast<size_t> (lib_handle) << std::endl;
                std::cout << "  Object name    : " << object_name << std::endl;
            }

#ifdef NDEBUG
            waitpid(pid, &error, 0);
            if (error) {
                std::cerr << "Failed to remove " << filename << std::endl;
                exit(-1);
            }
#endif
        }

//------------------------------------------------------------------------------
@@ -227,7 +236,9 @@ namespace gpu {
                                                     graph::input_nodes<T, SAFE_MATH> inputs,
                                                     graph::output_nodes<T, SAFE_MATH> outputs,
                                                     const size_t num_rays) {
            void *kernel = dlsym(lib_handle, kernel_name.c_str());
            auto entry = std::move(jit->lookup(kernel_name)).get();
            auto kernel = entry.toPtr<void(*)(std::map<size_t, T *> &)> ();

            if (!kernel) {
                std::cerr << "Failed to load function. " << kernel_name
                          << std::endl;
@@ -258,7 +269,7 @@ namespace gpu {
            }

            return [kernel, buffers] () mutable {
                ((void (*)(std::map<size_t, T *> &))kernel)(buffers);
                kernel(buffers);
            };
        }

@@ -392,7 +403,7 @@ namespace gpu {
            source_buffer << std::endl;
            source_buffer << "extern \"C\" void " << name << "(" << std::endl;
            
            source_buffer << "    std::map<size_t, ";
            source_buffer << "    map<size_t, ";
            jit::add_type<T> (source_buffer);
            source_buffer << " *> &args) {" << std::endl;

Loading