KhronosGroup / KhronosGroup/OpenCL-SDK

Utility library

Open
#2 0 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

Dominant language
C++
Stars
777
Forks
163
Avg merge
6d 17h
Merged PRs (30d)
2

Description

In #1 I touched upon the issue of how to present utilities from the SDK to the users.

The way I imagine the OpenCL SDK hosted by Khronos, is that it provides all the necessary files to compile an OpenCL application (the ICD loader and headers) as well as a utility library which applications could rely on to take care of some tedium in the API.

Consume via CMake

The way I imagined this was to extend the current CMake namespace with the SDK library. Applications consuming both sub-projects may do so via:

find_package(OpenCL 3.0
  REQUIRED
  COMPONENTS
    OpenCL
    SDK
)

add_executable(my_app ${SOURCES})

target_link_libraries(my_app
  PRIVATE
    OpenCL::OpenCL
    OpenCL::SDK
)

Utilities

Here is a short list of things I've grown to use in a few applications of mine.

profiling a la std::chrono
std::cout <<
        "Device (kernel) execution took: " <<
        cl::util::get_duration<CL_PROFILING_COMMAND_START,
                               CL_PROFILING_COMMAND_END,
                               std::chrono::microseconds>(kernel_event).count() <<
        " us." << std::endl;

implementation

namespace cl::util
{
    template <cl_int From, cl_int To, typename Dur = std::chrono::nanoseconds>
    auto get_duration(cl::Event& ev)
    {
        return std::chrono::duration_cast<Dur>(std::chrono::nanoseconds{ ev.getProfilingInfo<To>() - ev.getProfilingInfo<From>() });
    }
}
Iterator-based entry point

This I would like to propose as well for opencl.hpp

std::vector<cl::Platform> platforms(cl::util::Platform::begin(),
                                    cl::util::Platform::end());

implementation

namespace cl::util
{
    namespace Platform
    {
        class PlatformIterator;
        PlatformIterator begin();
        PlatformIterator end();

        cl_uint count()
        {
            cl_int _err = CL_SUCCESS;
            cl_uint _numPlatforms = 0;
            
            _err = clGetPlatformIDs(0, nullptr, &_numPlatforms);
            if (_err != CL_SUCCESS) throw cl::Error{ _err, "clGetPlatformIDs(0, nullptr, &cl_uint)" };

            return _numPlatforms;
        }

        class PlatformIterator
        {
            friend PlatformIterator begin();
            friend PlatformIterator end();

        public:
            typedef std::input_iterator_tag iterator_category;
            typedef cl::Platform value_type;
            typedef std::ptrdiff_t difference_type;
            typedef cl::Platform* pointer;
            typedef cl::Platform reference;

            PlatformIterator& operator++() { ++_curr; return *this; }
            PlatformIterator operator++(int) { auto res = *this; ++_curr; return res; }
            reference operator*() const { return _plats.at(_curr); }
            pointer operator->() const;
            bool operator==(const PlatformIterator& b) const { return _curr == b._curr; }
            bool operator!=(const PlatformIterator& b) const { return _curr != b._curr; }

        private:
            cl_uint _curr;
            std::vector<cl::Platform> _plats;

            PlatformIterator() : PlatformIterator{ 0 } {}
            PlatformIterator(cl_uint curr)
                : _curr{ curr }
            {
                if (_curr != count()) cl::Platform::get(&_plats);
            }
        };

        PlatformIterator begin() { return PlatformIterator{ 0 }; }
        PlatformIterator end() { return PlatformIterator{ count() }; }
    }
}
Obtain executable path
auto kernel_path = cl::util::get_exe_path().parent_path().append("saxpy.cl");
        std::ifstream source_file{ kernel_path };
        if (!source_file.is_open())
            throw std::runtime_error{ std::string{ "Cannot open kernel source: " } + kernel_path.generic_string() };

implementation

// Header //
#if __has_include(<filesystem>)
#include <filesystem>
#elif __has_include(<experimental/filesystem>)
#include <experimental/filesystem>

namespace std {
    namespace filesystem = experimental::filesystem;
}
#else
#error "No STL filesystem support could be detected"
#endif

namespace cl::util
{
    std::filesystem::path get_exe_path();
}

// Source //
#ifdef _WIN32
#include <Windows.h>    //GetModuleFileNameW
#else
#include <limits.h>
#include <unistd.h>     //readlink
#endif

std::filesystem::path cl::util::get_exe_path()
{
#ifdef _WIN32
    wchar_t path[MAX_PATH] = { 0 };
    GetModuleFileNameW(NULL, path, MAX_PATH);
    return path;
#else
    char result[PATH_MAX];
    ssize_t count = readlink("/proc/self/exe", result, PATH_MAX);
    return std::string(result, (count > 0) ? count : 0);
#endif
}

Contributor guide

No contributing guide indexed for this repository

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Review opencl.hpp and the current CMake package configuration first, then compare the proposed profiling, iterator, and executable-path utilities with the SDK's existing scope. Done means the utility-library scope, CMake consumption path, and implementation approach have been agreed for the selected utilities.

Written by the indexing model from the issue text.

Assessment

Tech stack
cmake, cpp
Domain
build-system, tooling
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.