Skip to content

Commit

Permalink
[RNG] Device API headers and tests migration (uxlfoundation#382)
Browse files Browse the repository at this point in the history
  • Loading branch information
egrabovskaya authored Nov 23, 2023
1 parent 3e729c5 commit 7867ca8
Show file tree
Hide file tree
Showing 37 changed files with 9,506 additions and 0 deletions.
8 changes: 8 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ oneMKL is part of [oneAPI](https://oneapi.io).

### Supported Usage Models:

#### Host API

There are two oneMKL selector layer implementations:

- **Run-time dispatching**: The application is linked with the oneMKL library and the required backend is loaded at run-time based on device vendor (all libraries should be dynamic).
Expand Down Expand Up @@ -140,6 +142,12 @@ $> clang++ -fsycl app.o –L$ONEMKL/lib –lonemkl_blas_mklcpu –lonemkl_blas_c

*Refer to [Selecting a Compiler](https://oneapi-src.github.io/oneMKL/selecting_a_compiler.html) for the choice between `icpx/icx` and `clang++` compilers.*

#### Device API

Header-based and backend-independent Device API can be called within ```sycl kernel``` or work from Host code ([device-rng-usage-model-example](https://spec.oneapi.io/versions/latest/elements/oneMKL/source/domains/rng/device_api/device-rng-usage-model.html#id2)). Currently, the following domains support the Device API:

- **RNG**. To use RNG Device API functionality it's required to include ```oneapi/mkl/rng/device.hpp``` header file.

### Supported Configurations:

Supported domains: BLAS, LAPACK, RNG, DFT
Expand Down
1 change: 1 addition & 0 deletions examples/rng/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@
# Note: compile-time example uses both MKLCPU and CURAND backends, therefore
# cmake in the sub-directory will only build it if CURAND backend is enabled
add_subdirectory(compile_time_dispatching)
add_subdirectory(device)

# runtime compilation is only possible with dynamic libraries
if (BUILD_SHARED_LIBS)
Expand Down
70 changes: 70 additions & 0 deletions examples/rng/device/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
#===============================================================================
# Copyright 2023 Intel Corporation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions
# and limitations under the License.
#
#
# SPDX-License-Identifier: Apache-2.0
#===============================================================================

# NOTE: user needs to set env var SYCL_DEVICE_FILTER to use runtime example (no need to specify backend when building with CMake)

# Build object from all example sources
set(RNG_DEVICE_SOURCES "uniform")

# Set up for the right backend for run-time dispatching examples
# If users build more than one backend (i.e. mklcpu and mklgpu, or mklcpu and CUDA), they may need to
# overwrite SYCL_DEVICE_FILTER in their environment to run on the desired backend
set(DEVICE_FILTERS "")
if(ENABLE_MKLCPU_BACKEND)
list(APPEND DEVICE_FILTERS "cpu")
endif()
# RNG only supports mklcpu backend on Windows
if(ENABLE_MKLGPU_BACKEND)
list(APPEND DEVICE_FILTERS "gpu")
endif()
if(ENABLE_CURAND_BACKEND)
list(APPEND DEVICE_FILTERS "cuda:gpu")
endif()
if(ENABLE_ROCRAND_BACKEND)
list(APPEND DEVICE_FILTERS "hip:gpu")
endif()

message(STATUS "SYCL_DEVICE_FILTER will be set to the following value(s): [${DEVICE_FILTERS}] for run-time dispatching examples")

foreach(rng_device_source ${RNG_DEVICE_SOURCES})
add_executable(example_${domain}_${rng_device_source} ${rng_device_source}.cpp)
target_include_directories(example_${domain}_${rng_device_source}
PUBLIC ${PROJECT_SOURCE_DIR}/examples/rng/device/include
PUBLIC ${PROJECT_SOURCE_DIR}/examples/include
PUBLIC ${PROJECT_SOURCE_DIR}/include
PUBLIC ${CMAKE_BINARY_DIR}/bin
)

if (USE_ADD_SYCL_TO_TARGET_INTEGRATION)
add_sycl_to_target(TARGET example_${domain}_${rng_device_source} SOURCES ${RNG_DEVICE_SOURCES})
endif()

target_link_libraries(example_${domain}_${rng_device_source} PUBLIC
ONEMKL::SYCL::SYCL
)

# Register example as ctest
foreach(device_filter ${DEVICE_FILTERS})
add_test(NAME ${domain}/EXAMPLE/DEVICE/${rng_device_source}/${device_filter} COMMAND example_${domain}_${rng_device_source})
set_property(TEST ${domain}/EXAMPLE/DEVICE/${rng_device_source}/${device_filter} PROPERTY
ENVIRONMENT LD_LIBRARY_PATH=${CMAKE_BINARY_DIR}/lib:$ENV{LD_LIBRARY_PATH}
ENVIRONMENT SYCL_DEVICE_FILTER=${device_filter})
endforeach(device_filter)

endforeach()
40 changes: 40 additions & 0 deletions examples/rng/device/include/rng_example_helper.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/*******************************************************************************
* Copyright 2023 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
*
*
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/

#ifndef _RNG_EXAMPLE_HELPER_HPP__
#define _RNG_EXAMPLE_HELPER_HPP__

template <typename T, typename = void>
struct has_member_code_meta : std::false_type {};

template <typename T>
struct has_member_code_meta<T, std::void_t<decltype(std::declval<T>().get_multi_ptr())>>
: std::true_type {};

template <typename T, typename std::enable_if<has_member_code_meta<T>::value>::type* = nullptr>
auto get_multi_ptr(T acc) {
return acc.get_multi_ptr();
};

template <typename T, typename std::enable_if<!has_member_code_meta<T>::value>::type* = nullptr>
auto get_multi_ptr(T acc) {
return acc.get_pointer();
};

#endif // _RNG_EXAMPLE_HELPER_HPP__
213 changes: 213 additions & 0 deletions examples/rng/device/uniform.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,213 @@
/*******************************************************************************
* Copyright 2023 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
*
*
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/

/*
*
* Content:
* This example demonstrates usage of oneapi::mkl::rng::device::mcg59
* random number generator to produce random
* numbers using unifrom distribution on a SYCL device (CPU, GPU).
*
*******************************************************************************/

// stl includes
#include <iostream>
#include <vector>

// oneMKL/SYCL includes
#if __has_include(<sycl/sycl.hpp>)
#include <sycl/sycl.hpp>
#else
#include <CL/sycl.hpp>
#endif

#include "oneapi/mkl/rng/device.hpp"

#include "rng_example_helper.hpp"

bool isDoubleSupported(sycl::device my_dev) {
return my_dev.get_info<sycl::info::device::double_fp_config>().size() != 0;
}

// example parameters
constexpr int seed = 777;
constexpr std::size_t n = 1024;
constexpr int n_print = 10;

//
// example show usage of rng device functionality, which can be called from both
// host and device sides with scalar and vector generation
//
template <typename Type, std::int32_t VecSize>
int run_example(sycl::queue& queue) {
if (VecSize == 1) {
std::cout << "\tRunning scalar example" << std::endl;
}
else {
std::cout << "\tRunning vector example with " << VecSize << " vector size" << std::endl;
}
// prepare array for random numbers
std::vector<Type> r_dev(n);

// submit a kernel to generate on device
{
sycl::buffer<Type> r_buf(r_dev.data(), r_dev.size());

try {
queue.submit([&](sycl::handler& cgh) {
sycl::accessor r_acc(r_buf, cgh, sycl::write_only);
cgh.parallel_for(sycl::range<1>(n / VecSize), [=](sycl::item<1> item) {
size_t item_id = item.get_id(0);
oneapi::mkl::rng::device::mcg59<VecSize> engine(seed, item_id * VecSize);
oneapi::mkl::rng::device::uniform<Type> distr;

auto res = oneapi::mkl::rng::device::generate(distr, engine);
if constexpr (VecSize == 1) {
r_acc[item_id] = res;
}
else {
res.store(item_id, get_multi_ptr(r_acc));
}
});
});
queue.wait_and_throw();
}
catch (sycl::exception const& e) {
std::cout << "\t\tSYCL exception\n" << e.what() << std::endl;
return 1;
}

std::cout << "\t\tOutput of generator:" << std::endl;

auto r_acc = sycl::host_accessor(r_buf, sycl::read_only);
std::cout << "first " << n_print << " numbers of " << n << ": " << std::endl;
for (int i = 0; i < n_print; i++) {
std::cout << r_acc[i] << " ";
}
std::cout << std::endl;
} // buffer life-time ends

// compare results with host-side generation
oneapi::mkl::rng::device::mcg59<1> engine(seed);
oneapi::mkl::rng::device::uniform<Type> distr;

int err = 0;
Type res_host;
for (int i = 0; i < n; i++) {
res_host = oneapi::mkl::rng::device::generate(distr, engine);
if (res_host != r_dev[i]) {
std::cout << "error in " << i << " element " << res_host << " " << r_dev[i]
<< std::endl;
err++;
}
}
return err;
}

//
// description of example setup, APIs used
//
void print_example_banner() {
std::cout << "" << std::endl;
std::cout << "########################################################################"
<< std::endl;
std::cout << "# Generate uniformly distributed random numbers example: " << std::endl;
std::cout << "# " << std::endl;
std::cout << "# Using APIs:" << std::endl;
std::cout << "# mcg59 uniform" << std::endl;
std::cout << "# " << std::endl;
std::cout << "########################################################################"
<< std::endl;
std::cout << std::endl;
}

int main() {
// Catch asynchronous exceptions
auto exception_handler = [](sycl::exception_list exceptions) {
for (std::exception_ptr const& e : exceptions) {
try {
std::rethrow_exception(e);
}
catch (sycl::exception const& e) {
std::cerr << "Caught asynchronous SYCL exception during generation:" << std::endl;
std::cerr << "\t" << e.what() << std::endl;
}
}
std::exit(2);
};

print_example_banner();

try {
sycl::device my_dev = sycl::device();

if (my_dev.is_gpu()) {
std::cout << "Running RNG uniform usm example on GPU device" << std::endl;
std::cout << "Device name is: " << my_dev.get_info<sycl::info::device::name>()
<< std::endl;
}
else {
std::cout << "Running RNG uniform usm example on CPU device" << std::endl;
std::cout << "Device name is: " << my_dev.get_info<sycl::info::device::name>()
<< std::endl;
}

sycl::queue queue(my_dev, exception_handler);

std::cout << "\n\tRunning with single precision real data type:" << std::endl;
if (run_example<float, 1>(queue) || run_example<float, 4>(queue)) {
std::cout << "FAILED" << std::endl;
return 1;
}
if (isDoubleSupported(my_dev)) {
std::cout << "\n\tRunning with double precision real data type:" << std::endl;
if (run_example<double, 1>(queue) || run_example<double, 4>(queue)) {
std::cout << "FAILED" << std::endl;
return 1;
}
}
else {
std::cout << "Double precision is not supported for this device" << std::endl;
}
std::cout << "\n\tRunning with integer data type:" << std::endl;
if (run_example<std::int32_t, 1>(queue) || run_example<std::int32_t, 4>(queue)) {
std::cout << "FAILED" << std::endl;
return 1;
}
std::cout << "\n\tRunning with unsigned integer data type:" << std::endl;
if (run_example<std::uint32_t, 1>(queue) || run_example<std::uint32_t, 4>(queue)) {
std::cout << "FAILED" << std::endl;
return 1;
}

std::cout << "Random number generator with uniform distribution ran OK" << std::endl;
}
catch (sycl::exception const& e) {
std::cerr << "Caught synchronous SYCL exception:" << std::endl;
std::cerr << "\t" << e.what() << std::endl;
std::cerr << "\tSYCL error code: " << e.code().value() << std::endl;
return 1;
}
catch (std::exception const& e) {
std::cerr << "Caught std::exception during generation:" << std::endl;
std::cerr << "\t" << e.what() << std::endl;
return 1;
}
return 0;
}
28 changes: 28 additions & 0 deletions include/oneapi/mkl/rng/device.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/*******************************************************************************
* Copyright 2023 Intel Corporation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions
* and limitations under the License.
*
*
* SPDX-License-Identifier: Apache-2.0
*******************************************************************************/

#ifndef _MKL_RNG_SYCL_DEVICE_HPP__
#define _MKL_RNG_SYCL_DEVICE_HPP__

#include "oneapi/mkl/rng/device/types.hpp"
#include "oneapi/mkl/rng/device/functions.hpp"
#include "oneapi/mkl/rng/device/distributions.hpp"
#include "oneapi/mkl/rng/device/engines.hpp"

#endif // _MKL_RNG_SYCL_DEVICE_HPP__
Loading

0 comments on commit 7867ca8

Please sign in to comment.