Beispiel #1
0
/// Compile and load a program from source string.
inline vex::backend::program build_sources(const command_queue &q,
        const std::string &source, const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#endif

    std::string compile_options = options + " " + get_compile_options(q);

    sha1_hasher sha1;
    sha1.process(source)
        .process(compile_options)
        .process(VEXCL_JIT_COMPILER)
        .process(VEXCL_JIT_COMPILER_OPTIONS);

    std::string hash = static_cast<std::string>(sha1);

    // Write source to a .cpp file
    std::string basename = program_binaries_path(hash, true) + "kernel";
    std::string sofile   = basename + ".so";

    if ( !boost::filesystem::exists(sofile) ) {
        std::string cppfile = basename + ".cpp";

        {
            std::ofstream f(cppfile);
            f << source;
        }

        // Compile the source.
        std::ostringstream cmdline;
        cmdline << VEXCL_JIT_COMPILER << " -o " << sofile << " " << cppfile << " "
                << VEXCL_JIT_COMPILER_OPTIONS << " " << compile_options;

        if (0 != system(cmdline.str().c_str()) ) {
#ifndef VEXCL_SHOW_KERNELS
            std::cerr << source << std::endl;
#endif

            vex::detail::print_backtrace();
            throw std::runtime_error("Kernel compilation failed");
        }
    }

    // Load the compiled shared library.
    return boost::dll::shared_library(sofile);
}
Beispiel #2
0
/**
 * If VEXCL_CACHE_KERNELS macro is defined, then program binaries are cached
 * in filesystem and reused in the following runs.
 */
inline boost::compute::program build_sources(
    const boost::compute::command_queue &queue,
    const std::string &source,
    const std::string &options = ""
)
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#endif

    return boost::compute::program::build_with_source(
               source, queue.get_context(),
               options + " " + get_compile_options(queue)
           );
}
Beispiel #3
0
/**
 * If VEXCL_CACHE_KERNELS macro is defined, then program binaries are cached
 * in filesystem and reused in the following runs.
 */
inline cl::Program build_sources(
        const cl::CommandQueue &queue, const std::string &source,
        const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#endif

    auto context = queue.getInfo<CL_QUEUE_CONTEXT>();
    auto device  = context.getInfo<CL_CONTEXT_DEVICES>();

    std::string compile_options = options + " " + get_compile_options(queue);

#ifdef VEXCL_CACHE_KERNELS
    // Get unique (hopefully) hash string for the kernel.
    std::ostringstream compiler_tag;
    compiler_tag
#if defined(_MSC_VER)
        << "MSC " << _MSC_VER
#elif defined(__clang__)
        << "Clang " << __clang_major__ << "." << __clang_minor__
#elif defined(__GNUC__)
        << "g++ " << __GNUC__ << "." << __GNUC_MINOR__
#else
        << "unknown"
#endif
        ;

    sha1_hasher sha1;
    sha1.process(source)
        .process(cl::Platform(device[0].getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>())
        .process(device[0].getInfo<CL_DEVICE_NAME>())
        .process(compile_options)
        .process(compiler_tag.str())
        ;

    std::string hash = static_cast<std::string>(sha1);

    // Try to get cached program binaries:
    try {
        if (boost::optional<cl::Program> program = load_program_binaries(hash, context, device, compile_options))
            return *program;
    } catch (...) {
        // Shit happens.
        std::cerr << "Failed to load precompiled binaries" << std::endl;
    }
#endif

    // If cache is not available, just compile the sources.
    cl::Program program(context, source);

    try {
        program.build(device, (options + " " + get_compile_options(queue)).c_str());
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;

        vex::detail::print_backtrace();
        throw;
    }

#ifdef VEXCL_CACHE_KERNELS
    // Save program binaries for future reuse:
    save_program_binaries(hash, program);
#endif

    return program;
}
Beispiel #4
0
/**
 * If VEXCL_CACHE_KERNELS macro is defined, then program binaries are cached
 * in filesystem and reused in the following runs.
 */
inline cl::Program build_sources(
        const cl::CommandQueue &queue, const std::string &source,
        const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
#  ifdef _MSC_VER
#    pragma warning(push)
#    pragma warning(disable: 4996)
#  endif
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#  ifdef _MSC_VER
#    pragma warning(pop)
#  endif
#endif

    auto context = queue.getInfo<CL_QUEUE_CONTEXT>();
    auto device  = context.getInfo<CL_CONTEXT_DEVICES>();

    std::string compile_options = options + " " + get_compile_options(queue);

#ifdef VEXCL_CACHE_KERNELS
    // Get unique (hopefully) hash string for the kernel.
    std::ostringstream fullsrc;

    fullsrc
        << "// Platform: " << cl::Platform(device[0].getInfo<CL_DEVICE_PLATFORM>()).getInfo<CL_PLATFORM_NAME>()
        << "\n// Device:   " << device[0].getInfo<CL_DEVICE_NAME>()
        << "\n// Compiler: "
#if defined(_MSC_VER)
        << "MSC " << _MSC_VER
#elif defined(__clang__)
        << "Clang " << __clang_major__ << "." << __clang_minor__
#elif defined(__GNUC__)
        << "g++ " << __GNUC__ << "." << __GNUC_MINOR__
#else
        << "unknown"
#endif
        << "\n// options:  " << compile_options
        << "\n" << source;

    std::string hash = sha1( fullsrc.str() );

    // Try to get cached program binaries:
    try {
        if (boost::optional<cl::Program> program = load_program_binaries(hash, context, device))
            return *program;
    } catch (...) {
        // Shit happens.
    }
#endif

    // If cache is not available, just compile the sources.
    cl::Program program(context, cl::Program::Sources(
                1, std::make_pair(source.c_str(), source.size())
                ));

    try {
        program.build(device, (options + " " + get_compile_options(queue)).c_str());
    } catch(const cl::Error&) {
        std::cerr << source
                  << std::endl
                  << program.getBuildInfo<CL_PROGRAM_BUILD_LOG>(device[0])
                  << std::endl;
        throw;
    }

#ifdef VEXCL_CACHE_KERNELS
    // Save program binaries for future reuse:
    save_program_binaries(hash, program, fullsrc.str());
#endif

    return program;
}
Beispiel #5
0
/// Create and build a program from source string.
inline vex::backend::program build_sources(
        const command_queue &queue, const std::string &source,
        const std::string &options = ""
        )
{
#ifdef VEXCL_SHOW_KERNELS
    std::cout << source << std::endl;
#else
    if (getenv("VEXCL_SHOW_KERNELS"))
        std::cout << source << std::endl;
#endif

    std::string compile_options = options + " " + get_compile_options(queue);

    queue.context().set_current();

    auto cc = queue.device().compute_capability();
    std::ostringstream ccstr;
    ccstr << std::get<0>(cc) << std::get<1>(cc);

    sha1_hasher sha1;
    sha1.process(source)
        .process(queue.device().name())
        .process(compile_options)
        .process(ccstr.str())
        ;

    std::string hash = static_cast<std::string>(sha1);

    // Write source to a .cu file
    std::string basename = program_binaries_path(hash, true) + "kernel";
    std::string ptxfile  = basename + ".ptx";

    if ( !boost::filesystem::exists(ptxfile) ) {
        std::string cufile = basename + ".cu";

        {
            std::ofstream f(cufile);
            f << source;
        }

        // Compile the source to ptx.
        std::ostringstream cmdline;
        cmdline
            << "nvcc -ptx -O3"
            << " -arch=sm_" << std::get<0>(cc) << std::get<1>(cc)
            << " " << compile_options
            << " -o " << ptxfile << " " << cufile;
        if (0 != system(cmdline.str().c_str()) ) {
#ifndef VEXCL_SHOW_KERNELS
            std::cerr << source << std::endl;
#endif

            vex::detail::print_backtrace();
            throw std::runtime_error("nvcc invocation failed");
        }
    }

    // Load the compiled ptx.
    CUmodule prg;
    cuda_check( cuModuleLoad(&prg, ptxfile.c_str()) );

    return program(queue.context(), prg);
}