Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
1482c0712a | ||
|
|
69d0954ba9 | ||
|
|
46d58dc838 | ||
|
|
05b1dd0789 | ||
|
|
88b4c2782a |
@@ -53,8 +53,6 @@ __pycache__/
|
||||
# -------- IDE --------
|
||||
.vscode/*
|
||||
.vs/*
|
||||
out/*
|
||||
CMakeSettings.json
|
||||
|
||||
# -------- CTags --------
|
||||
.tags
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -14,6 +14,8 @@
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
|
||||
# Enable CMake policies
|
||||
|
||||
if (POLICY CMP0091)
|
||||
@@ -28,39 +30,23 @@ if (TBB_WINDOWS_DRIVER AND (NOT ("${CMAKE_MSVC_RUNTIME_LIBRARY}" STREQUAL MultiT
|
||||
message(FATAL_ERROR "Enabled TBB_WINDOWS_DRIVER requires CMAKE_MSVC_RUNTIME_LIBRARY to be set to MultiThreaded or MultiThreadedDebug.")
|
||||
endif()
|
||||
|
||||
# Enable support of minimum supported macOS version flag
|
||||
if (APPLE)
|
||||
if (NOT CMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG)
|
||||
set(CMAKE_CXX_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=" CACHE STRING "Minimum macOS version flag")
|
||||
endif()
|
||||
if (NOT CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG)
|
||||
set(CMAKE_C_OSX_DEPLOYMENT_TARGET_FLAG "-mmacosx-version-min=" CACHE STRING "Minimum macOS version flag")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
# Until CMake 3.4.0 FindThreads.cmake requires C language enabled.
|
||||
# Enable C language before CXX to avoid possible override of CMAKE_SIZEOF_VOID_P.
|
||||
if (CMAKE_VERSION VERSION_LESS 3.4)
|
||||
enable_language(C)
|
||||
endif()
|
||||
|
||||
file(READ include/oneapi/tbb/version.h _tbb_version_info)
|
||||
file(READ include/tbb/version.h _tbb_version_info)
|
||||
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define TBB_VERSION_PATCH ([0-9]+).*" "\\1" _tbb_ver_patch "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" TBB_INTERFACE_VERSION "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define __TBB_BINARY_VERSION ([0-9]+).*" "\\1" TBB_BINARY_VERSION "${_tbb_version_info}")
|
||||
set(TBB_BINARY_MINOR_VERSION ${_tbb_ver_minor})
|
||||
set(TBBMALLOC_BINARY_VERSION 2)
|
||||
set(TBBBIND_BINARY_VERSION 3)
|
||||
|
||||
project(TBB VERSION ${_tbb_ver_major}.${_tbb_ver_minor}.${_tbb_ver_patch} LANGUAGES CXX)
|
||||
project(TBB VERSION ${_tbb_ver_major}.${_tbb_ver_minor} LANGUAGES CXX)
|
||||
unset(_tbb_ver_major)
|
||||
unset(_tbb_ver_minor)
|
||||
|
||||
include(CheckCXXCompilerFlag)
|
||||
include(GNUInstallDirs)
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------
|
||||
# Handle C++ standard version.
|
||||
if (NOT MSVC) # no need to cover MSVC as it uses C++14 by default.
|
||||
@@ -95,20 +81,13 @@ endif()
|
||||
option(TBB_TEST "Enable testing" ON)
|
||||
option(TBB_EXAMPLES "Enable examples" OFF)
|
||||
option(TBB_STRICT "Treat compiler warnings as errors" ON)
|
||||
option(TBB_NUMA_SUPPORT "Enable NUMA support that depends on Portable Hardware Locality (hwloc) library" OFF)
|
||||
option(TBB_WINDOWS_DRIVER "Build as Universal Windows Driver (UWD)" OFF)
|
||||
option(TBB_NO_APPCONTAINER "Apply /APPCONTAINER:NO (for testing binaries for Windows Store)" OFF)
|
||||
option(TBB4PY_BUILD "Enable tbb4py build" OFF)
|
||||
option(TBB_CPF "Enable preview features of the library" OFF)
|
||||
option(TBB_FIND_PACKAGE "Enable search for external oneTBB using find_package instead of build from sources" OFF)
|
||||
|
||||
if (NOT DEFINED BUILD_SHARED_LIBS)
|
||||
set(BUILD_SHARED_LIBS ON)
|
||||
endif()
|
||||
|
||||
if (NOT BUILD_SHARED_LIBS)
|
||||
message(WARNING "You are building oneTBB as a static library. This is highly discouraged and such configuration is not supported. Consider building a dynamic library to avoid unforeseen issues.")
|
||||
endif()
|
||||
|
||||
if (NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES)
|
||||
set(CMAKE_BUILD_TYPE RelWithDebInfo CACHE STRING "Build type" FORCE)
|
||||
message(STATUS "CMAKE_BUILD_TYPE is not specified. Using default: ${CMAKE_BUILD_TYPE}")
|
||||
@@ -172,6 +151,8 @@ set(THREADS_PREFER_PTHREAD_FLAG TRUE)
|
||||
find_package(Threads REQUIRED)
|
||||
# -------------------------------------------------------------------
|
||||
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/modules)
|
||||
|
||||
file(GLOB FILES_WITH_EXTRA_TARGETS ${CMAKE_CURRENT_SOURCE_DIR}/cmake/*.cmake)
|
||||
foreach(FILE_WITH_EXTRA_TARGETS ${FILES_WITH_EXTRA_TARGETS})
|
||||
include(${FILE_WITH_EXTRA_TARGETS})
|
||||
@@ -194,9 +175,7 @@ else()
|
||||
if (NOT "${CMAKE_SYSTEM_PROCESSOR}" MATCHES "mips")
|
||||
add_subdirectory(src/tbbmalloc)
|
||||
add_subdirectory(src/tbbmalloc_proxy)
|
||||
if (APPLE)
|
||||
message(STATUS "TBBBind build target is disabled due to unsupported environment")
|
||||
else()
|
||||
if (TBB_NUMA_SUPPORT)
|
||||
add_subdirectory(src/tbbbind)
|
||||
endif()
|
||||
endif()
|
||||
@@ -205,28 +184,21 @@ else()
|
||||
# Installation instructions
|
||||
include(CMakePackageConfigHelpers)
|
||||
|
||||
install(DIRECTORY include/
|
||||
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}
|
||||
COMPONENT devel)
|
||||
install(DIRECTORY include
|
||||
DESTINATION .)
|
||||
|
||||
install(EXPORT ${PROJECT_NAME}Targets
|
||||
install(EXPORT ${CMAKE_PROJECT_NAME}Targets
|
||||
NAMESPACE TBB::
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
COMPONENT devel)
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake
|
||||
"include(\${CMAKE_CURRENT_LIST_DIR}/${PROJECT_NAME}Targets.cmake)\n")
|
||||
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
|
||||
file(WRITE ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake
|
||||
"include(\${CMAKE_CURRENT_LIST_DIR}/${CMAKE_PROJECT_NAME}Targets.cmake)\n")
|
||||
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
write_basic_package_version_file("${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake"
|
||||
COMPATIBILITY AnyNewerVersion)
|
||||
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PROJECT_NAME}
|
||||
COMPONENT devel)
|
||||
|
||||
install(FILES "README.md"
|
||||
DESTINATION ${CMAKE_INSTALL_DOCDIR}
|
||||
COMPONENT devel)
|
||||
install(FILES "${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}Config.cmake"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_PROJECT_NAME}ConfigVersion.cmake"
|
||||
DESTINATION lib/cmake/${CMAKE_PROJECT_NAME})
|
||||
# -------------------------------------------------------------------
|
||||
endif()
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# oneAPI Threading Building Blocks
|
||||
[](LICENSE.txt)
|
||||
# oneAPI Threading Building Blocks (Beta)
|
||||
[](LICENSE)
|
||||
|
||||
oneAPI Threading Building Blocks (oneTBB) lets you easily write parallel C++ programs that take
|
||||
full advantage of multicore performance, that are portable, composable and have future-proof scalability.
|
||||
@@ -15,35 +15,17 @@ Here are [Release Notes]( https://software.intel.com/en-us/articles/intel-oneapi
|
||||
## Support
|
||||
Please report issues and suggestions via
|
||||
[GitHub issues](https://github.com/oneapi-src/oneTBB/issues) or start a topic on the
|
||||
[oneTBB forum](https://community.intel.com/t5/Intel-oneAPI-Threading-Building/bd-p/oneapi-threading-building-blocks).
|
||||
[TBB forum](http://software.intel.com/en-us/forums/intel-threading-building-blocks/).
|
||||
|
||||
## How to Contribute
|
||||
To contribute to oneTBB, please open a GitHub pull request (preferred) or send us a patch by e-mail.
|
||||
|
||||
Please use the sign-off line at the end of the patch.
|
||||
Your signature certifies that you wrote the patch or
|
||||
otherwise have the right to pass it on as an open-source patch.
|
||||
The rules are pretty simple:
|
||||
if you can certify the https://developercertificate.org then you just add a line to every git commit message:
|
||||
```
|
||||
Signed-off-by: Name Surname <user@email.com>
|
||||
```
|
||||
Use your real name (sorry, no pseudonyms or anonymous contributions).
|
||||
|
||||
If you set your `user.name` and `user.email` git configs, you can sign your
|
||||
commit automatically with `git commit -s`.
|
||||
|
||||
## License
|
||||
oneAPI Threading Building Blocks is licensed under [Apache License, Version 2.0](LICENSE.txt).
|
||||
oneAPI Threading Building Blocks is licensed under [Apache License, Version 2.0](LICENSE).
|
||||
By its terms, contributions submitted to the project are also done under that license.
|
||||
|
||||
## Security
|
||||
To report security issues please go to https://intel.com/security.
|
||||
|
||||
## Engineering team contacts
|
||||
* [E-mail us.](mailto:inteltbbdevelopers@intel.com)
|
||||
|
||||
------------------------------------------------------------------------
|
||||
Intel and the Intel logo are trademarks of Intel Corporation or its subsidiaries in the U.S. and/or other countries.
|
||||
|
||||
\* Other names and brands may be claimed as the property of others.
|
||||
\* Other names and brands may be claimed as the property of others.
|
||||
@@ -6,15 +6,17 @@ The following controls are available during the configure stage:
|
||||
```
|
||||
TBB_TEST:BOOL - Enable testing (ON by default)
|
||||
TBB_STRICT:BOOL - Treat compiler warnings as errors (ON by default)
|
||||
TBB_NUMA_SUPPORT:BOOL - Enable TBBBind build target and task_arena extensions for NUMA support (depends on Portable Hardware Locality (hwloc) library) (OFF by default)
|
||||
TBB_SANITIZE:STRING - Sanitizer parameter, passed to compiler/linker
|
||||
TBB_SIGNTOOL:FILEPATH - Tool for digital signing, used in post install step for libraries if provided.
|
||||
TBB_SIGNTOOL_ARGS:STRING - Additional arguments for TBB_SIGNTOOL, used if TBB_SIGNTOOL is set.
|
||||
TBB4PY_BUILD:BOOL - Enable Intel(R) oneAPI Threading Building Blocks (oneTBB) Python module build (OFF by default)
|
||||
TBB_CPF:BOOL - Enable preview features of the library (OFF by default)
|
||||
TBB_INSTALL_VARS:BOOL - Enable auto-generated vars installation(packages generated by `cpack` and `make install` will also include the vars script)(OFF by default)
|
||||
TBB_VALGRIND_MEMCHECK:BOOL - Enable scan for memory leaks using Valgrind (OFF by default)
|
||||
```
|
||||
|
||||
# Getting Started
|
||||
|
||||
## Configure, build and test
|
||||
|
||||
### Prerequisites
|
||||
@@ -23,7 +25,7 @@ TBB_VALGRIND_MEMCHECK:BOOL - Enable scan for memory leaks using Valgrind (OFF by
|
||||
|
||||
### Preparation
|
||||
|
||||
In order to perform out-of-source build you have to create a build directory and go there:
|
||||
In order to perform out-of-source build you have to create a build directory somewhere and go there:
|
||||
|
||||
```bash
|
||||
mkdir /tmp/my-build
|
||||
@@ -40,24 +42,10 @@ Some useful options:
|
||||
- `-G <generator>` - specify particular project generator, see `cmake --help` for details.
|
||||
- `-DCMAKE_BUILD_TYPE=Debug` - specify for Debug build, it doesn't applicable for multi-config generators, e.g. for Visual Studio generator).
|
||||
|
||||
#### TBBBind library configuration
|
||||
|
||||
The TBBbind library has two versions: `tbbbind` and `tbbbind_2_0`. Each of these versions is linked with corresponding HWLOC library version: `tbbbind` links with HWLOC 1.11.x , `tbbbind_2_0` links with HWLOC 2.x.
|
||||
|
||||
To enable the TBBBind library build or special tests that performed inside the HWLOC environment, please specify the following CMake variables:
|
||||
|
||||
- `CMAKE_HWLOC_<HWLOC_VER>_LIBRARY_PATH` - path to the corresponding HWLOC version shared library on Linux or path to `.lib` file on Windows.
|
||||
- `CMAKE_HWLOC_<HWLOC_VER>_INCLUDE_PATH` - path to the corresponding HWLOC version includes directory.
|
||||
|
||||
Windows requires one additional variable for correct TBBBind library building:
|
||||
- `CMAKE_HWLOC_<HWLOC_VER>_DLL_PATH` - path to the corresponding HWLOC version `.dll` file.
|
||||
|
||||
`HWLOC_VER` variable used above can be replaced with one of the two values: `1_11` for the `tbbbind` library configuration and `2` for the `tbbbind_2_0` library configuration.
|
||||
|
||||
### Build
|
||||
|
||||
```bash
|
||||
cmake --build . <options>
|
||||
cmake --build <options> .
|
||||
```
|
||||
|
||||
Some useful options:
|
||||
@@ -139,18 +127,6 @@ make -j
|
||||
ctest -V
|
||||
```
|
||||
|
||||
## Valgrind memcheck - configure, build and run
|
||||
|
||||
### Prerequisites
|
||||
* Valgrind tool executable
|
||||
### Example
|
||||
```bash
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DTBB_VALGRIND_MEMCHECK=ON ..
|
||||
make -j memcheck-<test name> # or memcheck-all to scan all tests
|
||||
```
|
||||
|
||||
## Test specification (Doxygen)
|
||||
|
||||
```bash
|
||||
@@ -164,17 +140,6 @@ make test_spec
|
||||
|
||||
**NOTE: be careful about installation: avoid commands like `make install` unless you fully understand the consequences.**
|
||||
|
||||
The following install components are supported:
|
||||
- `runtime` - oneTBB runtime package (core shared libraries and `.dll` files on Windows).
|
||||
- `devel` - oneTBB development package (header files, CMake integration files, library symbolic links and `.lib` files on Windows).
|
||||
- `tbb4py` - [oneTBB Module for Python](#onetbb-python-module-support).
|
||||
|
||||
How to install specific components after configuration and build:
|
||||
|
||||
```bash
|
||||
cmake -DCOMPONENT=<component> [-DBUILD_TYPE=<build-type>] -P cmake_install.cmake
|
||||
```
|
||||
|
||||
Simple packaging using CPack is supported.
|
||||
The following commands allow to create a simple portable package which includes header files, libraries and integration files for CMake:
|
||||
|
||||
@@ -183,50 +148,6 @@ cmake <options> ..
|
||||
cpack
|
||||
```
|
||||
|
||||
## TBBConfig - integration of binary packages
|
||||
|
||||
It is a configuration module that is used for integration of prebuilt oneTBB. It consists of two files (TBBConfig.cmake and TBBConfigVersion.cmake) and can be used via [find_package](https://cmake.org/cmake/help/latest/command/find_package.html) function.
|
||||
|
||||
How to use this module in your CMake project:
|
||||
1. Let CMake know where to search for TBBConfig, e.g. specify location of TBBConfig.cmake in `TBB_DIR` (for more details about search paths see [find_package](https://cmake.org/cmake/help/latest/command/find_package.html)).
|
||||
2. Use [find_package](https://cmake.org/cmake/help/latest/command/find_package.html) to find oneTBB.
|
||||
3. Use provided variables and/or imported targets (described below) to work with the found oneTBB.
|
||||
|
||||
Example:
|
||||
|
||||
```cmake
|
||||
add_executable(foo foo.cpp)
|
||||
find_package(TBB)
|
||||
target_link_libraries(foo TBB::tbb)
|
||||
```
|
||||
|
||||
oneTBB components can be passed to [find_package](https://cmake.org/cmake/help/latest/command/find_package.html) after keyword ``COMPONENTS`` or ``REQUIRED``.
|
||||
Use basic names of components (`tbb`, `tbbmalloc`, etc.).
|
||||
|
||||
If components are not specified then the default set is used: `tbb`, `tbbmalloc` and ``tbbmalloc_proxy``.
|
||||
|
||||
If `tbbmalloc_proxy` is requested, `tbbmalloc` component will also be added and set as dependency for `tbbmalloc_proxy`.
|
||||
|
||||
TBBConfig creates [imported targets](https://cmake.org/cmake/help/latest/manual/cmake-buildsystem.7.html#imported-targets>) as
|
||||
shared libraries using the following format: `TBB::<component>` (for example, `TBB::tbb`, `TBB::tbbmalloc`).
|
||||
|
||||
Set `TBB_FIND_RELEASE_ONLY` to `TRUE` before calling `find_package` in order to search only for release oneTBB version. This variable helps to avoid simultaneous linkage of release and debug oneTBB versions when CMake configuration is `Debug` but a third-party component depends on release oneTBB version.
|
||||
|
||||
Variables set during TBB configuration:
|
||||
|
||||
Variable | Description
|
||||
--- | ---
|
||||
`TBB_FOUND` | oneTBB is found
|
||||
`TBB_<component>_FOUND` | Specific oneTBB component is found
|
||||
`TBB_VERSION` | oneTBB version (format: `<major>.<minor>.<patch>.<tweak>`)
|
||||
`TBB_IMPORTED_TARGETS` | All created oneTBB imported targets (not supported for builds from source code)
|
||||
|
||||
Starting from [oneTBB 2021.1](https://github.com/oneapi-src/oneTBB/releases/tag/v2021.1) GitHub release TBBConfig files in the binary packages are located under `<tbb-root>/lib/cmake/TBB`.
|
||||
For example, `TBB_DIR` should be set to `<tbb-root>/lib/cmake/TBB`.
|
||||
|
||||
TBBConfig files are automatically created during the build from source code and can be installed together with the library.
|
||||
Also oneTBB provides a helper function that creates TBBConfig files from predefined templates: see `tbb_generate_config` in `cmake/config_generation.cmake`.
|
||||
|
||||
## oneTBB Python Module support
|
||||
`TBB4PY_BUILD` Cmake option provides ability to build Python module for oneTBB.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -18,22 +18,11 @@ set(TBB_WARNING_LEVEL -Wall -Wextra $<$<BOOL:${TBB_STRICT}>:-Werror>)
|
||||
set(TBB_TEST_WARNING_FLAGS -Wshadow -Wcast-qual -Woverloaded-virtual -Wnon-virtual-dtor)
|
||||
set(TBB_WARNING_SUPPRESS -Wno-parentheses -Wno-non-virtual-dtor -Wno-dangling-else)
|
||||
# For correct ucontext.h structures layout
|
||||
set(TBB_COMMON_COMPILE_FLAGS -D_XOPEN_SOURCE)
|
||||
set(TBB_LIB_COMPILE_FLAGS -D_XOPEN_SOURCE)
|
||||
set(TBB_BENCH_COMPILE_FLAGS -D_XOPEN_SOURCE)
|
||||
|
||||
# Depfile options (e.g. -MD) are inserted automatically in some cases.
|
||||
# Don't add -MMD to avoid conflicts in such cases.
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT CMAKE_CXX_DEPENDS_USE_COMPILER)
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
endif()
|
||||
|
||||
# Ignore -Werror set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(-Werror)
|
||||
endif()
|
||||
|
||||
if (NOT "${CMAKE_OSX_ARCHITECTURES}" MATCHES "^arm64$" AND CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
|
||||
endif()
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
set(TBB_COMMON_COMPILE_FLAGS -mrtm)
|
||||
|
||||
# TBB malloc settings
|
||||
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -12,40 +12,28 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if (APPLE)
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,-exported_symbols_list,)
|
||||
set(TBB_DEF_FILE_PREFIX mac${TBB_ARCH})
|
||||
|
||||
# For correct ucontext.h structures layout
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -D_XOPEN_SOURCE)
|
||||
else()
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,--version-script=)
|
||||
set(TBB_DEF_FILE_PREFIX lin${TBB_ARCH})
|
||||
endif()
|
||||
|
||||
# Depfile options (e.g. -MD) are inserted automatically in some cases.
|
||||
# Don't add -MMD to avoid conflicts in such cases.
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT CMAKE_CXX_DEPENDS_USE_COMPILER)
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
endif()
|
||||
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,--version-script=)
|
||||
set(TBB_DEF_FILE_PREFIX lin${TBB_ARCH})
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
set(TBB_WARNING_LEVEL -Wall -Wextra $<$<BOOL:${TBB_STRICT}>:-Werror>)
|
||||
set(TBB_TEST_WARNING_FLAGS -Wshadow -Wcast-qual -Woverloaded-virtual -Wnon-virtual-dtor)
|
||||
|
||||
# Ignore -Werror set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(-Werror)
|
||||
endif()
|
||||
set(TBB_WARNING_SUPPRESS -Wno-parentheses -Wno-non-virtual-dtor -Wno-dangling-else)
|
||||
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
|
||||
set(TBB_COMMON_COMPILE_FLAGS -mrtm)
|
||||
endif()
|
||||
|
||||
set(TBB_COMMON_LINK_LIBS dl)
|
||||
|
||||
set(TBB_WARNING_SUPPRESS -Wno-non-virtual-dtor -Wno-dangling-else)
|
||||
if (ANDROID_PLATFORM)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} $<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>)
|
||||
set(TBB_COMMON_COMPILE_FLAGS $<$<NOT:$<CONFIG:Debug>>:-D_FORTIFY_SOURCE=2>)
|
||||
endif()
|
||||
|
||||
if (NOT APPLE)
|
||||
set(TBB_WARNING_SUPPRESS -Wno-parentheses)
|
||||
endif()
|
||||
|
||||
# TBB malloc settings
|
||||
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -12,42 +12,32 @@
|
||||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
if (APPLE)
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,-exported_symbols_list,)
|
||||
set(TBB_DEF_FILE_PREFIX mac${TBB_ARCH})
|
||||
|
||||
# For correct ucontext.h structures layout
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -D_XOPEN_SOURCE)
|
||||
else()
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,--version-script=)
|
||||
set(TBB_DEF_FILE_PREFIX lin${TBB_ARCH})
|
||||
endif()
|
||||
|
||||
set(TBB_LINK_DEF_FILE_FLAG -Wl,--version-script=)
|
||||
set(TBB_DEF_FILE_PREFIX lin${TBB_ARCH})
|
||||
set(TBB_WARNING_LEVEL -Wall -Wextra $<$<BOOL:${TBB_STRICT}>:-Werror> -Wfatal-errors)
|
||||
set(TBB_TEST_WARNING_FLAGS -Wshadow -Wcast-qual -Woverloaded-virtual -Wnon-virtual-dtor)
|
||||
|
||||
# Depfile options (e.g. -MD) are inserted automatically in some cases.
|
||||
# Don't add -MMD to avoid conflicts in such cases.
|
||||
if (NOT CMAKE_GENERATOR MATCHES "Ninja" AND NOT CMAKE_CXX_DEPENDS_USE_COMPILER)
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
endif()
|
||||
|
||||
set(TBB_MMD_FLAG -MMD)
|
||||
if (CMAKE_SYSTEM_PROCESSOR STREQUAL x86_64)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -mrtm)
|
||||
set(TBB_COMMON_COMPILE_FLAGS -mrtm)
|
||||
endif()
|
||||
|
||||
set(TBB_COMMON_LINK_LIBS dl)
|
||||
|
||||
# Ignore -Werror set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(-Werror)
|
||||
endif()
|
||||
|
||||
if (NOT ${CMAKE_CXX_COMPILER_ID} STREQUAL Intel)
|
||||
# gcc 6.0 and later have -flifetime-dse option that controls elimination of stores done outside the object lifetime
|
||||
set(TBB_DSE_FLAG $<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},6.0>>:-flifetime-dse=1>)
|
||||
endif()
|
||||
|
||||
if (NOT APPLE)
|
||||
set(TBB_WARNING_SUPPRESS -Wno-parentheses)
|
||||
# gcc 5.0 and later have -Wno-sized-deallocation options
|
||||
set(TBB_WARNING_SUPPRESS ${TBB_WARNING_SUPPRESS}
|
||||
$<$<NOT:$<VERSION_LESS:${CMAKE_CXX_COMPILER_VERSION},5.0>>:-Wno-sized-deallocation>)
|
||||
else()
|
||||
set(TBB_WARNING_SUPPRESS -Wno-non-virtual-dtor)
|
||||
endif()
|
||||
|
||||
# Workaround for heavy tests
|
||||
if ("${CMAKE_SYSTEM_PROCESSOR}" MATCHES "mips")
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} -DTBB_TEST_LOW_WORKLOAD)
|
||||
@@ -55,4 +45,4 @@ endif()
|
||||
|
||||
# TBB malloc settings
|
||||
set(TBBMALLOC_LIB_COMPILE_FLAGS -fno-rtti -fno-exceptions)
|
||||
set(TBB_OPENMP_FLAG -fopenmp)
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -15,17 +15,14 @@
|
||||
if (MSVC)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/MSVC.cmake)
|
||||
set(TBB_WARNING_LEVEL ${TBB_WARNING_LEVEL} /W3)
|
||||
set(TBB_OPENMP_FLAG /Qopenmp)
|
||||
elseif (APPLE)
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/AppleClang.cmake)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -fstack-protector -Wformat -Wformat-security
|
||||
$<$<NOT:$<CONFIG:Debug>>:-fno-omit-frame-pointer -qno-opt-report-embed -D_FORTIFY_SOURCE=2>)
|
||||
set(TBB_OPENMP_FLAG -qopenmp)
|
||||
else()
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/GNU.cmake)
|
||||
set(TBB_LIB_LINK_FLAGS ${TBB_LIB_LINK_FLAGS} -static-intel -Wl,-z,relro,-z,now,)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} -fstack-protector -Wformat -Wformat-security
|
||||
$<$<NOT:$<CONFIG:Debug>>:-qno-opt-report-embed -D_FORTIFY_SOURCE=2>
|
||||
$<$<EQUAL:${TBB_ARCH},32>:-falign-stack=maintain-16-byte>)
|
||||
set(TBB_OPENMP_FLAG -qopenmp)
|
||||
endif()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -21,22 +21,11 @@ string(REGEX REPLACE "/W[0-4]" "" CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}")
|
||||
|
||||
# Warning suppression C4324: structure was padded due to alignment specifier
|
||||
set(TBB_WARNING_LEVEL $<$<NOT:$<CXX_COMPILER_ID:Intel>>:/W4> $<$<BOOL:${TBB_STRICT}>:/WX>)
|
||||
set(TBB_WARNING_SUPPRESS /wd4324)
|
||||
set(TBB_WARNING_SUPPRESS /wd4324 /wd4530 /wd4577)
|
||||
set(TBB_TEST_COMPILE_FLAGS /bigobj)
|
||||
if (MSVC_VERSION LESS_EQUAL 1900)
|
||||
# Warning suppression C4503 for VS2015 and earlier:
|
||||
# decorated name length exceeded, name was truncated.
|
||||
# More info can be found at
|
||||
# https://docs.microsoft.com/en-us/cpp/error-messages/compiler-warnings/compiler-warning-level-1-c4503
|
||||
set(TBB_TEST_COMPILE_FLAGS ${TBB_TEST_COMPILE_FLAGS} /wd4503)
|
||||
endif()
|
||||
set(TBB_LIB_COMPILE_FLAGS -D_CRT_SECURE_NO_WARNINGS /GS)
|
||||
set(TBB_COMMON_COMPILE_FLAGS /volatile:iso /FS)
|
||||
|
||||
# Ignore /WX set through add_compile_options() or added to CMAKE_CXX_FLAGS if TBB_STRICT is disabled.
|
||||
if (NOT TBB_STRICT AND COMMAND tbb_remove_compile_flag)
|
||||
tbb_remove_compile_flag(/WX)
|
||||
endif()
|
||||
set(TBB_COMMON_COMPILE_FLAGS /volatile:iso /FS)
|
||||
|
||||
if (WINDOWS_STORE OR TBB_WINDOWS_DRIVER)
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /D_WIN32_WINNT=0x0A00)
|
||||
@@ -68,5 +57,3 @@ if (TBB_WINDOWS_DRIVER)
|
||||
|
||||
set(TBB_COMMON_COMPILE_FLAGS ${TBB_COMMON_COMPILE_FLAGS} /D _UNICODE /DUNICODE /DWINAPI_FAMILY=WINAPI_FAMILY_APP /D__WRL_NO_DEFAULT_LIB__)
|
||||
endif()
|
||||
|
||||
set(TBB_OPENMP_FLAG /openmp)
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
# Save current location,
|
||||
# see for details: https://cmake.org/cmake/help/latest/variable/CMAKE_CURRENT_LIST_DIR.html
|
||||
set(_tbb_gen_cfg_path ${CMAKE_CURRENT_LIST_DIR})
|
||||
|
||||
include(CMakeParseArguments)
|
||||
|
||||
function(tbb_generate_config)
|
||||
set(options HANDLE_SUBDIRS)
|
||||
set(oneValueArgs INSTALL_DIR
|
||||
SYSTEM_NAME
|
||||
LIB_REL_PATH INC_REL_PATH DLL_REL_PATH
|
||||
VERSION
|
||||
TBB_BINARY_VERSION
|
||||
TBBMALLOC_BINARY_VERSION
|
||||
TBBMALLOC_PROXY_BINARY_VERSION
|
||||
TBBBIND_BINARY_VERSION)
|
||||
|
||||
cmake_parse_arguments(tbb_gen_cfg "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN})
|
||||
|
||||
get_filename_component(config_install_dir ${tbb_gen_cfg_INSTALL_DIR} ABSOLUTE)
|
||||
file(MAKE_DIRECTORY ${config_install_dir})
|
||||
|
||||
file(TO_CMAKE_PATH "${tbb_gen_cfg_LIB_REL_PATH}" TBB_LIB_REL_PATH)
|
||||
file(TO_CMAKE_PATH "${tbb_gen_cfg_DLL_REL_PATH}" TBB_DLL_REL_PATH)
|
||||
file(TO_CMAKE_PATH "${tbb_gen_cfg_INC_REL_PATH}" TBB_INC_REL_PATH)
|
||||
|
||||
set(TBB_VERSION ${tbb_gen_cfg_VERSION})
|
||||
|
||||
set(TBB_COMPONENTS_BIN_VERSION "
|
||||
set(_tbb_bin_version ${tbb_gen_cfg_TBB_BINARY_VERSION})
|
||||
set(_tbbmalloc_bin_version ${tbb_gen_cfg_TBBMALLOC_BINARY_VERSION})
|
||||
set(_tbbmalloc_proxy_bin_version ${tbb_gen_cfg_TBBMALLOC_PROXY_BINARY_VERSION})
|
||||
set(_tbbbind_bin_version ${tbb_gen_cfg_TBBBIND_BINARY_VERSION})
|
||||
")
|
||||
|
||||
if (tbb_gen_cfg_SYSTEM_NAME STREQUAL "Linux")
|
||||
set(TBB_LIB_PREFIX "lib")
|
||||
set(TBB_LIB_EXT "so.\${_\${_tbb_component}_bin_version}")
|
||||
set(TBB_IMPLIB_RELEASE "")
|
||||
set(TBB_IMPLIB_DEBUG "")
|
||||
if (tbb_gen_cfg_HANDLE_SUBDIRS)
|
||||
set(TBB_HANDLE_SUBDIRS "
|
||||
if (CMAKE_SIZEOF_VOID_P STREQUAL \"8\")
|
||||
set(_tbb_subdir intel64/gcc4.8)
|
||||
else ()
|
||||
set(_tbb_subdir ia32/gcc4.8)
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
elseif (tbb_gen_cfg_SYSTEM_NAME STREQUAL "Darwin")
|
||||
set(TBB_LIB_PREFIX "lib")
|
||||
set(TBB_LIB_EXT "\${_\${_tbb_component}_bin_version}.dylib")
|
||||
set(TBB_IMPLIB_RELEASE "")
|
||||
set(TBB_IMPLIB_DEBUG "")
|
||||
elseif (tbb_gen_cfg_SYSTEM_NAME STREQUAL "Windows")
|
||||
set(TBB_LIB_PREFIX "")
|
||||
set(TBB_LIB_EXT "dll")
|
||||
set(TBB_COMPILE_DEFINITIONS "
|
||||
INTERFACE_COMPILE_DEFINITIONS \"__TBB_NO_IMPLICIT_LINKAGE=1\"")
|
||||
|
||||
# .lib files installed to TBB_LIB_REL_PATH (e.g. <prefix>/lib);
|
||||
# .dll files installed to TBB_DLL_REL_PATH (e.g. <prefix>/bin);
|
||||
# Expand TBB_LIB_REL_PATH here in IMPORTED_IMPLIB property and
|
||||
# redefine it with TBB_DLL_REL_PATH value to properly fill IMPORTED_LOCATION property in TBBConfig.cmake.in template.
|
||||
set(TBB_IMPLIB_RELEASE "
|
||||
IMPORTED_IMPLIB_RELEASE \"\${_tbb_root}/${TBB_LIB_REL_PATH}/\${_tbb_subdir}/\${_tbb_component}\${_bin_version}.lib\"")
|
||||
set(TBB_IMPLIB_DEBUG "
|
||||
IMPORTED_IMPLIB_DEBUG \"\${_tbb_root}/${TBB_LIB_REL_PATH}/\${_tbb_subdir}/\${_tbb_component}\${_bin_version}_debug.lib\"")
|
||||
set(TBB_LIB_REL_PATH ${TBB_DLL_REL_PATH})
|
||||
|
||||
if (tbb_gen_cfg_HANDLE_SUBDIRS)
|
||||
set(TBB_HANDLE_SUBDIRS "
|
||||
set(_tbb_subdir vc14)
|
||||
if (WINDOWS_STORE)
|
||||
set(_tbb_subdir \${_tbb_subdir}_uwp)
|
||||
endif()
|
||||
|
||||
if (CMAKE_SIZEOF_VOID_P STREQUAL \"8\")
|
||||
set(_tbb_subdir intel64/\${_tbb_subdir})
|
||||
else ()
|
||||
set(_tbb_subdir ia32/\${_tbb_subdir})
|
||||
endif()
|
||||
")
|
||||
endif()
|
||||
|
||||
set(TBB_HANDLE_BIN_VERSION "
|
||||
unset(_bin_version)
|
||||
if (_tbb_component STREQUAL tbb)
|
||||
set(_bin_version \${_tbb_bin_version})
|
||||
endif()
|
||||
")
|
||||
else()
|
||||
message(FATAL_ERROR "Unsupported OS name: ${tbb_system_name}")
|
||||
endif()
|
||||
|
||||
configure_file(${_tbb_gen_cfg_path}/templates/TBBConfig.cmake.in ${config_install_dir}/TBBConfig.cmake @ONLY)
|
||||
configure_file(${_tbb_gen_cfg_path}/templates/TBBConfigVersion.cmake.in ${config_install_dir}/TBBConfigVersion.cmake @ONLY)
|
||||
endfunction()
|
||||
@@ -1,63 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
list(APPEND HWLOC_REQUIRED_VERSIONS 1_11 2 2_4)
|
||||
|
||||
foreach(hwloc_version ${HWLOC_REQUIRED_VERSIONS})
|
||||
if (NOT WIN32)
|
||||
set(CMAKE_HWLOC_${hwloc_version}_DLL_PATH STUB)
|
||||
endif()
|
||||
set(HWLOC_TARGET_NAME HWLOC::hwloc_${hwloc_version})
|
||||
|
||||
if (NOT TARGET ${HWLOC_TARGET_NAME} AND
|
||||
CMAKE_HWLOC_${hwloc_version}_LIBRARY_PATH AND
|
||||
CMAKE_HWLOC_${hwloc_version}_DLL_PATH AND
|
||||
CMAKE_HWLOC_${hwloc_version}_INCLUDE_PATH
|
||||
)
|
||||
add_library(${HWLOC_TARGET_NAME} SHARED IMPORTED)
|
||||
set_target_properties(${HWLOC_TARGET_NAME} PROPERTIES INTERFACE_INCLUDE_DIRECTORIES
|
||||
"${CMAKE_HWLOC_${hwloc_version}_INCLUDE_PATH}")
|
||||
if (WIN32)
|
||||
set_target_properties(${HWLOC_TARGET_NAME} PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_HWLOC_${hwloc_version}_DLL_PATH}"
|
||||
IMPORTED_IMPLIB "${CMAKE_HWLOC_${hwloc_version}_LIBRARY_PATH}")
|
||||
else()
|
||||
set_target_properties(${HWLOC_TARGET_NAME} PROPERTIES
|
||||
IMPORTED_LOCATION "${CMAKE_HWLOC_${hwloc_version}_LIBRARY_PATH}")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if (TARGET ${HWLOC_TARGET_NAME})
|
||||
set(HWLOC_TARGET_EXPLICITLY_DEFINED TRUE)
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
unset(HWLOC_TARGET_NAME)
|
||||
|
||||
if (NOT HWLOC_TARGET_EXPLICITLY_DEFINED)
|
||||
find_package(PkgConfig QUIET)
|
||||
if (PKG_CONFIG_FOUND)
|
||||
pkg_search_module(HWLOC hwloc)
|
||||
if (HWLOC_FOUND)
|
||||
if (HWLOC_VERSION VERSION_LESS 2)
|
||||
set(TBBBIND_LIBRARY_NAME tbbbind)
|
||||
elseif(HWLOC_VERSION VERSION_LESS 2.4)
|
||||
set(TBBBIND_LIBRARY_NAME tbbbind_2_0)
|
||||
else()
|
||||
set(TBBBIND_LIBRARY_NAME tbbbind_2_4)
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
@@ -1,104 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
option(TBB_VALGRIND_MEMCHECK "Enable scan for memory leaks using Valgrind" OFF)
|
||||
|
||||
if (NOT TBB_VALGRIND_MEMCHECK)
|
||||
return()
|
||||
endif()
|
||||
|
||||
add_custom_target(memcheck-all
|
||||
COMMENT "Run memcheck on all tests")
|
||||
|
||||
find_program(VALGRIND_EXE valgrind)
|
||||
|
||||
if (NOT VALGRIND_EXE)
|
||||
message(FATAL_ERROR "Valgrind executable is not found, add tool to PATH or turn off TBB_VALGRIND_MEMCHECK")
|
||||
else()
|
||||
message(STATUS "Found Valgrind to run memory leak scan")
|
||||
endif()
|
||||
|
||||
file(MAKE_DIRECTORY ${CMAKE_BINARY_DIR}/memcheck)
|
||||
|
||||
function(_tbb_run_memcheck test_target)
|
||||
set(target_name memcheck-${test_target})
|
||||
add_custom_target(${target_name}
|
||||
COMMAND ${VALGRIND_EXE} --leak-check=full --show-leak-kinds=all --log-file=${CMAKE_BINARY_DIR}/memcheck/${target_name}.log -v $<TARGET_FILE:${test_target}>)
|
||||
add_dependencies(memcheck-all ${target_name})
|
||||
endfunction()
|
||||
|
||||
add_custom_target(memcheck-short
|
||||
COMMENT "Run memcheck scan on specified list")
|
||||
|
||||
# List of reasonable and quick enough tests to use in automated memcheck
|
||||
add_dependencies(memcheck-short
|
||||
memcheck-test_allocators
|
||||
memcheck-test_arena_constraints
|
||||
memcheck-test_dynamic_link
|
||||
memcheck-test_concurrent_lru_cache
|
||||
memcheck-conformance_concurrent_unordered_map
|
||||
memcheck-conformance_concurrent_unordered_set
|
||||
memcheck-conformance_concurrent_map
|
||||
memcheck-conformance_concurrent_set
|
||||
memcheck-conformance_concurrent_priority_queue
|
||||
memcheck-conformance_concurrent_vector
|
||||
memcheck-conformance_concurrent_queue
|
||||
memcheck-conformance_concurrent_hash_map
|
||||
memcheck-test_parallel_for
|
||||
memcheck-test_parallel_for_each
|
||||
memcheck-test_parallel_reduce
|
||||
memcheck-test_parallel_sort
|
||||
memcheck-test_parallel_invoke
|
||||
memcheck-test_parallel_scan
|
||||
memcheck-test_parallel_pipeline
|
||||
memcheck-test_eh_algorithms
|
||||
memcheck-test_task_group
|
||||
memcheck-test_task_arena
|
||||
memcheck-test_enumerable_thread_specific
|
||||
memcheck-test_resumable_tasks
|
||||
memcheck-conformance_mutex
|
||||
memcheck-test_function_node
|
||||
memcheck-test_multifunction_node
|
||||
memcheck-test_broadcast_node
|
||||
memcheck-test_buffer_node
|
||||
memcheck-test_composite_node
|
||||
memcheck-test_continue_node
|
||||
memcheck-test_eh_flow_graph
|
||||
memcheck-test_flow_graph
|
||||
memcheck-test_flow_graph_priorities
|
||||
memcheck-test_flow_graph_whitebox
|
||||
memcheck-test_indexer_node
|
||||
memcheck-test_join_node
|
||||
memcheck-test_join_node_key_matching
|
||||
memcheck-test_join_node_msg_key_matching
|
||||
memcheck-test_priority_queue_node
|
||||
memcheck-test_sequencer_node
|
||||
memcheck-test_split_node
|
||||
memcheck-test_tagged_msg
|
||||
memcheck-test_overwrite_node
|
||||
memcheck-test_write_once_node
|
||||
memcheck-test_async_node
|
||||
memcheck-test_input_node
|
||||
memcheck-test_profiling
|
||||
memcheck-test_concurrent_queue_whitebox
|
||||
memcheck-test_intrusive_list
|
||||
memcheck-test_semaphore
|
||||
memcheck-test_environment_whitebox
|
||||
memcheck-test_handle_perror
|
||||
memcheck-test_hw_concurrency
|
||||
memcheck-test_eh_thread
|
||||
memcheck-test_global_control
|
||||
memcheck-test_task
|
||||
memcheck-test_concurrent_monitor
|
||||
)
|
||||
@@ -0,0 +1,35 @@
|
||||
# Copyright (c) 2020 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.
|
||||
|
||||
if (NOT HWLOC_FOUND)
|
||||
find_path(HWLOC_INCLUDE_DIRS
|
||||
NAMES hwloc.h
|
||||
HINTS $ENV{INCLUDE} $ENV{CPATH} $ENV{C_INCLUDE_PATH} $ENV{INCLUDE_PATH}
|
||||
PATH_SUFFIXES "hwloc")
|
||||
|
||||
if (UNIX)
|
||||
set(HWLOC_LIB_NAME hwloc)
|
||||
elseif(WIN32)
|
||||
set(HWLOC_LIB_NAME libhwloc)
|
||||
endif()
|
||||
|
||||
find_library(HWLOC_LIBRARIES
|
||||
NAMES ${HWLOC_LIB_NAME}
|
||||
HINTS $ENV{LIBRARY_PATH} $ENV{LD_LIBRARY_PATH} $ENV{DYLD_LIBRARY_PATH})
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
find_package_handle_standard_args(HWLOC DEFAULT_MSG HWLOC_LIBRARIES HWLOC_INCLUDE_DIRS)
|
||||
|
||||
mark_as_advanced(HWLOC_LIB_NAME)
|
||||
endif()
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -14,7 +14,7 @@
|
||||
|
||||
# Note: current implementation uses CMAKE_BUILD_TYPE,
|
||||
# this parameter is not defined for multi-config generators.
|
||||
set(CPACK_PACKAGE_NAME "${PROJECT_NAME}")
|
||||
set(CPACK_PACKAGE_NAME "${CMAKE_PROJECT_NAME}")
|
||||
set(CPACK_PACKAGE_VERSION "${TBB_VERSION}")
|
||||
string(TOLOWER ${CPACK_PACKAGE_NAME}-${PROJECT_VERSION}-${CMAKE_SYSTEM_NAME}_${TBB_OUTPUT_DIR_BASE}_${CMAKE_BUILD_TYPE} CPACK_PACKAGE_FILE_NAME)
|
||||
set(CPACK_GENERATOR ZIP)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,54 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
include(${CMAKE_CURRENT_LIST_DIR}/../config_generation.cmake)
|
||||
|
||||
# TBBConfig in TBB provided packages are expected to be placed into: <tbb-root>/lib/cmake/tbb*
|
||||
set(TBB_ROOT_REL_PATH "../../..")
|
||||
|
||||
# Paths relative to TBB root directory
|
||||
set(INC_REL_PATH "include")
|
||||
set(LIB_REL_PATH "lib")
|
||||
set(DLL_REL_PATH "redist")
|
||||
|
||||
# Parse version info
|
||||
file(READ ${CMAKE_CURRENT_LIST_DIR}/../../include/oneapi/tbb/version.h _tbb_version_info)
|
||||
string(REGEX REPLACE ".*#define TBB_VERSION_MAJOR ([0-9]+).*" "\\1" _tbb_ver_major "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define TBB_VERSION_MINOR ([0-9]+).*" "\\1" _tbb_ver_minor "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define TBB_INTERFACE_VERSION ([0-9]+).*" "\\1" _tbb_interface_ver "${_tbb_version_info}")
|
||||
string(REGEX REPLACE ".*#define __TBB_BINARY_VERSION ([0-9]+).*" "\\1" TBB_BINARY_VERSION "${_tbb_version_info}")
|
||||
file(READ ${CMAKE_CURRENT_LIST_DIR}/../../CMakeLists.txt _tbb_cmakelist)
|
||||
string(REGEX REPLACE ".*TBBMALLOC_BINARY_VERSION ([0-9]+).*" "\\1" TBBMALLOC_BINARY_VERSION "${_tbb_cmakelist}")
|
||||
set(TBBMALLOC_PROXY_BINARY_VERSION ${TBBMALLOC_BINARY_VERSION})
|
||||
string(REGEX REPLACE ".*TBBBIND_BINARY_VERSION ([0-9]+).*" "\\1" TBBBIND_BINARY_VERSION "${_tbb_cmakelist}")
|
||||
|
||||
# Parse patch and tweak versions from interface version: e.g. 12014 --> 01 - patch version, 4 - tweak version.
|
||||
math(EXPR _tbb_ver_patch "${_tbb_interface_ver} % 1000 / 10")
|
||||
math(EXPR _tbb_ver_tweak "${_tbb_interface_ver} % 10")
|
||||
|
||||
set(COMMON_ARGS
|
||||
TBB_ROOT_REL_PATH ${TBB_ROOT_REL_PATH}
|
||||
INC_REL_PATH ${INC_REL_PATH}
|
||||
LIB_REL_PATH ${LIB_REL_PATH}
|
||||
VERSION ${_tbb_ver_major}.${_tbb_ver_minor}.${_tbb_ver_patch}.${_tbb_ver_tweak}
|
||||
TBB_BINARY_VERSION ${TBB_BINARY_VERSION}
|
||||
TBBMALLOC_BINARY_VERSION ${TBBMALLOC_BINARY_VERSION}
|
||||
TBBMALLOC_PROXY_BINARY_VERSION ${TBBMALLOC_PROXY_BINARY_VERSION}
|
||||
TBBBIND_BINARY_VERSION ${TBBBIND_BINARY_VERSION}
|
||||
)
|
||||
|
||||
tbb_generate_config(INSTALL_DIR ${INSTALL_DIR}/linux SYSTEM_NAME Linux HANDLE_SUBDIRS ${COMMON_ARGS})
|
||||
tbb_generate_config(INSTALL_DIR ${INSTALL_DIR}/windows SYSTEM_NAME Windows HANDLE_SUBDIRS DLL_REL_PATH ${DLL_REL_PATH} ${COMMON_ARGS})
|
||||
tbb_generate_config(INSTALL_DIR ${INSTALL_DIR}/darwin SYSTEM_NAME Darwin ${COMMON_ARGS})
|
||||
message(STATUS "TBBConfig files were created in ${INSTALL_DIR}")
|
||||
@@ -1,98 +0,0 @@
|
||||
# Copyright (c) 2017-2021 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.
|
||||
|
||||
# It defines the following variables:
|
||||
# TBB_<component>_FOUND
|
||||
# TBB_IMPORTED_TARGETS
|
||||
#
|
||||
# TBBConfigVersion.cmake defines TBB_VERSION
|
||||
#
|
||||
# Initialize to default values
|
||||
if (NOT TBB_IMPORTED_TARGETS)
|
||||
set(TBB_IMPORTED_TARGETS "")
|
||||
endif()
|
||||
|
||||
if (NOT TBB_FIND_COMPONENTS)
|
||||
set(TBB_FIND_COMPONENTS "tbb;tbbmalloc;tbbmalloc_proxy")
|
||||
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
|
||||
set(TBB_FIND_REQUIRED_${_tbb_component} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
get_filename_component(_tbb_root "${CMAKE_CURRENT_LIST_DIR}" REALPATH)
|
||||
get_filename_component(_tbb_root "${_tbb_root}/@TBB_ROOT_REL_PATH@" ABSOLUTE)
|
||||
|
||||
set(TBB_INTERFACE_VERSION @TBB_INTERFACE_VERSION@)
|
||||
@TBB_COMPONENTS_BIN_VERSION@
|
||||
# Add components with internal dependencies: tbbmalloc_proxy -> tbbmalloc
|
||||
list(FIND TBB_FIND_COMPONENTS tbbmalloc_proxy _tbbmalloc_proxy_ix)
|
||||
if (NOT _tbbmalloc_proxy_ix EQUAL -1)
|
||||
list(APPEND TBB_FIND_COMPONENTS tbbmalloc)
|
||||
list(REMOVE_DUPLICATES TBB_FIND_COMPONENTS)
|
||||
set(TBB_FIND_REQUIRED_tbbmalloc ${TBB_FIND_REQUIRED_tbbmalloc_proxy})
|
||||
endif()
|
||||
unset(_tbbmalloc_proxy_ix)
|
||||
@TBB_HANDLE_SUBDIRS@
|
||||
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
|
||||
set(TBB_${_tbb_component}_FOUND 0)
|
||||
@TBB_HANDLE_BIN_VERSION@
|
||||
get_filename_component(_tbb_release_lib "${_tbb_root}/@TBB_LIB_REL_PATH@/${_tbb_subdir}/@TBB_LIB_PREFIX@${_tbb_component}${_bin_version}.@TBB_LIB_EXT@" ABSOLUTE)
|
||||
|
||||
if (NOT TBB_FIND_RELEASE_ONLY)
|
||||
get_filename_component(_tbb_debug_lib "${_tbb_root}/@TBB_LIB_REL_PATH@/${_tbb_subdir}/@TBB_LIB_PREFIX@${_tbb_component}${_bin_version}_debug.@TBB_LIB_EXT@" ABSOLUTE)
|
||||
endif()
|
||||
|
||||
if (EXISTS "${_tbb_release_lib}" OR EXISTS "${_tbb_debug_lib}")
|
||||
if (NOT TARGET TBB::${_tbb_component})
|
||||
add_library(TBB::${_tbb_component} SHARED IMPORTED)
|
||||
|
||||
get_filename_component(_tbb_include_dir "${_tbb_root}/@TBB_INC_REL_PATH@" ABSOLUTE)
|
||||
set_target_properties(TBB::${_tbb_component} PROPERTIES
|
||||
INTERFACE_INCLUDE_DIRECTORIES "${_tbb_include_dir}"@TBB_COMPILE_DEFINITIONS@)
|
||||
unset(_tbb_current_realpath)
|
||||
unset(_tbb_include_dir)
|
||||
|
||||
if (EXISTS "${_tbb_release_lib}")
|
||||
set_target_properties(TBB::${_tbb_component} PROPERTIES
|
||||
IMPORTED_LOCATION_RELEASE "${_tbb_release_lib}"@TBB_IMPLIB_RELEASE@)
|
||||
set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS RELEASE)
|
||||
endif()
|
||||
|
||||
if (EXISTS "${_tbb_debug_lib}")
|
||||
set_target_properties(TBB::${_tbb_component} PROPERTIES
|
||||
IMPORTED_LOCATION_DEBUG "${_tbb_debug_lib}"@TBB_IMPLIB_DEBUG@)
|
||||
set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS DEBUG)
|
||||
endif()
|
||||
|
||||
# Add internal dependencies for imported targets: TBB::tbbmalloc_proxy -> TBB::tbbmalloc
|
||||
if (_tbb_component STREQUAL tbbmalloc_proxy)
|
||||
set_target_properties(TBB::tbbmalloc_proxy PROPERTIES INTERFACE_LINK_LIBRARIES TBB::tbbmalloc)
|
||||
endif()
|
||||
endif()
|
||||
list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component})
|
||||
set(TBB_${_tbb_component}_FOUND 1)
|
||||
elseif (TBB_FIND_REQUIRED AND TBB_FIND_REQUIRED_${_tbb_component})
|
||||
message(STATUS "Missed required oneTBB component: ${_tbb_component}")
|
||||
if (TBB_FIND_RELEASE_ONLY)
|
||||
message(STATUS " ${_tbb_release_lib} must exist.")
|
||||
else()
|
||||
message(STATUS " one or both of:\n ${_tbb_release_lib}\n ${_tbb_debug_lib}\n files must exist.")
|
||||
endif()
|
||||
set(TBB_FOUND FALSE)
|
||||
endif()
|
||||
endforeach()
|
||||
list(REMOVE_DUPLICATES TBB_IMPORTED_TARGETS)
|
||||
unset(_tbb_release_lib)
|
||||
unset(_tbb_debug_lib)
|
||||
unset(_tbb_root)
|
||||
@@ -1,24 +0,0 @@
|
||||
# Copyright (c) 2017-2021 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.
|
||||
|
||||
set(PACKAGE_VERSION @TBB_VERSION@)
|
||||
|
||||
if ("${PACKAGE_VERSION}" VERSION_LESS "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_COMPATIBLE FALSE)
|
||||
else()
|
||||
set(PACKAGE_VERSION_COMPATIBLE TRUE)
|
||||
if ("${PACKAGE_VERSION}" VERSION_EQUAL "${PACKAGE_FIND_VERSION}")
|
||||
set(PACKAGE_VERSION_EXACT TRUE)
|
||||
endif()
|
||||
endif()
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
|
||||
@@ -1,44 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
macro(tbb_remove_compile_flag flag)
|
||||
get_property(_tbb_compile_options DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS)
|
||||
list(REMOVE_ITEM _tbb_compile_options ${flag})
|
||||
set_property(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} PROPERTY COMPILE_OPTIONS ${_tbb_compile_options})
|
||||
unset(_tbb_compile_options)
|
||||
if (CMAKE_CXX_FLAGS)
|
||||
string(REGEX REPLACE ${flag} "" CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(tbb_install_target target)
|
||||
install(TARGETS ${target}
|
||||
EXPORT TBBTargets
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
NAMELINK_SKIP
|
||||
COMPONENT runtime
|
||||
RUNTIME
|
||||
DESTINATION ${CMAKE_INSTALL_BINDIR}
|
||||
COMPONENT runtime
|
||||
ARCHIVE
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
COMPONENT devel)
|
||||
|
||||
install(TARGETS ${target}
|
||||
LIBRARY
|
||||
DESTINATION ${CMAKE_INSTALL_LIBDIR}
|
||||
NAMELINK_ONLY
|
||||
COMPONENT devel)
|
||||
endmacro()
|
||||
@@ -1,4 +1,4 @@
|
||||
# Copyright (c) 2020-2021 Intel Corporation
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||
# you may not use this file except in compliance with the License.
|
||||
@@ -22,23 +22,20 @@ else()
|
||||
set(TBB_VARS_TEMPLATE "linux/env/vars.sh.in")
|
||||
endif()
|
||||
|
||||
get_filename_component(TBB_VARS_TEMPLATE_NAME ${PROJECT_SOURCE_DIR}/integration/${TBB_VARS_TEMPLATE} NAME)
|
||||
get_filename_component(TBB_VARS_TEMPLATE_NAME ${CMAKE_SOURCE_DIR}/integration/${TBB_VARS_TEMPLATE} NAME)
|
||||
string(REPLACE ".in" "" TBB_VARS_NAME ${TBB_VARS_TEMPLATE_NAME})
|
||||
|
||||
macro(tbb_gen_vars target)
|
||||
if (${CMAKE_PROJECT_NAME} STREQUAL ${PROJECT_NAME})
|
||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DBINARY_DIR=${CMAKE_BINARY_DIR}
|
||||
-DSOURCE_DIR=${PROJECT_SOURCE_DIR}
|
||||
-DBIN_PATH=$<TARGET_FILE_DIR:${target}>
|
||||
-DVARS_TEMPLATE=${TBB_VARS_TEMPLATE}
|
||||
-DVARS_NAME=${TBB_VARS_NAME}
|
||||
-DTBB_INSTALL_VARS=${TBB_INSTALL_VARS}
|
||||
-DTBB_CMAKE_INSTALL_LIBDIR=${CMAKE_INSTALL_LIBDIR}
|
||||
-P ${PROJECT_SOURCE_DIR}/integration/cmake/generate_vars.cmake
|
||||
)
|
||||
endif()
|
||||
add_custom_command(TARGET ${target} POST_BUILD COMMAND
|
||||
${CMAKE_COMMAND}
|
||||
-DBINARY_DIR=${CMAKE_BINARY_DIR}
|
||||
-DSOURCE_DIR=${CMAKE_SOURCE_DIR}
|
||||
-DBIN_PATH=$<TARGET_FILE_DIR:${target}>
|
||||
-DVARS_TEMPLATE=${TBB_VARS_TEMPLATE}
|
||||
-DVARS_NAME=${TBB_VARS_NAME}
|
||||
-DTBB_INSTALL_VARS=${TBB_INSTALL_VARS}
|
||||
-P ${CMAKE_SOURCE_DIR}/integration/cmake/generate_vars.cmake
|
||||
)
|
||||
endmacro(tbb_gen_vars)
|
||||
|
||||
if (TBB_INSTALL_VARS)
|
||||
|
||||
@@ -19,7 +19,6 @@
|
||||
<tab type="filelist" visible="no" title="" intro=""/>
|
||||
<tab type="globals" visible="no" title="" intro=""/>
|
||||
</tab>
|
||||
<tab type="user" url="@ref test_classification" visible="yes" title="Test Classification"/>
|
||||
<tab type="examples" visible="yes" title="" intro=""/>
|
||||
</navindex>
|
||||
|
||||
|
||||
@@ -1,159 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
---
|
||||
Language: Cpp
|
||||
AccessModifierOffset: -4
|
||||
AlignAfterOpenBracket: Align
|
||||
AlignConsecutiveAssignments: false
|
||||
AlignConsecutiveDeclarations: false
|
||||
AlignConsecutiveMacros: true
|
||||
AlignEscapedNewlines: Left
|
||||
AlignOperands: true
|
||||
AlignTrailingComments: false
|
||||
AllowAllArgumentsOnNextLine: true
|
||||
AllowAllConstructorInitializersOnNextLine: false
|
||||
AllowAllParametersOfDeclarationOnNextLine: false
|
||||
AllowShortBlocksOnASingleLine: false
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: Empty
|
||||
AllowShortIfStatementsOnASingleLine: Never
|
||||
AllowShortLambdasOnASingleLine: Empty
|
||||
AllowShortLoopsOnASingleLine: false
|
||||
AlwaysBreakAfterDefinitionReturnType: None
|
||||
AlwaysBreakAfterReturnType: None
|
||||
AlwaysBreakBeforeMultilineStrings: false
|
||||
AlwaysBreakTemplateDeclarations: Yes
|
||||
BinPackArguments: false
|
||||
BinPackParameters: false
|
||||
BraceWrapping:
|
||||
AfterCaseLabel: false
|
||||
AfterClass: false
|
||||
AfterControlStatement: false
|
||||
AfterEnum: false
|
||||
AfterFunction: false
|
||||
AfterNamespace: false
|
||||
AfterObjCDeclaration: false
|
||||
AfterStruct: false
|
||||
AfterUnion: false
|
||||
AfterExternBlock: false
|
||||
BeforeCatch: true
|
||||
BeforeElse: true
|
||||
IndentBraces: false
|
||||
SplitEmptyFunction: false
|
||||
SplitEmptyRecord: false
|
||||
SplitEmptyNamespace: false
|
||||
BreakBeforeBinaryOperators: None
|
||||
BreakBeforeBraces: Custom
|
||||
BreakBeforeTernaryOperators: true
|
||||
BreakConstructorInitializers: BeforeColon
|
||||
BreakInheritanceList: BeforeColon
|
||||
BreakStringLiterals: false
|
||||
ColumnLimit: 100
|
||||
CommentPragmas: '^ IWYU pragma:'
|
||||
CompactNamespaces: false
|
||||
ConstructorInitializerAllOnOneLineOrOnePerLine: true
|
||||
ConstructorInitializerIndentWidth: 8
|
||||
ContinuationIndentWidth: 4
|
||||
Cpp11BracedListStyle: false
|
||||
DerivePointerAlignment: true
|
||||
DisableFormat: false
|
||||
FixNamespaceComments: true
|
||||
ForEachMacros:
|
||||
- foreach
|
||||
- Q_FOREACH
|
||||
- BOOST_FOREACH
|
||||
IncludeBlocks: Preserve
|
||||
IncludeCategories:
|
||||
- Regex: '^<ext/.*\.h>'
|
||||
Priority: 2
|
||||
- Regex: '^<.*\.h>'
|
||||
Priority: 1
|
||||
- Regex: '^<.*'
|
||||
Priority: 2
|
||||
- Regex: '.*'
|
||||
Priority: 3
|
||||
IncludeIsMainRegex: '([-_](test|unittest))?$'
|
||||
IndentCaseLabels: true
|
||||
IndentPPDirectives: None
|
||||
IndentWidth: 4
|
||||
IndentWrappedFunctionNames: false
|
||||
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||
MacroBlockBegin: ''
|
||||
MacroBlockEnd: ''
|
||||
MaxEmptyLinesToKeep: 1
|
||||
NamespaceIndentation: None
|
||||
PenaltyBreakAssignment: 2
|
||||
PenaltyBreakBeforeFirstCallParameter: 1
|
||||
PenaltyBreakComment: 300
|
||||
PenaltyBreakFirstLessLess: 120
|
||||
PenaltyBreakString: 1000
|
||||
PenaltyBreakTemplateDeclaration: 10
|
||||
PenaltyExcessCharacter: 1000000
|
||||
PenaltyReturnTypeOnItsOwnLine: 200
|
||||
PointerAlignment: Left
|
||||
RawStringFormats:
|
||||
- Language: Cpp
|
||||
Delimiters:
|
||||
- cc
|
||||
- CC
|
||||
- cpp
|
||||
- Cpp
|
||||
- CPP
|
||||
- 'c++'
|
||||
- 'C++'
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
- Language: TextProto
|
||||
Delimiters:
|
||||
- pb
|
||||
- PB
|
||||
- proto
|
||||
- PROTO
|
||||
EnclosingFunctions:
|
||||
- EqualsProto
|
||||
- EquivToProto
|
||||
- PARSE_PARTIAL_TEXT_PROTO
|
||||
- PARSE_TEST_PROTO
|
||||
- PARSE_TEXT_PROTO
|
||||
- ParseTextOrDie
|
||||
- ParseTextProtoOrDie
|
||||
CanonicalDelimiter: ''
|
||||
BasedOnStyle: google
|
||||
ReflowComments: false
|
||||
SortIncludes: false
|
||||
SortUsingDeclarations: false
|
||||
SpaceAfterCStyleCast: false
|
||||
SpaceAfterLogicalNot: false
|
||||
SpaceAfterTemplateKeyword: true
|
||||
SpaceBeforeAssignmentOperators: true
|
||||
SpaceBeforeCpp11BracedList: false
|
||||
SpaceBeforeCtorInitializerColon: true
|
||||
SpaceBeforeInheritanceColon: true
|
||||
SpaceBeforeParens: ControlStatements
|
||||
SpaceBeforeRangeBasedForLoopColon: true
|
||||
SpaceInEmptyParentheses: false
|
||||
SpacesBeforeTrailingComments: 1
|
||||
SpacesInAngles: false
|
||||
SpacesInContainerLiterals: false
|
||||
SpacesInCStyleCastParentheses: false
|
||||
SpacesInParentheses: false
|
||||
SpacesInSquareBrackets: false
|
||||
Standard: Cpp11
|
||||
StatementMacros:
|
||||
- Q_UNUSED
|
||||
- QT_REQUIRE_VERSION
|
||||
TabWidth: 1
|
||||
UseTab: Never
|
||||
...
|
||||
@@ -1,75 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
project(tbb_examples CXX)
|
||||
|
||||
add_custom_target(build_examples)
|
||||
add_custom_target(run_examples)
|
||||
add_dependencies(run_examples build_examples)
|
||||
|
||||
add_custom_target(light_test_examples)
|
||||
add_dependencies(light_test_examples build_examples)
|
||||
|
||||
macro(tbb_add_example subdir name)
|
||||
add_subdirectory(${subdir}/${name})
|
||||
add_dependencies(build_examples ${name})
|
||||
add_dependencies(run_examples run_${name})
|
||||
if (TARGET light_test_${name})
|
||||
add_dependencies(light_test_examples light_test_${name})
|
||||
else()
|
||||
add_dependencies(light_test_examples run_${name})
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
tbb_add_example(concurrent_hash_map count_strings)
|
||||
tbb_add_example(concurrent_priority_queue shortpath)
|
||||
|
||||
tbb_add_example(getting_started sub_string_finder)
|
||||
|
||||
tbb_add_example(graph binpack)
|
||||
|
||||
# TODO: Consider using FindMKL module
|
||||
find_library(MKL_INTEL_LP64_LIB mkl_intel_lp64 PATHS ENV LIBRARY_PATH)
|
||||
find_library(MKL_SEQUENTIAL_LIB mkl_sequential PATHS ENV LIBRARY_PATH)
|
||||
find_library(MKL_CORE_LIB mkl_core PATHS ENV LIBRARY_PATH)
|
||||
if(MKL_INTEL_LP64_LIB AND MKL_SEQUENTIAL_LIB AND MKL_CORE_LIB)
|
||||
tbb_add_example(graph cholesky)
|
||||
else()
|
||||
message(WARNING "Intel(R) Math Kernel Library (Intel(R) MKL) libraries were not found, graph/cholesky example is excluded from the build.")
|
||||
endif()
|
||||
|
||||
tbb_add_example(graph dining_philosophers)
|
||||
tbb_add_example(graph fgbzip2)
|
||||
tbb_add_example(graph logic_sim)
|
||||
tbb_add_example(graph som)
|
||||
|
||||
tbb_add_example(parallel_for game_of_life)
|
||||
tbb_add_example(parallel_for polygon_overlay)
|
||||
tbb_add_example(parallel_for seismic)
|
||||
tbb_add_example(parallel_for tachyon)
|
||||
|
||||
tbb_add_example(parallel_for_each parallel_preorder)
|
||||
|
||||
tbb_add_example(parallel_pipeline square)
|
||||
|
||||
tbb_add_example(parallel_reduce convex_hull)
|
||||
tbb_add_example(parallel_reduce primes)
|
||||
|
||||
tbb_add_example(task_arena fractal)
|
||||
|
||||
tbb_add_example(task_group sudoku)
|
||||
|
||||
tbb_add_example(test_all fibonacci)
|
||||
@@ -1,40 +0,0 @@
|
||||
# Code Samples of oneAPI Threading Building Blocks (oneTBB)
|
||||
This directory contains example usages of oneAPI Threading Building Blocks.
|
||||
|
||||
| Code sample name | Description
|
||||
|:--- |:---
|
||||
| getting_started/sub_string_finder | Example referenced by the [oneAPI Threading Building Blocks Get Started Guide](https://software.intel.com/content/www/us/en/develop/documentation/get-started-with-onetbb/top.html). Finds largest matching substrings.
|
||||
| concurrent_hash_map/count_strings | Concurrently inserts strings into a `concurrent_hash_map` container.
|
||||
| concurrent_priority_queue/shortpath | Solves the single source shortest path problem using a `concurrent_priority_queue` container.
|
||||
| graph/binpack | A solution to the binpacking problem using a `queue_node`, a `buffer_node` and `function_node`s.
|
||||
| graph/cholesky | Several versions of Cholesky Factorization algorithm implementation.
|
||||
| graph/dining_philosophers | An implementation of dining philosophers in graph using the reserving `join_node`.
|
||||
| graph/fgbzip2 | A parallel implementation of bzip2 block-sorting file compressor.
|
||||
| graph/logic_sim | An example of a collection of digital logic gates that can be easily composed into larger circuits.
|
||||
| graph/som | An example of a Kohonen Self-Organizing Map using cancellation.
|
||||
| parallel_for/game_of_life | Game of life overlay.
|
||||
| parallel_for/polygon_overlay | polygon overlay.
|
||||
| parallel_for/seismic | Parallel seismic wave simulation.
|
||||
| parallel_for/tachyon | Parallel 2-D raytracer/renderer.
|
||||
| parallel_for_each/parallel_preorder | Parallel preorder traversal of a graph.
|
||||
| parallel_pipeline/square | Another string transformation example that squares numbers read from a file.
|
||||
| parallel_reduce/convex_hull | Parallel version of convex hull algorithm (quick hull).
|
||||
| parallel_reduce/primes | Parallel version of the Sieve of Eratosthenes.
|
||||
| task_arena/fractal |The example calculates two classical Mandelbrot fractals with different concurrency limits.
|
||||
| task_group/sudoku | Compute all solutions for a Sudoku board.
|
||||
| test_all/fibonacci | Compute Fibonacci numbers in different ways.
|
||||
|
||||
## System Requirements
|
||||
"Refer to the [System Requirements](https://software.intel.com/content/www/us/en/develop/articles/intel-oneapi-threading-building-blocks-system-requirements.html) for the list of supported hardware and software".
|
||||
|
||||
### Graphical User Interface (GUI)
|
||||
Some examples (fractal, seismic, tachyon, polygon_overlay) supports different GUI modes, which may be defined via the `EXAMPLES_UI_MODE` CMake variable. Supported values are:
|
||||
- Cross-platform:
|
||||
- `con` - Console mode (Default).
|
||||
- Windows:
|
||||
- `gdi` - `GDI+` based implementation.
|
||||
- `d2d` - `Direct 2D` based implementation. May offer superior performance, but can only be used if the Microsoft* DirectX* SDK is installed on your system(`DXSDK_DIR` should be defined).
|
||||
- Linux:
|
||||
- `x` - `X11` based implementation. Also `libXext` may be required to display the output correctly.
|
||||
- MacOS:
|
||||
- `mac` - `OpenGL` based implementation. Also requires the `Foundation` and `Cocoa` libraries availability.
|
||||
@@ -0,0 +1,838 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# FPGA Development Flow and optimizations"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Sections\n",
|
||||
"- [oneAPI with Intel® FPGAs](#oneAPI-with-Intel®-FPGAs)\n",
|
||||
"- [Stage 1: Emulation](#Stage-1:-Emulation)\n",
|
||||
"- [Stage 2: Optimization Report Generation](#Stage-2:-Optimization-Report-Generation)\n",
|
||||
"- [Stage 3: Optimizing the previous code](#Stage-3:-Optimizing-the-previous-code)\n",
|
||||
"- [References to Learn More](#References-to-Learn-More)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"# oneAPI with Intel® FPGAs\n",
|
||||
"\n",
|
||||
"The development flow for Intel FPGAs with oneAPI includes multiple stages. The purpose of these stages is to:\n",
|
||||
"* Ensure functionality of your code (you get the correct answers from your computation)\n",
|
||||
"* Ensure the custom hardware built to implement your code has optimal performance\n",
|
||||
"\n",
|
||||
"Without having to endure the lengthy compile to a full FPGA executable each time.\n",
|
||||
"\n",
|
||||
"The detailed flow is shown in the diagram below.\n",
|
||||
"\n",
|
||||
"In this lab, we will practice the first 2 stages of the flow - emulating your code to make sure your code is functional, and generating an optimization report to see how optimized the hardware image generated from your code is. (A subsequent lab will give you practice working with the optimization report.)\n",
|
||||
"\n",
|
||||
"<img src=\"assets/fpga_flow.png\">"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"# Stage 1: Emulation\n",
|
||||
"\n",
|
||||
"The first stage developing code for FPGAs with oneAPI is __emulation__. The purpose of emulation is to make sure that your code is __functional__, or in other words, that you __get the correct answers from your computations__.\n",
|
||||
"\n",
|
||||
"The compile time for this stage will be very quick, usually seconds.\n",
|
||||
"\n",
|
||||
"This quick compile time allows you to iterate through this stage many times, until your code is functionally correct.\n",
|
||||
"\n",
|
||||
"__Now, let's give it a try!__\n",
|
||||
"\n",
|
||||
"The code below just adds two vectors. Please have a quick look to get an overview of what it is doing.\n",
|
||||
"\n",
|
||||
"We will continue using this simple piece of code to learn about the development flow for FPGAs with oneAPI and howto apply optimizations.\n",
|
||||
"\n",
|
||||
"__After you are finished examining the code, click ▶ to save the code to a file.__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 1,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Writing lab/loop.cpp\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile lab/loop.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"#include <CL/sycl.hpp>\n",
|
||||
"#include <iomanip>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"// dpc_common.hpp can be found in the dev-utilities include folder.\n",
|
||||
"// e.g., $ONEAPI_ROOT/dev-utilities/latest/include/dpc_common.hpp\n",
|
||||
"#include \"dpc_common.hpp\"\n",
|
||||
"\n",
|
||||
"// Header locations and some DPC++ extensions changed between beta09 and beta10\n",
|
||||
"// Temporarily modify the code sample to accept either version\n",
|
||||
"#define BETA09 20200827\n",
|
||||
"#if __SYCL_COMPILER_VERSION <= BETA09\n",
|
||||
" #include <CL/sycl/intel/fpga_extensions.hpp>\n",
|
||||
" namespace INTEL = sycl::intel; // Namespace alias for backward compatibility\n",
|
||||
"#else\n",
|
||||
" #include <CL/sycl/INTEL/fpga_extensions.hpp>\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
"using namespace sycl;\n",
|
||||
"\n",
|
||||
"// This function instantiates the vector add kernel, which contains\n",
|
||||
"// a loop that adds up the two summand arrays and stores the result\n",
|
||||
"// into sum. \n",
|
||||
"void VecAdd(const std::vector<float> &summands1,\n",
|
||||
" const std::vector<float> &summands2, std::vector<float> &sum,\n",
|
||||
" size_t array_size) {\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#if defined(FPGA_EMULATOR)\n",
|
||||
" INTEL::fpga_emulator_selector device_selector;\n",
|
||||
"#else\n",
|
||||
" INTEL::fpga_selector device_selector;\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
" try {\n",
|
||||
" queue q(device_selector, dpc_common::exception_handler,\n",
|
||||
" property::queue::enable_profiling{});\n",
|
||||
"\n",
|
||||
" buffer buffer_summands1(summands1);\n",
|
||||
" buffer buffer_summands2(summands2);\n",
|
||||
" // Use verbose SYCL 1.2 syntax for the output buffer.\n",
|
||||
" // (This will become unnecessary in a future compiler version.)\n",
|
||||
" buffer<float, 1> buffer_sum(sum.data(), array_size);\n",
|
||||
"\n",
|
||||
" event e = q.submit([&](handler &h) {\n",
|
||||
" auto acc_summands1 = buffer_summands1.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_summands2 = buffer_summands2.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_sum = buffer_sum.get_access<access::mode::discard_write>(h);\n",
|
||||
"\n",
|
||||
" h.single_task([=]() {\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" acc_sum[i] = acc_summands1[i] + acc_summands2[i];\n",
|
||||
" }\n",
|
||||
" });\n",
|
||||
" });\n",
|
||||
"\n",
|
||||
" double start = e.get_profiling_info<info::event_profiling::command_start>();\n",
|
||||
" double end = e.get_profiling_info<info::event_profiling::command_end>();\n",
|
||||
" // convert from nanoseconds to ms\n",
|
||||
" double kernel_time = (double)(end - start) * 1e-6;\n",
|
||||
"\n",
|
||||
" std::cout << \" kernel time : \" << kernel_time << \" ms\\n\";\n",
|
||||
" std::cout << \"Throughput for kernel \" << \": \";\n",
|
||||
" std::cout << std::fixed << std::setprecision(3)\n",
|
||||
" << ((double)array_size / kernel_time) / 1e6f << \" GFlops\\n\";\n",
|
||||
"\n",
|
||||
" } catch (sycl::exception const &e) {\n",
|
||||
" // Catches exceptions in the host code\n",
|
||||
" std::cout << \"Caught a SYCL host exception:\\n\" << e.what() << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Most likely the runtime couldn't find FPGA hardware!\n",
|
||||
" if (e.get_cl_code() == CL_DEVICE_NOT_FOUND) {\n",
|
||||
" std::cout << \"If you are targeting an FPGA, please ensure that your \"\n",
|
||||
" \"system has a correctly configured FPGA board.\\n\";\n",
|
||||
" std::cout << \"If you are targeting the FPGA emulator, compile with \"\n",
|
||||
" \"-DFPGA_EMULATOR.\\n\";\n",
|
||||
" }\n",
|
||||
" std::terminate();\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"int main(int argc, char *argv[]) {\n",
|
||||
" size_t array_size = 1 << 26;\n",
|
||||
"\n",
|
||||
" if (argc > 1) {\n",
|
||||
" std::string option(argv[1]);\n",
|
||||
" if (option == \"-h\" || option == \"--help\") {\n",
|
||||
" std::cout << \"Usage: \\n<executable> <data size>\\n\\nFAILED\\n\";\n",
|
||||
" return 1;\n",
|
||||
" } else {\n",
|
||||
" array_size = std::stoi(option);\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::vector<float> summands1(array_size);\n",
|
||||
" std::vector<float> summands2(array_size);\n",
|
||||
"\n",
|
||||
" std::vector<float> sum(array_size);\n",
|
||||
"\n",
|
||||
" // Initialize the two summand arrays (arrays to be added to each other) to\n",
|
||||
" // 1:N and N:1, so that the sum of all elements is N + 1\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" summands1[i] = static_cast<float>(i + 1);\n",
|
||||
" summands2[i] = static_cast<float>(array_size - i);\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::cout << \"Input Array Size: \" << array_size << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Instantiate VecAdd kernel that contains a loop that adds up the two summand arrays.\n",
|
||||
" VecAdd(summands1, summands2, sum, array_size);\n",
|
||||
"\n",
|
||||
" // Verify that the output data is the same for every unroll factor\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" if (sum[i] != summands1[i] + summands2[i]) {\n",
|
||||
" std::cout << \"FAILED: The results are incorrect\\n\";\n",
|
||||
" return 1;\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" std::cout << \"PASSED: The results are correct\\n\";\n",
|
||||
" return 0;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"__Now, you will compile the code to target the FPGA emulator.__\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! echo \"##\" $(whoami) is compiling a simple FPGA code with a loop\n",
|
||||
"! dpcpp -fintelfpga lab/loop.cpp -DFPGA_EMULATOR -o bin/loop.emu\n",
|
||||
"! bin/loop.emu"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"## Stage 2: Optimization Report Generation\n",
|
||||
"\n",
|
||||
"In this next section of the lab, you will compile the kernel using different command line options with Intel's oneAPI DPC++ compiler in order to create an optimization report. You will also be using the Jupyter Lab interface to browse and open a file, so that will be explained to you.\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"__Let's compile the code and generate an optimization report.__\n",
|
||||
"\n",
|
||||
"The commands you need to do this are shown below. (We are using the two-step method since there is a current issue showing the source code in the report with the one-step method.)\n",
|
||||
"\n",
|
||||
"```\n",
|
||||
"dpcpp -fintelfpga lab/loop.cpp -c -o bin/loop.o\n",
|
||||
"dpcpp -fintelfpga bin/loop.o -fsycl-link -Xshardware -o bin/loop.a\n",
|
||||
"```\n",
|
||||
"\n",
|
||||
"__This compilation may take approximately 2 minutes.__"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! rm -rf bin/loop.a\n",
|
||||
"! echo \"##\" $(whoami) is working on generating the report for loop.cpp lab step 2\n",
|
||||
"! dpcpp -fintelfpga lab/loop.cpp -c -o bin/loop.o\n",
|
||||
"! dpcpp -fintelfpga bin/loop.o -fsycl-link -Xshardware -o bin/loop.a\n",
|
||||
"! echo \"Compilation done.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"You may wonder if these two previous dpcpp calls can be summarized into a single one. The answer is yes, and it would be:\n",
|
||||
"```\n",
|
||||
"dpcpp -fintelfpga lab/loop.cpp -fsycl-link -Xshardware -o bin/loop.a\n",
|
||||
"```\n",
|
||||
"But then you may get a warning saying:\n",
|
||||
"```\n",
|
||||
"aoc: Warning: Cannot find dependency file \"/home/u32284/tmp/loop.d\" for source file \"/home/u32284/tmp/loop-172fb0.spv\". Source code will not be available in the HLD Reports. Ensure you ran dpcpp with the -fintelfpga flag.\n",
|
||||
"```\n",
|
||||
"Which means that you won't see the `source code` in the resulting reports. Try at your own risk."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"jupyter": {
|
||||
"source_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! echo \"##\" $(whoami) is working on generating the report for loop.cpp lab step 2\n",
|
||||
"! dpcpp -fintelfpga lab/loop.cpp -fsycl-link -Xshardware -o bin/loop.a\n",
|
||||
"! echo \"The compile is finished.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"__When you see the \"Compilation done.\" message above, an optimization report file will have been generated for our example. You will see a warning if you compile more than once. The warning can be ignored.__\n",
|
||||
"\n",
|
||||
"Now, let's examine the generated report file.\n",
|
||||
"\n",
|
||||
"Within the Jupyter Lab environment, it’s easy to navigate to the generated optimization report through the file browser on the leftmost panel. Browse to the directory `bin/loop.prj/reports/` (Double click on directories to open.)\n",
|
||||
"\n",
|
||||
"__Double-click on report.html.__ The report will open up as another tab beside the notebook tab in Jupyter Lab, as shown below.\n",
|
||||
"\n",
|
||||
"__You will need to click on \"Trust HTML\" for the report to display correctly.__\n",
|
||||
"\n",
|
||||
"<img src=\"assets/FPGA-report.png\">\n",
|
||||
"\n",
|
||||
"You've now learned how to use the first two stages of the FPGA development flow with oneAPI! You will spend most of your development time in these two stages. In the next sections of the lab, you will learn different optimization techniques."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"## Stage 3: Optimizing the code for FPGA\n",
|
||||
"\n",
|
||||
"As you may have noticed, the `Initiation Interval` is too high (`II=286`) and as a result the FPGA device would be running at 240Mz which is not ideal. To overcome those kind of issues, in this exercise we will exemplarily apply three optimizations:\n",
|
||||
"\n",
|
||||
"1. Give a hint to the compiler promising that the vectors `acc_sum`, `acc_summands1` and `acc_summands2` do not share elements (they are non-overlapping regions of memory) and therefore they do not result in loop-carried dependencies.\n",
|
||||
"2. Unroll the loop to have more pipelines processing elements of the arrays per clock cycle\n",
|
||||
"3. Replicate the kernel to better utilize the FPGA HW resources and also enabling more operations per sencod. For the sake of expediency, we will replicate the kernel but changing the unroll factor for each replica. Replication is implemented in modern C++ using templated functions and classes.\n",
|
||||
"\n",
|
||||
"In the following code, some changes are needed:\n",
|
||||
"\n",
|
||||
"1. Inspect the code cell below and make the following modifications.\n",
|
||||
" 1. STEP A: Insert in the q.single_task the intel::kernel_args_restrict C++ attribute (as in Slide 16 in 10-FPGA-Optimizations)\n",
|
||||
" 2. STEP B: Insert in the q.single_task the pragma unroll using the template argument unroll_factor (as in Slide 13) \n",
|
||||
" 3. STEP C: Add in the main() function a fith invocation to VecAdd now using unroll_factor=16 and sum_unrollx16\n",
|
||||
"2. When the modifications are complete, click run ▶ to save the code to a file.\n",
|
||||
"3. Run ▶ the cell in the __Build and check the report of the modified code__ section below the code snippet to compile and execute the code in the saved file.\n",
|
||||
"\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 2,
|
||||
"metadata": {},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Writing lab/loop_unroll.cpp\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile lab/loop_unroll.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"#include <CL/sycl.hpp>\n",
|
||||
"#include <iomanip>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"// dpc_common.hpp can be found in the dev-utilities include folder.\n",
|
||||
"// e.g., $ONEAPI_ROOT/dev-utilities//include/dpc_common.hpp\n",
|
||||
"#include \"dpc_common.hpp\"\n",
|
||||
"\n",
|
||||
"// Header locations and some DPC++ extensions changed between beta09 and beta10\n",
|
||||
"// Temporarily modify the code sample to accept either version\n",
|
||||
"#define BETA09 20200827\n",
|
||||
"#if __SYCL_COMPILER_VERSION <= BETA09\n",
|
||||
" #include <CL/sycl/intel/fpga_extensions.hpp>\n",
|
||||
" namespace INTEL = sycl::intel; // Namespace alias for backward compatibility\n",
|
||||
"#else\n",
|
||||
" #include <CL/sycl/INTEL/fpga_extensions.hpp>\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
"using namespace sycl;\n",
|
||||
"\n",
|
||||
"template <int unroll_factor> class VAdd;\n",
|
||||
"\n",
|
||||
"// This function instantiates the vector add kernel, which contains\n",
|
||||
"// a loop that adds up the two summand arrays and stores the result\n",
|
||||
"// into sum. This loop will be unrolled by the specified unroll_factor.\n",
|
||||
"template <int unroll_factor>\n",
|
||||
"void VecAdd(const std::vector<float> &summands1,\n",
|
||||
" const std::vector<float> &summands2, std::vector<float> &sum,\n",
|
||||
" size_t array_size) {\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#if defined(FPGA_EMULATOR)\n",
|
||||
" INTEL::fpga_emulator_selector device_selector;\n",
|
||||
"#else\n",
|
||||
" INTEL::fpga_selector device_selector;\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
" try {\n",
|
||||
" queue q(device_selector, dpc_common::exception_handler,\n",
|
||||
" property::queue::enable_profiling{});\n",
|
||||
"\n",
|
||||
" buffer buffer_summands1(summands1);\n",
|
||||
" buffer buffer_summands2(summands2);\n",
|
||||
" // Use verbose SYCL 1.2 syntax for the output buffer.\n",
|
||||
" // (This will become unnecessary in a future compiler version.)\n",
|
||||
" buffer<float, 1> buffer_sum(sum.data(), array_size);\n",
|
||||
"\n",
|
||||
" event e = q.submit([&](handler &h) {\n",
|
||||
" auto acc_summands1 = buffer_summands1.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_summands2 = buffer_summands2.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_sum = buffer_sum.get_access<access::mode::discard_write>(h);\n",
|
||||
"\n",
|
||||
"//This template argument to single_task allows for the correct name_mangling for all the kernels\n",
|
||||
" h.single_task<VAdd<unroll_factor>>([=]()\n",
|
||||
"//STEP A: Insert here the intel::kernel_args_restrict C++ attribute (as in Slide 16 in 10-FPGA-Optimizations)\n",
|
||||
" {\n",
|
||||
" // Unroll the loop fully or partially, depending on unroll_factor\n",
|
||||
"//STEP B: Insert here the pragma unroll using the template argument unroll_factor (as in Slide 13)\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" acc_sum[i] = acc_summands1[i] + acc_summands2[i];\n",
|
||||
" }\n",
|
||||
" });\n",
|
||||
" });\n",
|
||||
"\n",
|
||||
" double start = e.get_profiling_info<info::event_profiling::command_start>();\n",
|
||||
" double end = e.get_profiling_info<info::event_profiling::command_end>();\n",
|
||||
" // convert from nanoseconds to ms\n",
|
||||
" double kernel_time = (double)(end - start) * 1e-6;\n",
|
||||
"\n",
|
||||
" std::cout << \"unroll_factor \" << unroll_factor\n",
|
||||
" << \" kernel time : \" << kernel_time << \" ms\\n\";\n",
|
||||
" std::cout << \"Throughput for kernel with unroll_factor \" << unroll_factor\n",
|
||||
" << \": \";\n",
|
||||
" std::cout << std::fixed << std::setprecision(3)\n",
|
||||
" << ((double)array_size / kernel_time) / 1e6f << \" GFlops\\n\";\n",
|
||||
"\n",
|
||||
" } catch (sycl::exception const &e) {\n",
|
||||
" // Catches exceptions in the host code\n",
|
||||
" std::cout << \"Caught a SYCL host exception:\\n\" << e.what() << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Most likely the runtime couldn't find FPGA hardware!\n",
|
||||
" if (e.get_cl_code() == CL_DEVICE_NOT_FOUND) {\n",
|
||||
" std::cout << \"If you are targeting an FPGA, please ensure that your \"\n",
|
||||
" \"system has a correctly configured FPGA board.\\n\";\n",
|
||||
" std::cout << \"If you are targeting the FPGA emulator, compile with \"\n",
|
||||
" \"-DFPGA_EMULATOR.\\n\";\n",
|
||||
" }\n",
|
||||
" std::terminate();\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"int main(int argc, char *argv[]) {\n",
|
||||
" size_t array_size = 1 << 26;\n",
|
||||
"\n",
|
||||
" if (argc > 1) {\n",
|
||||
" std::string option(argv[1]);\n",
|
||||
" if (option == \"-h\" || option == \"--help\") {\n",
|
||||
" std::cout << \"Usage: \\n<executable> <data size>\\n\\nFAILED\\n\";\n",
|
||||
" return 1;\n",
|
||||
" } else {\n",
|
||||
" array_size = std::stoi(option);\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::vector<float> summands1(array_size);\n",
|
||||
" std::vector<float> summands2(array_size);\n",
|
||||
"\n",
|
||||
" std::vector<float> sum_unrollx1(array_size);\n",
|
||||
" std::vector<float> sum_unrollx2(array_size);\n",
|
||||
" std::vector<float> sum_unrollx4(array_size);\n",
|
||||
" std::vector<float> sum_unrollx8(array_size);\n",
|
||||
" std::vector<float> sum_unrollx16(array_size);\n",
|
||||
"\n",
|
||||
" // Initialize the two summand arrays (arrays to be added to each other) to\n",
|
||||
" // 1:N and N:1, so that the sum of all elements is N + 1\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" summands1[i] = static_cast<float>(i + 1);\n",
|
||||
" summands2[i] = static_cast<float>(array_size - i);\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::cout << \"Input Array Size: \" << array_size << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Instantiate VecAdd kernel with different unroll factors: 1, 2, 4, 8, 16\n",
|
||||
" // The VecAdd kernel contains a loop that adds up the two summand arrays.\n",
|
||||
" // This loop will be unrolled by the specified unroll factor.\n",
|
||||
" // The sum array is expected to be identical, regardless of the unroll factor.\n",
|
||||
" VecAdd<1>(summands1, summands2, sum_unrollx1, array_size);\n",
|
||||
" VecAdd<2>(summands1, summands2, sum_unrollx2, array_size);\n",
|
||||
" VecAdd<4>(summands1, summands2, sum_unrollx4, array_size);\n",
|
||||
" VecAdd<8>(summands1, summands2, sum_unrollx8, array_size);\n",
|
||||
"\n",
|
||||
"//STEP C: Add a fith invocation to VecAdd now using unroll_factor=16 and sum_unrollx16\n",
|
||||
"\n",
|
||||
" // Verify that the output data is the same for every unroll factor\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" if (sum_unrollx1[i] != summands1[i] + summands2[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx2[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx4[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx8[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx16[i]) {\n",
|
||||
" std::cout << \"FAILED: The results are incorrect\\n\";\n",
|
||||
" return 1;\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" std::cout << \"PASSED: The results are correct\\n\";\n",
|
||||
" return 0;\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Build and check the report of the modified code\n",
|
||||
"\n",
|
||||
"Select the cell below and click Run ▶ to compile and generate the report for the code that you modified above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! rm -rf lab/loop_unroll.a\n",
|
||||
"! echo \"##\" $(whoami) is working on optimizing with loop unrolling\n",
|
||||
"! dpcpp -fintelfpga lab/loop_unroll.cpp -c -o lab/loop_unroll.o\n",
|
||||
"! dpcpp -fintelfpga lab/loop_unroll.o -fsycl-link -Xshardware -o lab/loop_unroll.a\n",
|
||||
"! echo \"The compile is finished.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Browse to the directory `lab`/loop_unroll.prj/reports/ (Double click on directories to open them.)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution (Don't peak unless you have to)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": 3,
|
||||
"metadata": {
|
||||
"jupyter": {
|
||||
"source_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [
|
||||
{
|
||||
"name": "stdout",
|
||||
"output_type": "stream",
|
||||
"text": [
|
||||
"Writing solutions/loop_unroll.cpp\n"
|
||||
]
|
||||
}
|
||||
],
|
||||
"source": [
|
||||
"%%writefile solutions/loop_unroll.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"#include <CL/sycl.hpp>\n",
|
||||
"#include <iomanip>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"// dpc_common.hpp can be found in the dev-utilities include folder.\n",
|
||||
"// e.g., $ONEAPI_ROOT/dev-utilities//include/dpc_common.hpp\n",
|
||||
"#include \"dpc_common.hpp\"\n",
|
||||
"\n",
|
||||
"// Header locations and some DPC++ extensions changed between beta09 and beta10\n",
|
||||
"// Temporarily modify the code sample to accept either version\n",
|
||||
"#define BETA09 20200827\n",
|
||||
"#if __SYCL_COMPILER_VERSION <= BETA09\n",
|
||||
" #include <CL/sycl/intel/fpga_extensions.hpp>\n",
|
||||
" namespace INTEL = sycl::intel; // Namespace alias for backward compatibility\n",
|
||||
"#else\n",
|
||||
" #include <CL/sycl/INTEL/fpga_extensions.hpp>\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
"using namespace sycl;\n",
|
||||
"\n",
|
||||
"template <int unroll_factor> class VAdd;\n",
|
||||
"\n",
|
||||
"// This function instantiates the vector add kernel, which contains\n",
|
||||
"// a loop that adds up the two summand arrays and stores the result\n",
|
||||
"// into sum. This loop will be unrolled by the specified unroll_factor.\n",
|
||||
"template <int unroll_factor>\n",
|
||||
"void VecAdd(const std::vector<float> &summands1,\n",
|
||||
" const std::vector<float> &summands2, std::vector<float> &sum,\n",
|
||||
" size_t array_size) {\n",
|
||||
"\n",
|
||||
"\n",
|
||||
"#if defined(FPGA_EMULATOR)\n",
|
||||
" INTEL::fpga_emulator_selector device_selector;\n",
|
||||
"#else\n",
|
||||
" INTEL::fpga_selector device_selector;\n",
|
||||
"#endif\n",
|
||||
"\n",
|
||||
" try {\n",
|
||||
" queue q(device_selector, dpc_common::exception_handler,\n",
|
||||
" property::queue::enable_profiling{});\n",
|
||||
"\n",
|
||||
" buffer buffer_summands1(summands1);\n",
|
||||
" buffer buffer_summands2(summands2);\n",
|
||||
" // Use verbose SYCL 1.2 syntax for the output buffer.\n",
|
||||
" // (This will become unnecessary in a future compiler version.)\n",
|
||||
" buffer<float, 1> buffer_sum(sum.data(), array_size);\n",
|
||||
"\n",
|
||||
" event e = q.submit([&](handler &h) {\n",
|
||||
" auto acc_summands1 = buffer_summands1.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_summands2 = buffer_summands2.get_access<access::mode::read>(h);\n",
|
||||
" auto acc_sum = buffer_sum.get_access<access::mode::discard_write>(h);\n",
|
||||
"\n",
|
||||
" h.single_task<VAdd<unroll_factor>>([=]()\n",
|
||||
" [[intel::kernel_args_restrict]] {\n",
|
||||
" // Unroll the loop fully or partially, depending on unroll_factor\n",
|
||||
" #pragma unroll unroll_factor\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" acc_sum[i] = acc_summands1[i] + acc_summands2[i];\n",
|
||||
" }\n",
|
||||
" });\n",
|
||||
" });\n",
|
||||
"\n",
|
||||
" double start = e.get_profiling_info<info::event_profiling::command_start>();\n",
|
||||
" double end = e.get_profiling_info<info::event_profiling::command_end>();\n",
|
||||
" // convert from nanoseconds to ms\n",
|
||||
" double kernel_time = (double)(end - start) * 1e-6;\n",
|
||||
"\n",
|
||||
" std::cout << \"unroll_factor \" << unroll_factor\n",
|
||||
" << \" kernel time : \" << kernel_time << \" ms\\n\";\n",
|
||||
" std::cout << \"Throughput for kernel with unroll_factor \" << unroll_factor\n",
|
||||
" << \": \";\n",
|
||||
" std::cout << std::fixed << std::setprecision(3)\n",
|
||||
" << ((double)array_size / kernel_time) / 1e6f << \" GFlops\\n\";\n",
|
||||
"\n",
|
||||
" } catch (sycl::exception const &e) {\n",
|
||||
" // Catches exceptions in the host code\n",
|
||||
" std::cout << \"Caught a SYCL host exception:\\n\" << e.what() << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Most likely the runtime couldn't find FPGA hardware!\n",
|
||||
" if (e.get_cl_code() == CL_DEVICE_NOT_FOUND) {\n",
|
||||
" std::cout << \"If you are targeting an FPGA, please ensure that your \"\n",
|
||||
" \"system has a correctly configured FPGA board.\\n\";\n",
|
||||
" std::cout << \"If you are targeting the FPGA emulator, compile with \"\n",
|
||||
" \"-DFPGA_EMULATOR.\\n\";\n",
|
||||
" }\n",
|
||||
" std::terminate();\n",
|
||||
" }\n",
|
||||
"}\n",
|
||||
"\n",
|
||||
"int main(int argc, char *argv[]) {\n",
|
||||
" size_t array_size = 1 << 26;\n",
|
||||
"\n",
|
||||
" if (argc > 1) {\n",
|
||||
" std::string option(argv[1]);\n",
|
||||
" if (option == \"-h\" || option == \"--help\") {\n",
|
||||
" std::cout << \"Usage: \\n<executable> <data size>\\n\\nFAILED\\n\";\n",
|
||||
" return 1;\n",
|
||||
" } else {\n",
|
||||
" array_size = std::stoi(option);\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::vector<float> summands1(array_size);\n",
|
||||
" std::vector<float> summands2(array_size);\n",
|
||||
"\n",
|
||||
" std::vector<float> sum_unrollx1(array_size);\n",
|
||||
" std::vector<float> sum_unrollx2(array_size);\n",
|
||||
" std::vector<float> sum_unrollx4(array_size);\n",
|
||||
" std::vector<float> sum_unrollx8(array_size);\n",
|
||||
" std::vector<float> sum_unrollx16(array_size);\n",
|
||||
"\n",
|
||||
" // Initialize the two summand arrays (arrays to be added to each other) to\n",
|
||||
" // 1:N and N:1, so that the sum of all elements is N + 1\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" summands1[i] = static_cast<float>(i + 1);\n",
|
||||
" summands2[i] = static_cast<float>(array_size - i);\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" std::cout << \"Input Array Size: \" << array_size << \"\\n\";\n",
|
||||
"\n",
|
||||
" // Instantiate VecAdd kernel with different unroll factors: 1, 2, 4, 8, 16\n",
|
||||
" // The VecAdd kernel contains a loop that adds up the two summand arrays.\n",
|
||||
" // This loop will be unrolled by the specified unroll factor.\n",
|
||||
" // The sum array is expected to be identical, regardless of the unroll factor.\n",
|
||||
" VecAdd<1>(summands1, summands2, sum_unrollx1, array_size);\n",
|
||||
" VecAdd<2>(summands1, summands2, sum_unrollx2, array_size);\n",
|
||||
" VecAdd<4>(summands1, summands2, sum_unrollx4, array_size);\n",
|
||||
" VecAdd<8>(summands1, summands2, sum_unrollx8, array_size);\n",
|
||||
" VecAdd<16>(summands1, summands2, sum_unrollx16, array_size);\n",
|
||||
"\n",
|
||||
" // Verify that the output data is the same for every unroll factor\n",
|
||||
" for (size_t i = 0; i < array_size; i++) {\n",
|
||||
" if (sum_unrollx1[i] != summands1[i] + summands2[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx2[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx4[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx8[i] ||\n",
|
||||
" sum_unrollx1[i] != sum_unrollx16[i]) {\n",
|
||||
" std::cout << \"FAILED: The results are incorrect\\n\";\n",
|
||||
" return 1;\n",
|
||||
" }\n",
|
||||
" }\n",
|
||||
" std::cout << \"PASSED: The results are correct\\n\";\n",
|
||||
" return 0;\n",
|
||||
"}\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Generate the report:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! rm -rf solutions/loop_unroll.a\n",
|
||||
"! echo \"##\" $(whoami) is working on optimizing with loop unrolling\n",
|
||||
"! dpcpp -fintelfpga solutions/loop_unroll.cpp -c -o solutions/loop_unroll.o\n",
|
||||
"! dpcpp -fintelfpga solutions/loop_unroll.o -fsycl-link -Xshardware -o solutions/loop_unroll.a\n",
|
||||
"! echo \"The compile is finished.\""
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Browse to the directory `solutions`/loop_unroll.prj/reports/ (Double click on diretories to push down into them.)\n",
|
||||
"\n",
|
||||
"The report should now look like:\n",
|
||||
"\n",
|
||||
"<img src=\"assets/FPGA-unroll-report.png\">\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Feel free to compile it as we did in the first hands-on session and you can expect a similar output running on an Intel Arria10 FPGA that is available in DevCloud:\n",
|
||||
"```\n",
|
||||
"Input Array Size: 67108864\n",
|
||||
"unroll_factor 1 kernel time : 242.849 ms\n",
|
||||
"Throughput for kernel with unroll_factor 1: 0.276 GFlops\n",
|
||||
"unroll_factor 2 kernel time : 122.319 ms\n",
|
||||
"Throughput for kernel with unroll_factor 2: 0.549 GFlops\n",
|
||||
"unroll_factor 4 kernel time : 63.950 ms\n",
|
||||
"Throughput for kernel with unroll_factor 4: 1.049 GFlops\n",
|
||||
"unroll_factor 8 kernel time : 39.567 ms\n",
|
||||
"Throughput for kernel with unroll_factor 8: 1.696 GFlops\n",
|
||||
"unroll_factor 16 kernel time : 37.500 ms\n",
|
||||
"Throughput for kernel with unroll_factor 16: 1.790 GFlops\n",
|
||||
"PASSED: The results are correct\n",
|
||||
"```\n"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"## References to Learn More\n",
|
||||
"\n",
|
||||
"Please refer to the following resources to learn more. This is a great thing to do if you have extra time during the lab!\n",
|
||||
"\n",
|
||||
"#### FPGA Specific Documentation\n",
|
||||
"\n",
|
||||
"* [Website hub for using FPGAs with oneAPI](https://software.intel.com/content/www/us/en/develop/tools/oneapi/components/fpga.html)\n",
|
||||
"* [Intel® oneAPI Programming Guide](https://software.intel.com/content/www/us/en/develop/download/intel-oneapi-programming-guide.html)\n",
|
||||
"* [Intel® oneAPI DPC++ FPGA Optimization Guide](https://software.intel.com/content/www/us/en/develop/download/oneapi-fpga-optimization-guide.html)\n",
|
||||
"* [oneAPI Samples on GitHub](https://github.com/oneapi-src/oneAPI-samples)\n",
|
||||
"\n",
|
||||
"#### Intel® oneAPI Toolkit documentation\n",
|
||||
"* [Intel® oneAPI main page](https://software.intel.com/oneapi \"oneAPI main page\")\n",
|
||||
"* [Intel® DevCloud Signup](https://software.intel.com/en-us/devcloud/oneapi \"Intel DevCloud\") Sign up here if you do not have an account.\n",
|
||||
"* [Intel® DevCloud Connect](https://devcloud.intel.com/datacenter/connect) Login to the DevCloud here.\n",
|
||||
"* [oneAPI Specification elements](https://www.oneapi.com/spec/)\n",
|
||||
"* [DPC++ reference](https://docs.oneapi.com/versions/latest/dpcpp/)\n",
|
||||
"\n",
|
||||
"#### SYCL \n",
|
||||
"* [SYCL* Specification (for version 1.2.1)](https://www.khronos.org/registry/SYCL/specs/sycl-1.2.1.pdf)\n",
|
||||
"\n",
|
||||
"#### Modern C++\n",
|
||||
"* [CPPReference](https://en.cppreference.com/w/)\n",
|
||||
"* [CPlusPlus](http://www.cplusplus.com/)"
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3.7 (Intel® oneAPI)",
|
||||
"language": "python",
|
||||
"name": "c009-intel_distribution_of_python_3_oneapi-beta05-python"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.7"
|
||||
},
|
||||
"toc": {
|
||||
"base_numbering": 1,
|
||||
"nav_menu": {},
|
||||
"number_sections": true,
|
||||
"sideBar": true,
|
||||
"skip_h1_title": false,
|
||||
"title_cell": "Table of Contents",
|
||||
"title_sidebar": "Contents",
|
||||
"toc_cell": false,
|
||||
"toc_position": {
|
||||
"height": "525.6px",
|
||||
"left": "28px",
|
||||
"top": "137.8px",
|
||||
"width": "301.109px"
|
||||
},
|
||||
"toc_section_display": true,
|
||||
"toc_window_display": true
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
@@ -0,0 +1,442 @@
|
||||
{
|
||||
"cells": [
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"# Introduction to oneDPL"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"##### Sections\n",
|
||||
"- _Code_: [Hello, PSTL!](#Hello,-PSTL!)\n",
|
||||
"- _Code_: [Fancy Iterators](#Fancy-iterators)\n",
|
||||
"- _Code_: [Monte Carlo Example](#Monte-Carlo-Pi)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"# Hello, PSTL!\n",
|
||||
"\n",
|
||||
"To begin, we'll build and run a very simple C++ application that invokes the classic STL algorithm ``sort`` on an input sequence of random integers.\n",
|
||||
"\n",
|
||||
"To make this exercise more interesting we parallelize our sort at a high-level. To do that, we simply add a parallel execution policy and take the algorithm for a second run. Adding a parallel execution policy is as easy as inserting `std::execution::par` as a first parameter. This tells the compiler and runtime that it's safe to execute iterations in parallel on multiple threads of execution. It's a hint by the user but not a mandatory requirement to run any optimizations for the runtime. A high-quality implementation like Parallel STL with TBB as a backend could benefit by splitting the sort into finer grained tasks. Those can be executed by TBB's scheduler in a multithreaded fashion. Of course that adds some overhead, such as maintaining a thread pool or synchronize the tasks. So it's not advised to add a parallel execution policy to each and every algorithm. It's a user's (Yes that's you) responsibility to ensure a parallel optimization hint is legal and beneficial.\n",
|
||||
"\n",
|
||||
"Consequently, in our simple example we time both runs so that we can compare them. Please note that intentionally any warm-up for the parallel execution is skipped.\n",
|
||||
"\n",
|
||||
"Inspect the code below - there are no modifications necessary. Run the first cell to create the file, then run the cell below it to compile and execute the code.\n",
|
||||
"1. Inspect the code cell below, then click run ▶ to save the code to a file\n",
|
||||
"2. Run ▶ the cell in the __Build and Run__ section below the code snippet to compile and execute the code in the saved file\n",
|
||||
"\n",
|
||||
"What are your expectations regarding the speedup? We're likely running on an system with two Intel Xeon processor with 6 cores each (12 hardware threads) in the current DevCloud configuration, as of Sept'20. \n",
|
||||
"\n",
|
||||
"What happens if we decrease the size of the input sequence to let's say 50? "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile lab/sort.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) 2020 Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"\n",
|
||||
"#include <chrono>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"#include <random>\n",
|
||||
"\n",
|
||||
"#include <oneapi/dpl/execution>\n",
|
||||
"#include <oneapi/dpl/algorithm>\n",
|
||||
"\n",
|
||||
"int main() {\n",
|
||||
" std::default_random_engine e1(0);\n",
|
||||
" std::uniform_int_distribution<int> d(0, 5000);\n",
|
||||
"\n",
|
||||
" // initialize input vector with random numbers\n",
|
||||
" std::vector<int> data(5000000);\n",
|
||||
" for(auto& i:data) {\n",
|
||||
" i = d(e1);\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" std::vector<int> input(data);\n",
|
||||
" std::cout << \"Running sequentially:\\n\";\n",
|
||||
" auto st0 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::sort(input.begin(), input.end());\n",
|
||||
" auto st1 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::cout << \"Serial time = \" << 1e-9 * (st1-st0).count() << \" seconds\\n\";\n",
|
||||
" }\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" std::vector<int> input(data);\n",
|
||||
" std::cout << \"\\nRunning in parallel:\\n\";\n",
|
||||
" auto pt0 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::sort(std::execution::par, input.begin(), input.end());\n",
|
||||
" auto pt1 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::cout << \"Parallel time = \" << 1e-9 * (pt1-pt0).count() << \" seconds\\n\";\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" return 0;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile scripts/run_sort.sh\n",
|
||||
"#!/bin/bash\n",
|
||||
"#==========================================\n",
|
||||
"# Copyright (c) 2020 Intel Corporation\n",
|
||||
"#\n",
|
||||
"# SPDX-License-Identifier: Apache-2.0\n",
|
||||
"#==========================================\n",
|
||||
"\n",
|
||||
"source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1\n",
|
||||
"/bin/echo \"##\" $(whoami) is compiling oneDPL example\n",
|
||||
"rm -rf bin/sort\n",
|
||||
"dpcpp lab/sort.cpp -o bin/sort -tbb\n",
|
||||
"bin/sort"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Select the cell below and click Run ▶ to compile and execute the code above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! chmod 755 q; chmod 755 scripts/run_sort.sh; if [ -x \"$(command -v qsub)\" ]; then ./q scripts/run_sort.sh; else ./scripts/run_sort.sh; fi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"# Fancy iterators\n",
|
||||
"\n",
|
||||
"Next we want to demonstrate how the applicability of classic STL algorithms can be extended by special iterators, so called fancy iterators. Imagine the following problem: A logic sequence of pairs (key and data elements) has to be sorted according to its key element. The elements are stored in two containers, one vector that holds the keys and another vector that holds the data elements.\n",
|
||||
"\n",
|
||||
"oneDPL as part of Intel oneAPI supports fancy iterators that can be used with the C++17 parallel algorithms. For example a `counting_iterator` is provided that represents a linear increasing sequence. With one big advantage compared to a classic vector that holds the data. This can actually save memory bandwidth. Because the sequence does not need a representation in memory.\n",
|
||||
"\n",
|
||||
"In our example we use a `zip_iterator` that can be used to tie two or even multiple sequences. The resulting iterator can now be used as an input or output of STL algorithm. Like in the following example.\n",
|
||||
"\n",
|
||||
"Complete the instructions in the following code template to implement a sort by key using a zip iterator."
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile lab/fancy_sort.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) 2020 Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"\n",
|
||||
"#include <chrono>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"#include <oneapi/dpl/iterator>\n",
|
||||
"#include <oneapi/dpl/execution>\n",
|
||||
"#include <oneapi/dpl/algorithm>\n",
|
||||
"\n",
|
||||
"int main() {\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" using oneapi::dpl::make_zip_iterator;\n",
|
||||
" std::vector<int> keys = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};\n",
|
||||
" std::vector<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n",
|
||||
" // *** Step 1: create a zip iterator with iterator to begin of keys and data as input.\n",
|
||||
" auto zip_in = data.begin();\n",
|
||||
" const size_t n = std::distance(keys.begin(), keys.end()); \n",
|
||||
"\n",
|
||||
" std::cout << \"\\nRunning in parallel:\\n\";\n",
|
||||
" auto pt0 = std::chrono::high_resolution_clock::now();\n",
|
||||
" // *** Step 2: Replace left and right side of comparison with get<>() to extract and compare key\n",
|
||||
" auto custom_func = [](auto l, auto r){ using std::get; return l < r;};\n",
|
||||
" // *** Step 3: Replace all instances of iterator data.begin() with your zip iterator\n",
|
||||
" std::sort(std::execution::par, zip_in, zip_in + n, custom_func);\n",
|
||||
" auto pt1 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::cout << \"Parallel time = \" << 1e-9 * (pt1-pt0).count() << \" seconds\\n\";\n",
|
||||
" \n",
|
||||
" std::cout << \"Sorted keys:\" ;\n",
|
||||
" for(auto i:keys)\n",
|
||||
" std::cout << i << \" \";\n",
|
||||
" std::cout << \"\\n\" << \"Sorted data:\";\n",
|
||||
" for(auto i:data)\n",
|
||||
" std::cout << i << \" \";\n",
|
||||
" std::cout << \"\\n\";\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" return 0;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### Solution (Don't peak unless you have to)"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {
|
||||
"jupyter": {
|
||||
"source_hidden": true
|
||||
}
|
||||
},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile lab/fancy_sort.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) 2020 Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"\n",
|
||||
"#include <chrono>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"#include <oneapi/dpl/iterator>\n",
|
||||
"#include <oneapi/dpl/execution>\n",
|
||||
"#include <oneapi/dpl/algorithm>\n",
|
||||
"\n",
|
||||
"int main() {\n",
|
||||
"\n",
|
||||
" {\n",
|
||||
" using oneapi::dpl::make_zip_iterator;\n",
|
||||
" std::vector<int> keys = { 0, 1, 0, 1, 0, 1, 0, 1, 0, 1};\n",
|
||||
" std::vector<int> data = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9};\n",
|
||||
" auto zip_in = make_zip_iterator(keys.begin(), data.begin());\n",
|
||||
" const size_t n = std::distance(keys.begin(), keys.end()); \n",
|
||||
" auto custom_func = [](auto l, auto r){ using std::get; return get<0>(l) < get<0>(r);};\n",
|
||||
" \n",
|
||||
" std::cout << \"\\nRunning in parallel:\\n\";\n",
|
||||
" auto pt0 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::sort(std::execution::par, zip_in, zip_in + n, custom_func);\n",
|
||||
" auto pt1 = std::chrono::high_resolution_clock::now();\n",
|
||||
" std::cout << \"Parallel time = \" << 1e-9 * (pt1-pt0).count() << \" seconds\\n\";\n",
|
||||
" \n",
|
||||
" std::cout << \"Sorted keys:\" ;\n",
|
||||
" for(auto i:keys)\n",
|
||||
" std::cout << i << \" \";\n",
|
||||
" std::cout << \"\\n\" << \"Sorted data:\";\n",
|
||||
" for(auto i:data)\n",
|
||||
" std::cout << i << \" \";\n",
|
||||
" std::cout << \"\\n\";\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" return 0;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile scripts/run_fancy_sort.sh\n",
|
||||
"#!/bin/bash\n",
|
||||
"#==========================================\n",
|
||||
"# Copyright (c) 2020 Intel Corporation\n",
|
||||
"#\n",
|
||||
"# SPDX-License-Identifier: Apache-2.0\n",
|
||||
"#==========================================\n",
|
||||
"\n",
|
||||
"source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1\n",
|
||||
"/bin/echo \"##\" $(whoami) is compiling oneDPL example\n",
|
||||
"rm -rf bin/fancy_sort\n",
|
||||
"dpcpp lab/fancy_sort.cpp -o bin/fancy_sort -tbb\n",
|
||||
"bin/fancy_sort"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Select the cell below and click Run ▶ to compile and execute the code above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! chmod 755 q; chmod 755 scripts/run_fancy_sort.sh; if [ -x \"$(command -v qsub)\" ]; then ./q scripts/run_fancy_sort.sh; else ./scripts/run_fancy_sort.sh; fi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"***\n",
|
||||
"# Monte Carlo Pi\n",
|
||||
"\n",
|
||||
"Let's recreate the Direct programming DPC++ example using the DPC++ library (oneDPL). We'll use the algorithm ``transform_reduce``, which can for example be used to parallelize the computation of a dot product, by applying a parallel execution policy. Well or the monte carlo simulation computing PI. "
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile lab/monte_carlo_pi.cpp\n",
|
||||
"//==============================================================\n",
|
||||
"// Copyright (c) 2020 Intel Corporation\n",
|
||||
"//\n",
|
||||
"// SPDX-License-Identifier: Apache-2.0\n",
|
||||
"// =============================================================\n",
|
||||
"\n",
|
||||
"#include <chrono>\n",
|
||||
"#include <iostream>\n",
|
||||
"#include <vector>\n",
|
||||
"\n",
|
||||
"#include <CL/sycl.hpp>\n",
|
||||
"\n",
|
||||
"#include <oneapi/dpl/random>\n",
|
||||
"\n",
|
||||
"#include <oneapi/dpl/iterator>\n",
|
||||
"#include <oneapi/dpl/execution>\n",
|
||||
"#include <oneapi/dpl/algorithm>\n",
|
||||
"\n",
|
||||
"#define N 500\n",
|
||||
"#define LOCAL_N 1000\n",
|
||||
"\n",
|
||||
"#define SEED 667\n",
|
||||
"#define PI 3.1415926535897932384626433832795\n",
|
||||
"\n",
|
||||
"int main() {\n",
|
||||
" \n",
|
||||
" using oneapi::dpl::counting_iterator;\n",
|
||||
" double estimated_pi = 3.14;\n",
|
||||
" {\n",
|
||||
" sycl::queue q; //(sycl::gpu_selector{});\n",
|
||||
" auto policy = oneapi::dpl::execution::make_device_policy(q);\n",
|
||||
" \n",
|
||||
" auto sum = transform_reduce( policy, counting_iterator<int>(0), counting_iterator<int>(N), 0, std::plus<float>{}\n",
|
||||
" , [=](auto n){\n",
|
||||
" float local_sum = 0.0f;\n",
|
||||
" // Get random coords\n",
|
||||
" oneapi::std::minstd_rand engine(SEED, n);\n",
|
||||
" oneapi::std::uniform_real_distribution<float> distr(-1.0f,1.0f);\n",
|
||||
" for(int i = 0; i < LOCAL_N; ++i) {\n",
|
||||
" float x = distr(engine);\n",
|
||||
" float y = distr(engine);\n",
|
||||
" auto hypotenuse_sqr = x * x + y * y;\n",
|
||||
" if (hypotenuse_sqr <= 1.0)\n",
|
||||
" local_sum += 1.0;\n",
|
||||
" }\n",
|
||||
" return local_sum / (float)LOCAL_N;\n",
|
||||
" });\n",
|
||||
"\n",
|
||||
" estimated_pi = 4.0 * (float)sum / N;\n",
|
||||
" }\n",
|
||||
" \n",
|
||||
" // Printing Results\n",
|
||||
" std::cout << \"Estimated value of Pi = \" << estimated_pi << std::endl;\n",
|
||||
" std::cout << \"Exact value of Pi = \" << PI << std::endl;\n",
|
||||
" std::cout << \"Absolute error = \" << fabs( PI-estimated_pi ) << std::endl;\n",
|
||||
"\n",
|
||||
" return 0;\n",
|
||||
"}"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"%%writefile scripts/run_monte_carlo_pi.sh\n",
|
||||
"#!/bin/bash\n",
|
||||
"#==========================================\n",
|
||||
"# Copyright (c) 2020 Intel Corporation\n",
|
||||
"#\n",
|
||||
"# SPDX-License-Identifier: Apache-2.0\n",
|
||||
"#==========================================\n",
|
||||
"\n",
|
||||
"source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1\n",
|
||||
"/bin/echo \"##\" $(whoami) is compiling oneDPL example\n",
|
||||
"rm -rf bin/monte_carlo_pi\n",
|
||||
"dpcpp lab/monte_carlo_pi.cpp -o bin/monte_carlo_pi -tbb\n",
|
||||
"bin/monte_carlo_pi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"Select the cell below and click Run ▶ to compile and execute the code above:"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "code",
|
||||
"execution_count": null,
|
||||
"metadata": {},
|
||||
"outputs": [],
|
||||
"source": [
|
||||
"! chmod 755 q; chmod 755 scripts/run_monte_carlo_pi.sh; if [ -x \"$(command -v qsub)\" ]; then ./q scripts/run_monte_carlo_pi.sh; else ./scripts/run_monte_carlo_pi.sh; fi"
|
||||
]
|
||||
},
|
||||
{
|
||||
"cell_type": "markdown",
|
||||
"metadata": {},
|
||||
"source": [
|
||||
"### "
|
||||
]
|
||||
}
|
||||
],
|
||||
"metadata": {
|
||||
"kernelspec": {
|
||||
"display_name": "Python 3.7 (Intel® oneAPI)",
|
||||
"language": "python",
|
||||
"name": "c009-intel_distribution_of_python_3_oneapi-beta05-python"
|
||||
},
|
||||
"language_info": {
|
||||
"codemirror_mode": {
|
||||
"name": "ipython",
|
||||
"version": 3
|
||||
},
|
||||
"file_extension": ".py",
|
||||
"mimetype": "text/x-python",
|
||||
"name": "python",
|
||||
"nbconvert_exporter": "python",
|
||||
"pygments_lexer": "ipython3",
|
||||
"version": "3.7.7"
|
||||
}
|
||||
},
|
||||
"nbformat": 4,
|
||||
"nbformat_minor": 4
|
||||
}
|
||||
|
After Width: | Height: | Size: 438 KiB |
|
After Width: | Height: | Size: 406 KiB |
|
After Width: | Height: | Size: 73 KiB |
|
After Width: | Height: | Size: 113 KiB |
|
After Width: | Height: | Size: 84 KiB |
|
After Width: | Height: | Size: 164 KiB |
|
After Width: | Height: | Size: 81 KiB |
|
After Width: | Height: | Size: 29 KiB |
@@ -0,0 +1 @@
|
||||
bin directory needed for notebook
|
||||
@@ -0,0 +1,149 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <exception>
|
||||
#include <iostream>
|
||||
#include <numeric>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
|
||||
namespace common {
|
||||
|
||||
// this exception handler with catch async exceptions
|
||||
static auto exception_handler = [](cl::sycl::exception_list eList) {
|
||||
for (std::exception_ptr const &e : eList) {
|
||||
try {
|
||||
std::rethrow_exception(e);
|
||||
} catch (std::exception const &e) {
|
||||
#if _DEBUG
|
||||
std::cout << "Failure" << std::endl;
|
||||
#endif
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename ArrayType>
|
||||
void print_array(const char* text, const ArrayType& array) {
|
||||
std::cout << text;
|
||||
for (const auto& s : array) std::cout << s << ' ';
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
void print_array(const char* text, const float * array, int array_size) {
|
||||
std::cout << text;
|
||||
for (int i=0; i<array_size; ++i) std::cout << array[i] << ' ';
|
||||
std::cout << "\n";
|
||||
}
|
||||
|
||||
template<typename ArrayType>
|
||||
void init_input_arrays(ArrayType &a_array, ArrayType &b_array) {
|
||||
std::iota(a_array.begin(), a_array.end(), 0);
|
||||
std::iota(b_array.begin(), b_array.end(), 0);
|
||||
}
|
||||
|
||||
template<typename ArrayType>
|
||||
void validate_results(float alpha, const ArrayType& a_array, const ArrayType& b_array,
|
||||
const ArrayType& c_sycl, const ArrayType& c_tbb) {
|
||||
// Create gold standard / serial result
|
||||
ArrayType c_gold;
|
||||
|
||||
for (size_t i = 0; i < a_array.size(); ++i)
|
||||
c_gold[i] = a_array[i] + alpha * b_array[i];
|
||||
|
||||
// Compare golden triad with heterogeneous triad
|
||||
if (!std::equal(std::begin(c_sycl), std::end(c_sycl), std::begin(c_gold)))
|
||||
std::cout << "SYCL triad error.\n";
|
||||
else
|
||||
std::cout << "SYCL triad correct.\n";
|
||||
|
||||
// Compare golden triad with TBB triad
|
||||
if (!std::equal(std::begin(c_tbb), end(c_tbb),
|
||||
std::begin(c_gold)))
|
||||
std::cout << "TBB triad error.\n";
|
||||
else
|
||||
std::cout << "TBB triad correct.\n";
|
||||
}
|
||||
|
||||
template<typename ArrayType>
|
||||
void validate_hetero_results(float ratio, float alpha_sycl, float alpha_tbb, const ArrayType& a_array,
|
||||
const ArrayType& b_array, const ArrayType& c_array) {
|
||||
|
||||
std::size_t ratio_switch_pt = static_cast<std::size_t>(std::ceil(c_array.size() * ratio));
|
||||
|
||||
// Create gold standard / serial result
|
||||
ArrayType c_gold;
|
||||
for (size_t i = 0; i < ratio_switch_pt; ++i)
|
||||
c_gold[i] = a_array[i] + alpha_sycl * b_array[i];
|
||||
for (size_t i = ratio_switch_pt; i < c_array.size(); ++i)
|
||||
c_gold[i] = a_array[i] + alpha_tbb * b_array[i];
|
||||
|
||||
// Compare golden triad with heterogeneous triad
|
||||
if (!std::equal(std::begin(c_array), std::end(c_array), std::begin(c_gold)))
|
||||
std::cout << "Hetero triad error.\n";
|
||||
else
|
||||
std::cout << "Hetero triad correct.\n";
|
||||
}
|
||||
|
||||
void validate_usm_results(float ratio, float alpha_sycl, float alpha_tbb, const float* a_array,
|
||||
const float* b_array, const float* c_array, int array_size) {
|
||||
|
||||
std::size_t ratio_switch_pt = static_cast<std::size_t>(std::ceil(array_size * ratio));
|
||||
|
||||
// Create gold standard / serial result
|
||||
float* c_gold=new float[array_size];
|
||||
for (size_t i = 0; i < ratio_switch_pt; ++i)
|
||||
c_gold[i] = a_array[i] + alpha_sycl * b_array[i];
|
||||
for (size_t i = ratio_switch_pt; i < array_size; ++i)
|
||||
c_gold[i] = a_array[i] + alpha_tbb * b_array[i];
|
||||
|
||||
// Compare golden triad with heterogeneous triad
|
||||
if (!std::equal(c_array, c_array+array_size, c_gold))
|
||||
std::cout << "Hetero triad error.\n";
|
||||
else
|
||||
std::cout << "Hetero triad correct.\n";
|
||||
delete[] c_gold;
|
||||
}
|
||||
|
||||
|
||||
template<typename ArrayType>
|
||||
void print_results(float alpha, const ArrayType& a_array, const ArrayType& b_array,
|
||||
const ArrayType& c_sycl, const ArrayType& c_tbb) {
|
||||
print_array("input array a_array: ", a_array);
|
||||
print_array("input array b_array: ", b_array);
|
||||
std::cout << "alpha: " << alpha << "\n";
|
||||
print_array("output array c using SYCL on GPU: ", c_sycl);
|
||||
print_array("output array c using TBB on CPU: ", c_tbb);
|
||||
}
|
||||
|
||||
template<typename ArrayType>
|
||||
void print_hetero_results(float ratio, float alpha_sycl, float alpha_tbb, const ArrayType& a_array,
|
||||
const ArrayType& b_array, const ArrayType& c_array) {
|
||||
print_array("input array a_array: ", a_array);
|
||||
print_array("input array b_array: ", b_array);
|
||||
std::cout << "ratio: " << ratio << "\n";
|
||||
std::cout << "switch_index: " << static_cast<std::size_t>(std::ceil(c_array.size() * ratio)) << "\n";
|
||||
std::cout << "alpha_sycl: " << alpha_sycl << "\n";
|
||||
std::cout << "alpha_tbb: " << alpha_tbb << "\n";
|
||||
print_array("output array c_array: ", c_array);
|
||||
}
|
||||
|
||||
void print_usm_results(float ratio, float alpha_sycl, float alpha_tbb, const float *a_array,
|
||||
const float *b_array, const float *c_array, int array_size) {
|
||||
print_array("input array a_array: ", a_array, array_size);
|
||||
print_array("input array b_array: ", b_array, array_size);
|
||||
std::cout << "ratio: " << ratio << "\n";
|
||||
std::cout << "switch_index: " << static_cast<std::size_t>(std::ceil(array_size * ratio)) << "\n";
|
||||
std::cout << "alpha_sycl: " << alpha_sycl << "\n";
|
||||
std::cout << "alpha_tbb: " << alpha_tbb << "\n";
|
||||
print_array("output array c_tbb: ", c_array, array_size);
|
||||
}
|
||||
|
||||
}; // namespace common
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_HPP
|
||||
#define _GAMMA_UTILS_HPP
|
||||
|
||||
#include "utils/Img.hpp"
|
||||
#include "utils/ImgAlgorithm.hpp"
|
||||
#include "utils/ImgFormat.hpp"
|
||||
#include "utils/ImgPixel.hpp"
|
||||
|
||||
#include "utils/Other.hpp"
|
||||
|
||||
#endif // _GAMMA_UTILS_HPP
|
||||
@@ -0,0 +1,204 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_IMG_HPP
|
||||
#define _GAMMA_UTILS_IMG_HPP
|
||||
|
||||
#include "ImgPixel.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// Image class definition
|
||||
template <typename Format>
|
||||
class Img {
|
||||
private:
|
||||
Format _format;
|
||||
std::int32_t _width;
|
||||
std::int32_t _height;
|
||||
std::vector<ImgPixel> _pixels;
|
||||
|
||||
using Iterator = std::vector<ImgPixel>::iterator;
|
||||
using ConstIterator = std::vector<ImgPixel>::const_iterator;
|
||||
|
||||
public:
|
||||
/////////////////////
|
||||
// SPECIAL METHODS //
|
||||
/////////////////////
|
||||
|
||||
Img(std::int32_t width, std::int32_t height);
|
||||
|
||||
void reset(std::int32_t width, std::int32_t height);
|
||||
|
||||
///////////////
|
||||
// ITERATORS //
|
||||
///////////////
|
||||
|
||||
Iterator begin() noexcept;
|
||||
Iterator end() noexcept;
|
||||
ConstIterator begin() const noexcept;
|
||||
ConstIterator end() const noexcept;
|
||||
ConstIterator cbegin() const noexcept;
|
||||
ConstIterator cend() const noexcept;
|
||||
|
||||
/////////////
|
||||
// GETTERS //
|
||||
/////////////
|
||||
|
||||
std::int32_t width() const noexcept;
|
||||
std::int32_t height() const noexcept;
|
||||
|
||||
ImgPixel const* data() const noexcept;
|
||||
ImgPixel* data() noexcept;
|
||||
|
||||
///////////////////
|
||||
// FUNCTIONALITY //
|
||||
///////////////////
|
||||
|
||||
void write(std::string const& filename) const;
|
||||
|
||||
template <typename Functor>
|
||||
void fill(Functor f);
|
||||
void fill(ImgPixel pixel);
|
||||
void fill(ImgPixel pixel, std::int32_t row, std::int32_t col);
|
||||
};
|
||||
|
||||
///////////////////////////////////////////////
|
||||
// IMG CLASS IMPLEMENTATION: SPECIAL METHODS //
|
||||
///////////////////////////////////////////////
|
||||
|
||||
template <typename Format>
|
||||
Img<Format>::Img(std::int32_t width, std::int32_t height)
|
||||
: _format(width, height) {
|
||||
_pixels.resize(width * height);
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
void Img<Format>::reset(std::int32_t width, std::int32_t height) {
|
||||
_pixels.resize(width * height);
|
||||
|
||||
_width = width;
|
||||
_height = height;
|
||||
|
||||
_format.reset(width, height);
|
||||
}
|
||||
|
||||
/////////////////////////////////////////
|
||||
// IMG CLASS IMPLEMENTATION: ITERATORS //
|
||||
/////////////////////////////////////////
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::Iterator Img<Format>::begin() noexcept {
|
||||
return _pixels.begin();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::Iterator Img<Format>::end() noexcept {
|
||||
return _pixels.end();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::ConstIterator Img<Format>::begin() const noexcept {
|
||||
return _pixels.begin();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::ConstIterator Img<Format>::end() const noexcept {
|
||||
return _pixels.end();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::ConstIterator Img<Format>::cbegin() const noexcept {
|
||||
return _pixels.begin();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
typename Img<Format>::ConstIterator Img<Format>::cend() const noexcept {
|
||||
return _pixels.end();
|
||||
}
|
||||
|
||||
///////////////////////////////////////
|
||||
// IMG CLASS IMPLEMENTATION: GETTERS //
|
||||
///////////////////////////////////////
|
||||
|
||||
template <typename Format>
|
||||
std::int32_t Img<Format>::width() const noexcept {
|
||||
return _width;
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
std::int32_t Img<Format>::height() const noexcept {
|
||||
return _height;
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
ImgPixel const* Img<Format>::data() const noexcept {
|
||||
return _pixels.data();
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
ImgPixel* Img<Format>::data() noexcept {
|
||||
return _pixels.data();
|
||||
}
|
||||
|
||||
/////////////////////////////////////////////
|
||||
// IMG CLASS IMPLEMENTATION: FUNCTIONALITY //
|
||||
/////////////////////////////////////////////
|
||||
|
||||
template <typename Format>
|
||||
void Img<Format>::write(std::string const& filename) const {
|
||||
if (_pixels.empty()) {
|
||||
std::cerr << "Img::write:: image is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::ofstream filestream(filename, std::ios::binary);
|
||||
|
||||
_format.write(filestream, *this);
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
template <typename Functor>
|
||||
void Img<Format>::fill(Functor f) {
|
||||
if (_pixels.empty()) {
|
||||
std::cerr << "Img::fill(Functor): image is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
for (auto& pixel : _pixels) f(pixel);
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
void Img<Format>::fill(ImgPixel pixel) {
|
||||
if (_pixels.empty()) {
|
||||
std::cerr << "Img::fill(ImgPixel): image is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
std::fill(_pixels.begin(), _pixels.end(), pixel);
|
||||
}
|
||||
|
||||
template <typename Format>
|
||||
void Img<Format>::fill(ImgPixel pixel, int row, int col) {
|
||||
if (_pixels.empty()) {
|
||||
std::cerr << "Img::fill(ImgPixel): image is empty" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (row >= _height || row < 0 || col >= _width || col < 0) {
|
||||
std::cerr << "Img::fill(ImgPixel, int, int): out of range" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
_pixels.at(row * _width + col) = pixel;
|
||||
}
|
||||
|
||||
#endif // _GAMMA_UTILS_IMG_HPP
|
||||
@@ -0,0 +1,50 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_IMGALGORITHM_HPP
|
||||
#define _GAMMA_UTILS_IMGALGORITHM_HPP
|
||||
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
|
||||
// struct to store fractal that image will fill from
|
||||
class ImgFractal {
|
||||
private:
|
||||
const std::int32_t _width;
|
||||
const std::int32_t _height;
|
||||
|
||||
double _cx = -0.7436;
|
||||
double _cy = 0.1319;
|
||||
|
||||
double _magn = 2000000.0;
|
||||
int _maxIterations = 1000;
|
||||
|
||||
public:
|
||||
ImgFractal(std::int32_t width, std::int32_t height)
|
||||
: _width(width), _height(height) {}
|
||||
|
||||
double operator()(std::int32_t x, std::int32_t y) const {
|
||||
double fx = (double(x) - double(_width) / 2) * (1 / _magn) + _cx;
|
||||
double fy = (double(y) - double(_height) / 2) * (1 / _magn) + _cy;
|
||||
|
||||
double res = 0;
|
||||
double nx = 0;
|
||||
double ny = 0;
|
||||
double val = 0;
|
||||
|
||||
for (int i = 0; nx * nx + ny * ny <= 4 && i < _maxIterations; ++i) {
|
||||
val = nx * nx - ny * ny + fx;
|
||||
ny = 2 * nx * ny + fy;
|
||||
nx = val;
|
||||
|
||||
res += std::exp(-std::sqrt(nx * nx + ny * ny));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
};
|
||||
|
||||
#endif // _GAMMA_UTILS_IMGALGORITHM_HPP
|
||||
@@ -0,0 +1,98 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_IMGFORMAT_HPP
|
||||
#define _GAMMA_UTILS_IMGFORMAT_HPP
|
||||
|
||||
#include "ImgPixel.hpp"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
namespace ImgFormat {
|
||||
|
||||
// struct to store an image in BMP format
|
||||
struct BMP {
|
||||
private:
|
||||
using FileHeader = struct {
|
||||
// not from specification
|
||||
// was added for alignment
|
||||
// store size of rest of the fields
|
||||
std::uint16_t sizeRest; // file header size in bytes
|
||||
|
||||
std::uint16_t type;
|
||||
std::uint32_t size; // file size in bytes
|
||||
std::uint32_t reserved;
|
||||
std::uint32_t offBits; // cumulative header size in bytes
|
||||
};
|
||||
|
||||
using InfoHeader = struct {
|
||||
// from specification
|
||||
// store size of rest of the fields
|
||||
std::uint32_t size; // info header size in bytes
|
||||
|
||||
std::int32_t width; // image width in pixels
|
||||
std::int32_t height; // image height in pixels
|
||||
std::uint16_t planes;
|
||||
std::uint16_t bitCount; // color depth
|
||||
std::uint32_t compression; // compression
|
||||
std::uint32_t sizeImage; // image map size in bytes
|
||||
std::int32_t xPelsPerMeter; // pixel per metre (y axis)
|
||||
std::int32_t yPelsPerMeter; // pixel per metre (y axis)
|
||||
std::uint32_t clrUsed; // color palette (0 is default)
|
||||
std::uint32_t clrImportant;
|
||||
};
|
||||
|
||||
FileHeader _fileHeader;
|
||||
InfoHeader _infoHeader;
|
||||
|
||||
public:
|
||||
BMP(std::int32_t width, std::int32_t height) noexcept {
|
||||
reset(width, height);
|
||||
}
|
||||
|
||||
void reset(std::int32_t width, std::int32_t height) noexcept {
|
||||
uint32_t padSize = (4 - (width * sizeof(ImgPixel)) % 4) % 4;
|
||||
uint32_t mapSize = width * height * sizeof(ImgPixel) + height * padSize;
|
||||
uint32_t allSize = mapSize + _fileHeader.sizeRest + _infoHeader.size;
|
||||
|
||||
_fileHeader.sizeRest = 14; // file header size in bytes
|
||||
_fileHeader.type = 0x4d42;
|
||||
_fileHeader.size = allSize; // file size in bytes
|
||||
_fileHeader.reserved = 0;
|
||||
_fileHeader.offBits = 54; // sizeRest + size -> 14 + 40 -> 54
|
||||
|
||||
_infoHeader.size = 40; // info header size in bytes
|
||||
_infoHeader.width = width; // image width in pixels
|
||||
_infoHeader.height = height; // image height in pixels
|
||||
_infoHeader.planes = 1;
|
||||
_infoHeader.bitCount = 32; // color depth
|
||||
_infoHeader.compression = 0; // compression
|
||||
_infoHeader.sizeImage = mapSize; // image map size in bytes
|
||||
_infoHeader.xPelsPerMeter = 0; // pixel per metre (x axis)
|
||||
_infoHeader.yPelsPerMeter = 0; // pixel per metre (y axis)
|
||||
_infoHeader.clrUsed = 0; // color palette (0 is default)
|
||||
_infoHeader.clrImportant = 0;
|
||||
}
|
||||
|
||||
template <template <class> class Image, typename Format>
|
||||
void write(std::ofstream& ostream, Image<Format> const& image) const {
|
||||
ostream.write(reinterpret_cast<char const*>(&_fileHeader.type),
|
||||
_fileHeader.sizeRest);
|
||||
|
||||
ostream.write(reinterpret_cast<char const*>(&_infoHeader),
|
||||
_infoHeader.size);
|
||||
|
||||
ostream.write(reinterpret_cast<char const*>(image.data()),
|
||||
image.width() * image.height() * sizeof(image.data()[0]));
|
||||
}
|
||||
|
||||
FileHeader const& fileHeader() const noexcept { return _fileHeader; }
|
||||
InfoHeader const& infoHeader() const noexcept { return _infoHeader; }
|
||||
};
|
||||
|
||||
} // namespace ImgFormat
|
||||
|
||||
#endif // _GAMMA_UTILS_IMGFORMAT_HPP
|
||||
@@ -0,0 +1,40 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_IMGPIXEL_HPP
|
||||
#define _GAMMA_UTILS_IMGPIXEL_HPP
|
||||
|
||||
#include <cstdint>
|
||||
#include <ostream>
|
||||
|
||||
// struct to store a pixel of image
|
||||
struct ImgPixel {
|
||||
std::uint8_t b;
|
||||
std::uint8_t g;
|
||||
std::uint8_t r;
|
||||
std::uint8_t a;
|
||||
|
||||
bool operator==(ImgPixel const& other) const {
|
||||
return (b == other.b) && (g == other.g) && (r == other.r) && (a == other.a);
|
||||
}
|
||||
|
||||
bool operator!=(ImgPixel const& other) const { return !(*this == other); }
|
||||
|
||||
void set(std::uint8_t blue, std::uint8_t green, std::uint8_t red,
|
||||
std::uint8_t alpha) {
|
||||
b = blue;
|
||||
g = green;
|
||||
r = red;
|
||||
a = alpha;
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream& output, ImgPixel const& pixel) {
|
||||
return output << "(" << unsigned(pixel.r) << ", " << unsigned(pixel.g) << ", "
|
||||
<< unsigned(pixel.b) << ", " << unsigned(pixel.a) << ")";
|
||||
}
|
||||
|
||||
#endif // _GAMMA_UTILS_IMGPIXEL_HPP
|
||||
@@ -0,0 +1,31 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2019-2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#ifndef _GAMMA_UTILS_OTHER_HPP
|
||||
#define _GAMMA_UTILS_OTHER_HPP
|
||||
|
||||
#include <chrono>
|
||||
|
||||
// function for time measuring
|
||||
inline double get_time_in_sec() {
|
||||
namespace ch = std::chrono;
|
||||
return ch::time_point_cast<ch::milliseconds>(ch::steady_clock::now())
|
||||
.time_since_epoch()
|
||||
.count() *
|
||||
1.e-3;
|
||||
}
|
||||
|
||||
// function to check correctness
|
||||
template <typename It>
|
||||
bool check(It begin1, It end1, It begin2) {
|
||||
for (; begin1 != end1; ++begin1, ++begin2) {
|
||||
if (*begin1 != *begin2) return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
#endif // _GAMMA_UTILS_OTHER_HPP
|
||||
@@ -0,0 +1 @@
|
||||
lab directory needed for notebook
|
||||
@@ -0,0 +1,55 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
# Script to submit job in Intel(R) DevCloud
|
||||
# Version: 0.7
|
||||
#==========================================
|
||||
if [ -z "$1" ]; then
|
||||
echo "Missing script argument, Usage: ./q run.sh"
|
||||
elif [ ! -f "$1" ]; then
|
||||
echo "File $1 does not exist"
|
||||
else
|
||||
echo "Job has been submitted to Intel(R) DevCloud and will execute soon."
|
||||
echo ""
|
||||
echo " If you do not see result in 60 seconds, please restart the Jupyter kernel:"
|
||||
echo " Kernel -> 'Restart Kernel and Clear All Outputs...' and then try again"
|
||||
echo ""
|
||||
script=$1
|
||||
shift
|
||||
args=$@
|
||||
# Remove old output files
|
||||
rm *.sh.* > /dev/null 2>&1
|
||||
# Submit job using qsub
|
||||
qsub_id=`qsub -l nodes=1:gpu:ppn=2 -d . $script $@`
|
||||
job_id="$(cut -d'.' -f1 <<<"$qsub_id")"
|
||||
# Print qstat output
|
||||
qstat
|
||||
# Wait for output file to be generated and display
|
||||
echo ""
|
||||
echo -ne "Waiting for Output "
|
||||
script_name=${script/scripts\//}
|
||||
until [ -f $script_name.o$job_id ]; do
|
||||
sleep 1
|
||||
echo -ne "█"
|
||||
((timeout++))
|
||||
# Timeout if no output file generated within 60 seconds
|
||||
if [ $timeout == 60 ]; then
|
||||
echo ""
|
||||
echo ""
|
||||
echo "TimeOut 60 seconds: Job is still queued for execution, check for output file later ($script_name.o$job_id)"
|
||||
echo ""
|
||||
break
|
||||
fi
|
||||
done
|
||||
# Print output and error file content if exist
|
||||
if [ -n "$(find -name '*.sh.o'$job_id)" ]; then
|
||||
echo " Done⬇"
|
||||
cat $script_name.o$job_id
|
||||
cat $script_name.e$job_id
|
||||
echo "Job Completed in $timeout seconds."
|
||||
rm *.sh.*$job_id > /dev/null 2>&1
|
||||
fi
|
||||
fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL hetero exercise using flow::async_node
|
||||
dpcpp -std=c++20 -O2 solutions/triad-hetero-async_node-solved.cpp -o bin/triad-hetero-async_node-solved -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-hetero-async_node-solved; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL hetero exercise using flow::async_node
|
||||
dpcpp -std=c++20 -O2 lab/triad-hetero-async_node.cpp -o bin/triad-hetero-async_node -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-hetero-async_node; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL exercise triad consecutive
|
||||
dpcpp -std=c++20 -O2 lab/triad-consecutive.cpp -o bin/triad-consecutive -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-consecutive; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB Introduction exercise pi-parallel
|
||||
dpcpp -std=c++17 -O2 lab/pi-parallel.cpp -o bin/pi-parallel -tbb
|
||||
bin/pi-parallel
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB Introduction exercise pi-serial
|
||||
dpcpp -std=c++17 -O2 lab/pi-serial.cpp -o bin/pi-serial
|
||||
bin/pi-serial
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB Introduction sample pi-parallel
|
||||
dpcpp -std=c++17 -O2 solutions/pi-parallel.cpp -o bin/pi-parallel-solution -tbb
|
||||
bin/pi-parallel-solution
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL hetero solution using a resumable task
|
||||
dpcpp -std=c++20 -O2 solutions/triad-hetero-suspend-resume-solved.cpp -o bin/triad-hetero-suspend-resume-solved -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-hetero-suspend-resume-solved; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL hetero exercise using a resumable task
|
||||
dpcpp -std=c++20 -O2 lab/triad-hetero-suspend-resume.cpp -o bin/triad-hetero-suspend-resume -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-hetero-suspend-resume; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL solution using a task_group
|
||||
dpcpp -std=c++20 -O2 solutions/triad-task_group-solved.cpp -o bin/triad-task_group-solved -tbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-task_group-solved; fi
|
||||
@@ -0,0 +1,11 @@
|
||||
#!/bin/bash
|
||||
#==========================================
|
||||
# Copyright (c) 2020 Intel Corporation
|
||||
#
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
#==========================================
|
||||
|
||||
source /opt/intel/inteloneapi/setvars.sh > /dev/null 2>&1
|
||||
/bin/echo "##" $(whoami) is compiling oneTBB with SYCL exercise using a task_group
|
||||
dpcpp -std=c++20 -O2 lab/triad-task_group.cpp -o bin/triad-task_group -ltbb -lpthread
|
||||
if [ $? -eq 0 ]; then bin/triad-task_group; fi
|
||||
@@ -0,0 +1,62 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
#define SIZE 1024
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
int main() {
|
||||
|
||||
std::array<int, SIZE> c;
|
||||
// Reference vector for sanity check
|
||||
std::array<int, SIZE> c_res;
|
||||
std::fill_n(c_res.begin(), SIZE, 1);
|
||||
|
||||
{
|
||||
range<1> r{SIZE};
|
||||
queue q(gpu_selector{});
|
||||
buffer<int, 1> a_buf{r};
|
||||
buffer<int, 1> b_buf{r};
|
||||
buffer<int, 1> c_buf{c.data(), r};
|
||||
|
||||
// Create a simple data dependency graph,
|
||||
// Following structure:
|
||||
// (1) ----> (3) ---> (4)
|
||||
// (2) __/
|
||||
|
||||
q.submit([&](auto& h) {
|
||||
accessor a(a_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
a[idx] = idx; });
|
||||
});
|
||||
q.submit([&](auto& h) {
|
||||
accessor b(b_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
b[idx] = -idx; });
|
||||
});
|
||||
q.submit([&](auto& h) {
|
||||
accessor a(a_buf, h, read_only);
|
||||
accessor b(b_buf, h, read_only);
|
||||
accessor c(c_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
c[idx] = a[idx] + b[idx]; });
|
||||
});
|
||||
q.submit([&](auto& h) {
|
||||
accessor c(c_buf, h, read_write);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
c[idx] += 1; });
|
||||
}).wait();
|
||||
}
|
||||
|
||||
if (std::equal(c.begin(), c.end(), c_res.begin())) {
|
||||
std::cout << "DONE.\n";
|
||||
} else {
|
||||
std::cout << "ERROR. Mismatch in resulting data!\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
//==============================================================
|
||||
// Copyright (c) Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
#include <CL/sycl.hpp>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// dpc_common.hpp can be found in the dev-utilities include folder.
|
||||
// e.g., $ONEAPI_ROOT/dev-utilities/latest/include/dpc_common.hpp
|
||||
#include "dpc_common.hpp"
|
||||
|
||||
// Header locations and some DPC++ extensions changed between beta09 and beta10
|
||||
// Temporarily modify the code sample to accept either version
|
||||
#define BETA09 20200827
|
||||
#if __SYCL_COMPILER_VERSION <= BETA09
|
||||
#include <CL/sycl/intel/fpga_extensions.hpp>
|
||||
namespace INTEL = sycl::intel; // Namespace alias for backward compatibility
|
||||
#else
|
||||
#include <CL/sycl/INTEL/fpga_extensions.hpp>
|
||||
#endif
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
// This function instantiates the vector add kernel, which contains
|
||||
// a loop that adds up the two summand arrays and stores the result
|
||||
// into sum.
|
||||
void VecAdd(const std::vector<float> &summands1,
|
||||
const std::vector<float> &summands2, std::vector<float> &sum,
|
||||
size_t array_size) {
|
||||
|
||||
|
||||
#if defined(FPGA_EMULATOR)
|
||||
INTEL::fpga_emulator_selector device_selector;
|
||||
#else
|
||||
INTEL::fpga_selector device_selector;
|
||||
#endif
|
||||
|
||||
try {
|
||||
queue q(device_selector, dpc_common::exception_handler,
|
||||
property::queue::enable_profiling{});
|
||||
|
||||
buffer buffer_summands1(summands1);
|
||||
buffer buffer_summands2(summands2);
|
||||
// Use verbose SYCL 1.2 syntax for the output buffer.
|
||||
// (This will become unnecessary in a future compiler version.)
|
||||
buffer<float, 1> buffer_sum(sum.data(), array_size);
|
||||
|
||||
event e = q.submit([&](handler &h) {
|
||||
auto acc_summands1 = buffer_summands1.get_access<access::mode::read>(h);
|
||||
auto acc_summands2 = buffer_summands2.get_access<access::mode::read>(h);
|
||||
auto acc_sum = buffer_sum.get_access<access::mode::discard_write>(h);
|
||||
|
||||
h.single_task([=]() {
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
acc_sum[i] = acc_summands1[i] + acc_summands2[i];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
double start = e.get_profiling_info<info::event_profiling::command_start>();
|
||||
double end = e.get_profiling_info<info::event_profiling::command_end>();
|
||||
// convert from nanoseconds to ms
|
||||
double kernel_time = (double)(end - start) * 1e-6;
|
||||
|
||||
std::cout << " kernel time : " << kernel_time << " ms\n";
|
||||
std::cout << "Throughput for kernel " << ": ";
|
||||
std::cout << std::fixed << std::setprecision(3)
|
||||
<< ((double)array_size / kernel_time) / 1e6f << " GFlops\n";
|
||||
|
||||
} catch (sycl::exception const &e) {
|
||||
// Catches exceptions in the host code
|
||||
std::cout << "Caught a SYCL host exception:\n" << e.what() << "\n";
|
||||
|
||||
// Most likely the runtime couldn't find FPGA hardware!
|
||||
if (e.get_cl_code() == CL_DEVICE_NOT_FOUND) {
|
||||
std::cout << "If you are targeting an FPGA, please ensure that your "
|
||||
"system has a correctly configured FPGA board.\n";
|
||||
std::cout << "If you are targeting the FPGA emulator, compile with "
|
||||
"-DFPGA_EMULATOR.\n";
|
||||
}
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
size_t array_size = 1 << 26;
|
||||
|
||||
if (argc > 1) {
|
||||
std::string option(argv[1]);
|
||||
if (option == "-h" || option == "--help") {
|
||||
std::cout << "Usage: \n<executable> <data size>\n\nFAILED\n";
|
||||
return 1;
|
||||
} else {
|
||||
array_size = std::stoi(option);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> summands1(array_size);
|
||||
std::vector<float> summands2(array_size);
|
||||
|
||||
std::vector<float> sum(array_size);
|
||||
|
||||
// Initialize the two summand arrays (arrays to be added to each other) to
|
||||
// 1:N and N:1, so that the sum of all elements is N + 1
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
summands1[i] = static_cast<float>(i + 1);
|
||||
summands2[i] = static_cast<float>(array_size - i);
|
||||
}
|
||||
|
||||
std::cout << "Input Array Size: " << array_size << "\n";
|
||||
|
||||
// Instantiate VecAdd kernel that contains a loop that adds up the two summand arrays.
|
||||
VecAdd(summands1, summands2, sum, array_size);
|
||||
|
||||
// Verify that the output data is the same for every unroll factor
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
if (sum[i] != summands1[i] + summands2[i]) {
|
||||
std::cout << "FAILED: The results are incorrect\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASSED: The results are correct\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
//==============================================================
|
||||
// Copyright (c) Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
#include <CL/sycl.hpp>
|
||||
#include <iomanip>
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
// dpc_common.hpp can be found in the dev-utilities include folder.
|
||||
// e.g., $ONEAPI_ROOT/dev-utilities//include/dpc_common.hpp
|
||||
#include "dpc_common.hpp"
|
||||
|
||||
// Header locations and some DPC++ extensions changed between beta09 and beta10
|
||||
// Temporarily modify the code sample to accept either version
|
||||
#define BETA09 20200827
|
||||
#if __SYCL_COMPILER_VERSION <= BETA09
|
||||
#include <CL/sycl/intel/fpga_extensions.hpp>
|
||||
namespace INTEL = sycl::intel; // Namespace alias for backward compatibility
|
||||
#else
|
||||
#include <CL/sycl/INTEL/fpga_extensions.hpp>
|
||||
#endif
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
template <int unroll_factor> class VAdd;
|
||||
|
||||
// This function instantiates the vector add kernel, which contains
|
||||
// a loop that adds up the two summand arrays and stores the result
|
||||
// into sum. This loop will be unrolled by the specified unroll_factor.
|
||||
template <int unroll_factor>
|
||||
void VecAdd(const std::vector<float> &summands1,
|
||||
const std::vector<float> &summands2, std::vector<float> &sum,
|
||||
size_t array_size) {
|
||||
|
||||
|
||||
#if defined(FPGA_EMULATOR)
|
||||
INTEL::fpga_emulator_selector device_selector;
|
||||
#else
|
||||
INTEL::fpga_selector device_selector;
|
||||
#endif
|
||||
|
||||
try {
|
||||
queue q(device_selector, dpc_common::exception_handler,
|
||||
property::queue::enable_profiling{});
|
||||
|
||||
buffer buffer_summands1(summands1);
|
||||
buffer buffer_summands2(summands2);
|
||||
// Use verbose SYCL 1.2 syntax for the output buffer.
|
||||
// (This will become unnecessary in a future compiler version.)
|
||||
buffer<float, 1> buffer_sum(sum.data(), array_size);
|
||||
|
||||
event e = q.submit([&](handler &h) {
|
||||
auto acc_summands1 = buffer_summands1.get_access<access::mode::read>(h);
|
||||
auto acc_summands2 = buffer_summands2.get_access<access::mode::read>(h);
|
||||
auto acc_sum = buffer_sum.get_access<access::mode::discard_write>(h);
|
||||
|
||||
h.single_task<VAdd<unroll_factor>>([=]()
|
||||
[[intel::kernel_args_restrict]] {
|
||||
// Unroll the loop fully or partially, depending on unroll_factor
|
||||
#pragma unroll unroll_factor
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
acc_sum[i] = acc_summands1[i] + acc_summands2[i];
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
double start = e.get_profiling_info<info::event_profiling::command_start>();
|
||||
double end = e.get_profiling_info<info::event_profiling::command_end>();
|
||||
// convert from nanoseconds to ms
|
||||
double kernel_time = (double)(end - start) * 1e-6;
|
||||
|
||||
std::cout << "unroll_factor " << unroll_factor
|
||||
<< " kernel time : " << kernel_time << " ms\n";
|
||||
std::cout << "Throughput for kernel with unroll_factor " << unroll_factor
|
||||
<< ": ";
|
||||
std::cout << std::fixed << std::setprecision(3)
|
||||
<< ((double)array_size / kernel_time) / 1e6f << " GFlops\n";
|
||||
|
||||
} catch (sycl::exception const &e) {
|
||||
// Catches exceptions in the host code
|
||||
std::cout << "Caught a SYCL host exception:\n" << e.what() << "\n";
|
||||
|
||||
// Most likely the runtime couldn't find FPGA hardware!
|
||||
if (e.get_cl_code() == CL_DEVICE_NOT_FOUND) {
|
||||
std::cout << "If you are targeting an FPGA, please ensure that your "
|
||||
"system has a correctly configured FPGA board.\n";
|
||||
std::cout << "If you are targeting the FPGA emulator, compile with "
|
||||
"-DFPGA_EMULATOR.\n";
|
||||
}
|
||||
std::terminate();
|
||||
}
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[]) {
|
||||
size_t array_size = 1 << 26;
|
||||
|
||||
if (argc > 1) {
|
||||
std::string option(argv[1]);
|
||||
if (option == "-h" || option == "--help") {
|
||||
std::cout << "Usage: \n<executable> <data size>\n\nFAILED\n";
|
||||
return 1;
|
||||
} else {
|
||||
array_size = std::stoi(option);
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<float> summands1(array_size);
|
||||
std::vector<float> summands2(array_size);
|
||||
|
||||
std::vector<float> sum_unrollx1(array_size);
|
||||
std::vector<float> sum_unrollx2(array_size);
|
||||
std::vector<float> sum_unrollx4(array_size);
|
||||
std::vector<float> sum_unrollx8(array_size);
|
||||
std::vector<float> sum_unrollx16(array_size);
|
||||
|
||||
// Initialize the two summand arrays (arrays to be added to each other) to
|
||||
// 1:N and N:1, so that the sum of all elements is N + 1
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
summands1[i] = static_cast<float>(i + 1);
|
||||
summands2[i] = static_cast<float>(array_size - i);
|
||||
}
|
||||
|
||||
std::cout << "Input Array Size: " << array_size << "\n";
|
||||
|
||||
// Instantiate VecAdd kernel with different unroll factors: 1, 2, 4, 8, 16
|
||||
// The VecAdd kernel contains a loop that adds up the two summand arrays.
|
||||
// This loop will be unrolled by the specified unroll factor.
|
||||
// The sum array is expected to be identical, regardless of the unroll factor.
|
||||
VecAdd<1>(summands1, summands2, sum_unrollx1, array_size);
|
||||
VecAdd<2>(summands1, summands2, sum_unrollx2, array_size);
|
||||
VecAdd<4>(summands1, summands2, sum_unrollx4, array_size);
|
||||
VecAdd<8>(summands1, summands2, sum_unrollx8, array_size);
|
||||
VecAdd<16>(summands1, summands2, sum_unrollx16, array_size);
|
||||
|
||||
// Verify that the output data is the same for every unroll factor
|
||||
for (size_t i = 0; i < array_size; i++) {
|
||||
if (sum_unrollx1[i] != summands1[i] + summands2[i] ||
|
||||
sum_unrollx1[i] != sum_unrollx2[i] ||
|
||||
sum_unrollx1[i] != sum_unrollx4[i] ||
|
||||
sum_unrollx1[i] != sum_unrollx8[i] ||
|
||||
sum_unrollx1[i] != sum_unrollx16[i]) {
|
||||
std::cout << "FAILED: The results are incorrect\n";
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::cout << "PASSED: The results are correct\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <chrono>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
#include <thread>
|
||||
#include <tbb/tbb.h>
|
||||
|
||||
double calc_pi(int num_intervals) {
|
||||
double dx = 1.0 / num_intervals;
|
||||
double sum = tbb::parallel_reduce(
|
||||
/* range = */ tbb::blocked_range<int>(0, num_intervals ),
|
||||
/* identity = */ 0.0,
|
||||
/* func */
|
||||
[=](const tbb::blocked_range<int>& r, double init) -> double {
|
||||
for (int i = r.begin(); i != r.end(); ++i) {
|
||||
double x = (i+0.5)*dx;
|
||||
double h = std::sqrt(1-x*x);
|
||||
init += h*dx;
|
||||
}
|
||||
return init;
|
||||
},
|
||||
std::plus<double>{}
|
||||
);
|
||||
double pi = 4 * sum;
|
||||
return pi;
|
||||
}
|
||||
|
||||
static void warmupTBB() {
|
||||
int num_threads = std::thread::hardware_concurrency();
|
||||
tbb::parallel_for(0, num_threads,
|
||||
[](unsigned int) {
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
});
|
||||
}
|
||||
|
||||
int main() {
|
||||
const int num_intervals = std::numeric_limits<int>::max();
|
||||
double parallel_time = 0.0;
|
||||
warmupTBB();
|
||||
{
|
||||
auto pt0 = std::chrono::high_resolution_clock::now();
|
||||
double pi = calc_pi(num_intervals);
|
||||
parallel_time = 1e-9*(std::chrono::high_resolution_clock::now() - pt0).count();
|
||||
std::cout << "parallel pi == " << pi << std::endl;
|
||||
}
|
||||
|
||||
std::cout << "parallel_time == " << parallel_time << " seconds" << std::endl;
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
// For random number generation in device code:
|
||||
#include <oneapi/dpl/random>
|
||||
// Utility header for output Image
|
||||
#include "utils.hpp"
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
const int iter = 10000;
|
||||
const int img_dimensions = 512;
|
||||
|
||||
const int size_wg = 32;
|
||||
const int num_wg = (int)ceil((double)iter / (double)size_wg);
|
||||
|
||||
// Return index of pixel corresponding to a set of simulation coordinates:
|
||||
int GetPixelIndex(double x, double y) {
|
||||
const int radius = img_dimensions / 2;
|
||||
int img_x = x * radius + radius;
|
||||
int img_y = y * radius + radius;
|
||||
return img_y * img_dimensions + img_x;
|
||||
}
|
||||
|
||||
int main() {
|
||||
Img<ImgFormat::BMP> image{img_dimensions, img_dimensions};
|
||||
int sum = 0;
|
||||
|
||||
queue q(default_selector{});
|
||||
|
||||
std::uint32_t seed = 667;
|
||||
{
|
||||
buffer sum_buf(&sum, range(1));
|
||||
buffer<ImgPixel,1> imgplot_buf(image.data(), image.width() * image.height());
|
||||
|
||||
queue q;
|
||||
// Compute a dot-product by reducing all computed values using standard plus functor
|
||||
q.submit([&](handler& cgh) {
|
||||
accessor img_plot(imgplot_buf, cgh, read_write);
|
||||
accessor sum(sum_buf, cgh, read_write);
|
||||
cgh.parallel_for<class dot_product>(nd_range<1>{num_wg * size_wg, size_wg}, sycl::ONEAPI::reduction(sum, 0, std::plus<int>()), [=](nd_item<1> it, auto& sum) {
|
||||
int i = it.get_global_id(0);
|
||||
|
||||
if (i < iter) {
|
||||
// Get random coords
|
||||
oneapi::std::minstd_rand engine(seed, i * 2);
|
||||
oneapi::std::uniform_real_distribution<double> distr(-1.0,1.0);
|
||||
double x = distr(engine);
|
||||
double y = distr(engine);
|
||||
|
||||
auto hypotenuse_sqr = x * x + y * y;
|
||||
if (hypotenuse_sqr <= 1.0) {
|
||||
sum += 1;
|
||||
img_plot[GetPixelIndex(x,y)].set(255,255,255,255);
|
||||
}
|
||||
}
|
||||
});
|
||||
}).wait();
|
||||
}
|
||||
std::cout << "DONE. \nPi: " << 4.0 * (double)sum / iter << "\n";
|
||||
image.write("img/pi.png");
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache 2.0
|
||||
// =============================================================
|
||||
|
||||
#include "../common/common_utils.hpp"
|
||||
|
||||
#include <cmath> //for std::ceil
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/flow_graph.h>
|
||||
#include <tbb/global_control.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
constexpr size_t array_size = 16;
|
||||
|
||||
template<size_t ARRAY_SIZE>
|
||||
struct msg_t {
|
||||
static constexpr size_t array_size = ARRAY_SIZE;
|
||||
const float offload_ratio = 0.5;
|
||||
const float alpha_0 = 0.5;
|
||||
const float alpha_1 = 1.0;
|
||||
std::array<float, array_size> a_array; // input
|
||||
std::array<float, array_size> b_array; // input
|
||||
std::array<float, array_size> c_sycl; // GPU output
|
||||
std::array<float, array_size> c_tbb; // CPU output
|
||||
};
|
||||
|
||||
using msg_ptr = std::shared_ptr<msg_t<array_size>>;
|
||||
|
||||
using async_node_t = tbb::flow::async_node<msg_ptr, msg_ptr>;
|
||||
using gateway_t = async_node_t::gateway_type;
|
||||
|
||||
class AsyncActivity {
|
||||
msg_ptr msg;
|
||||
gateway_t* gateway_ptr;
|
||||
std::atomic<bool> submit_flag;
|
||||
std::thread service_thread;
|
||||
|
||||
public:
|
||||
AsyncActivity() : msg{nullptr}, gateway_ptr{nullptr}, submit_flag{false},
|
||||
service_thread( [this] {
|
||||
//Wait until other thread sets submit_flag=true
|
||||
while( !submit_flag ) std::this_thread::yield();
|
||||
// Here we go! Dispatch code to the GPU
|
||||
// Execute the kernel over a portion of the array range
|
||||
size_t array_size_sycl = std::ceil(msg->a_array.size() * msg->offload_ratio);
|
||||
{
|
||||
sycl::buffer a_buffer{msg->a_array}, b_buffer{msg->b_array}, c_buffer{msg->c_sycl};
|
||||
sycl::queue q{sycl::gpu_selector{}};
|
||||
float alpha = msg->alpha_0;
|
||||
q.submit([&, alpha](sycl::handler& h) {
|
||||
sycl::accessor a_accessor{a_buffer, h, sycl::read_only};
|
||||
sycl::accessor b_accessor{b_buffer, h, sycl::read_only};
|
||||
sycl::accessor c_accessor{c_buffer, h, sycl::write_only};
|
||||
h.parallel_for(sycl::range<1>{array_size_sycl}, [=](sycl::id<1> index) {
|
||||
c_accessor[index] = a_accessor[index] + b_accessor[index] * alpha;
|
||||
});
|
||||
}).wait();
|
||||
}
|
||||
gateway_ptr->try_put(msg);
|
||||
gateway_ptr->release_wait();
|
||||
} ) {}
|
||||
|
||||
~AsyncActivity() {
|
||||
service_thread.join();
|
||||
}
|
||||
|
||||
void submit(msg_ptr m, gateway_t& gateway) {
|
||||
gateway.reserve_wait();
|
||||
msg = m;
|
||||
gateway_ptr = &gateway;
|
||||
submit_flag = true;
|
||||
}
|
||||
};
|
||||
|
||||
int main() {
|
||||
tbb::flow::graph g;
|
||||
|
||||
// Input node:
|
||||
tbb::flow::input_node<msg_ptr> in_node{g,
|
||||
[&](tbb::flow_control& fc) -> msg_ptr {
|
||||
static bool has_run = false;
|
||||
if (has_run) fc.stop();
|
||||
has_run = true; // This example only creates a message to feed the Flow Graph
|
||||
msg_ptr msg = std::make_shared<msg_t<array_size>>();
|
||||
common::init_input_arrays(msg->a_array, msg->b_array);
|
||||
return msg;
|
||||
}
|
||||
};
|
||||
|
||||
// CPU node
|
||||
tbb::flow::function_node<msg_ptr, msg_ptr> cpu_node{
|
||||
g, tbb::flow::unlimited, [&](msg_ptr msg) -> msg_ptr {
|
||||
size_t i_start = static_cast<size_t>(std::ceil(msg->array_size * msg->offload_ratio));
|
||||
size_t i_end = static_cast<size_t>(msg->array_size);
|
||||
auto &a_array = msg->a_array, &b_array = msg->b_array, &c_tbb = msg->c_tbb;
|
||||
float alpha = msg->alpha_1;
|
||||
tbb::parallel_for(tbb::blocked_range<size_t>{i_start, i_end},
|
||||
[&, alpha](const tbb::blocked_range<size_t>& r) {
|
||||
for (size_t i = r.begin(); i < r.end(); ++i)
|
||||
c_tbb[i] = a_array[i] + alpha * b_array[i];
|
||||
}
|
||||
);
|
||||
return msg;
|
||||
}};
|
||||
|
||||
// async node -- GPU
|
||||
AsyncActivity async_act;
|
||||
async_node_t a_node{g, tbb::flow::unlimited,
|
||||
[&async_act](msg_ptr msg, gateway_t& gateway) {
|
||||
async_act.submit(msg, gateway);
|
||||
}
|
||||
};
|
||||
|
||||
// join node
|
||||
using join_t = tbb::flow::join_node<std::tuple<msg_ptr, msg_ptr>>;
|
||||
join_t node_join{g};
|
||||
|
||||
// out node
|
||||
tbb::flow::function_node<join_t::output_type> out_node{g, tbb::flow::unlimited,
|
||||
[&](const join_t::output_type& two_msgs) {
|
||||
msg_ptr msg = std::get<0>(two_msgs); //Both msg's point to the same data
|
||||
//Merge GPU result into CPU array
|
||||
std::size_t gpu_end = static_cast<std::size_t>(std::ceil(msg->array_size * msg->offload_ratio));
|
||||
std::copy(msg->c_sycl.begin(), msg->c_sycl.begin()+gpu_end, msg->c_tbb.begin());
|
||||
common::validate_hetero_results(msg->offload_ratio, msg->alpha_0, msg->alpha_1,
|
||||
msg->a_array, msg->b_array, msg->c_tbb);
|
||||
if(msg->array_size<=64)
|
||||
common::print_hetero_results(msg->offload_ratio, msg->alpha_0, msg->alpha_1,
|
||||
msg->a_array, msg->b_array, msg->c_tbb);
|
||||
}
|
||||
}; // end of out node
|
||||
|
||||
// construct graph
|
||||
tbb::flow::make_edge(in_node, a_node);
|
||||
tbb::flow::make_edge(in_node, cpu_node);
|
||||
tbb::flow::make_edge(a_node, tbb::flow::input_port<0>(node_join));
|
||||
tbb::flow::make_edge(cpu_node, tbb::flow::input_port<1>(node_join));
|
||||
tbb::flow::make_edge(node_join, out_node);
|
||||
|
||||
in_node.activate();
|
||||
g.wait_for_all();
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache 2.0
|
||||
// =============================================================
|
||||
|
||||
#include "../common/common_utils.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <atomic>
|
||||
#include <cmath>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <algorithm>
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/task.h>
|
||||
#include <tbb/task_group.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
|
||||
template<size_t array_size>
|
||||
class AsyncActivity {
|
||||
float alpha;
|
||||
const float *a_array, *b_array;
|
||||
float *c_sycl;
|
||||
sycl::queue& q;
|
||||
float offload_ratio;
|
||||
std::atomic<bool> submit_flag;
|
||||
tbb::task::suspend_point suspend_point;
|
||||
std::thread service_thread;
|
||||
|
||||
public:
|
||||
AsyncActivity(float alpha_sycl, const float *a, const float *b, float *c, sycl::queue &queue) :
|
||||
alpha{alpha_sycl}, a_array{a}, b_array{b}, c_sycl{c}, q{queue},
|
||||
offload_ratio{0}, submit_flag{false},
|
||||
service_thread([this] {
|
||||
// Wait until the job will be submitted into the async activity
|
||||
while(!submit_flag) std::this_thread::yield();
|
||||
// Here submit_flag==true --> DISPATCH GPU computation
|
||||
std::size_t array_size_sycl = std::ceil(array_size * offload_ratio);
|
||||
float l_alpha=alpha;
|
||||
const float *la=a_array, *lb=b_array;
|
||||
float *lc=c_sycl;
|
||||
q.submit([&](sycl::handler& h) {
|
||||
h.parallel_for(sycl::range<1>{array_size_sycl}, [=](sycl::id<1> index) {
|
||||
lc[index] = la[index] + lb[index] * l_alpha;
|
||||
});
|
||||
}).wait(); //The thread may spin or block here.
|
||||
|
||||
// Pass a signal into the main thread that the GPU work is completed
|
||||
tbb::task::resume(suspend_point);
|
||||
}) {}
|
||||
|
||||
~AsyncActivity() {
|
||||
service_thread.join();
|
||||
}
|
||||
|
||||
void submit( float ratio, tbb::task::suspend_point sus_point ) {
|
||||
offload_ratio = ratio;
|
||||
suspend_point = sus_point;
|
||||
submit_flag = true;
|
||||
}
|
||||
}; // class AsyncActivity
|
||||
|
||||
int main() {
|
||||
|
||||
constexpr float ratio = 0.5; // CPU or GPU offload ratio
|
||||
// We use different alpha coefficients so that
|
||||
//we can identify the GPU and CPU part if we print c_array result
|
||||
const float alpha_sycl = 0.5, alpha_tbb = 1.0;
|
||||
constexpr size_t array_size = 16;
|
||||
|
||||
sycl::queue q{sycl::gpu_selector{}};
|
||||
std::cout << "Using device: " << q.get_device().get_info<sycl::info::device::name>() << '\n';
|
||||
|
||||
//This host allocation of c comes handy specially for integrated GPUs (CPU and GPU share mem)
|
||||
float *a_array = malloc_host<float>(array_size, q);
|
||||
float *b_array = malloc_host<float>(array_size, q);
|
||||
float *c_sycl = malloc_host<float>(array_size, q);
|
||||
float *c_tbb = new float[array_size];
|
||||
|
||||
// sets array values to 0..N
|
||||
std::iota(a_array, a_array+array_size,0);
|
||||
std::iota(b_array, b_array+array_size,0);
|
||||
|
||||
tbb::task_group tg;
|
||||
AsyncActivity<array_size> activity{alpha_sycl, a_array, b_array, c_sycl, q};
|
||||
|
||||
//Spawn a task that runs a parallel_for on the CPU
|
||||
tg.run([&, alpha_tbb]{
|
||||
std::size_t i_start = static_cast<std::size_t>(std::ceil(array_size * ratio));
|
||||
std::size_t i_end = array_size;
|
||||
tbb::parallel_for(i_start, i_end, [=]( std::size_t index ) {
|
||||
c_tbb[index] = a_array[index] + alpha_tbb * b_array[index];
|
||||
});
|
||||
});
|
||||
|
||||
//Spawn another task that asyncrhonously offloads computation to the GPU
|
||||
tbb::task::suspend([&]( tbb::task::suspend_point suspend_point ) {
|
||||
activity.submit(ratio, suspend_point);
|
||||
});
|
||||
|
||||
tg.wait();
|
||||
|
||||
//Merge GPU result into CPU array
|
||||
std::size_t gpu_end = static_cast<std::size_t>(std::ceil(array_size * ratio));
|
||||
std::copy(c_sycl, c_sycl+gpu_end, c_tbb);
|
||||
|
||||
common::validate_usm_results(ratio, alpha_sycl, alpha_tbb, a_array, b_array, c_tbb, array_size);
|
||||
if(array_size<64)
|
||||
common::print_usm_results(ratio, alpha_sycl, alpha_tbb, a_array, b_array, c_tbb, array_size);
|
||||
|
||||
free(a_array,q);
|
||||
free(b_array,q);
|
||||
free(c_sycl,q);
|
||||
delete[] c_tbb;
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache 2.0
|
||||
// =============================================================
|
||||
|
||||
#include "../common/common_utils.hpp"
|
||||
#include <array>
|
||||
#include <tbb/blocked_range.h>
|
||||
#include <tbb/parallel_for.h>
|
||||
#include "tbb/task_group.h"
|
||||
|
||||
int main() {
|
||||
const float alpha = 0.5; // coeff for triad calculation
|
||||
const size_t array_size = 16;
|
||||
|
||||
std::array<float, array_size> a_array, b_array, c_sycl, c_tbb;
|
||||
|
||||
// sets array values to 0..N
|
||||
common::init_input_arrays(a_array, b_array);
|
||||
|
||||
// create task_group
|
||||
tbb::task_group tg;
|
||||
|
||||
// Run a TBB task that uses SYCL to offload to GPU, function run does not block
|
||||
tg.run([&, alpha]() {
|
||||
std::cout << "executing on the GPU using SYCL\n";
|
||||
{
|
||||
sycl::buffer a_buffer{a_array}, b_buffer{b_array}, c_buffer{c_sycl};
|
||||
sycl::queue q{sycl::default_selector{}};
|
||||
q.submit([&](sycl::handler& h) {
|
||||
sycl::accessor a_accessor{a_buffer, h, sycl::read_only};
|
||||
sycl::accessor b_accessor{b_buffer, h, sycl::read_only};
|
||||
sycl::accessor c_accessor{c_buffer, h, sycl::write_only};
|
||||
h.parallel_for(sycl::range<1>{array_size}, [=](sycl::id<1> index) {
|
||||
c_accessor[index] = a_accessor[index] + b_accessor[index] * alpha;
|
||||
});
|
||||
}).wait();
|
||||
}
|
||||
});
|
||||
|
||||
// Run a TBB task that uses SYCL to offload to CPU
|
||||
tg.run([&, alpha]() {
|
||||
std::cout << "executing on the CPU using TBB\n";
|
||||
|
||||
tbb::parallel_for(tbb::blocked_range<int>(0, a_array.size()),
|
||||
[&](tbb::blocked_range<int> r) {
|
||||
for (int index = r.begin(); index < r.end(); ++index) {
|
||||
c_tbb[index] = a_array[index] + b_array[index] * alpha;
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// wait for both TBB tasks to complete
|
||||
tg.wait();
|
||||
|
||||
common::validate_results(alpha, a_array, b_array, c_sycl, c_tbb);
|
||||
common::print_results(alpha, a_array, b_array, c_sycl, c_tbb);
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
|
||||
#define N 1024
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
int main() {
|
||||
|
||||
std::vector<int> c_host(N);
|
||||
std::vector<int> c_res(N);
|
||||
std::fill_n(c_res.begin(), N, 1);
|
||||
|
||||
{
|
||||
queue q(gpu_selector{});
|
||||
|
||||
int *a = malloc_shared<int>(N, q);
|
||||
int *b = malloc_shared<int>(N, q);
|
||||
int *c_dev = malloc_device<int>(N, q);
|
||||
|
||||
for (int i = 0; i < N; ++i) {
|
||||
a[i] = i + 1;
|
||||
b[i] = -i;
|
||||
}
|
||||
|
||||
auto e1 = q.parallel_for(range<1>(N), [=](id<1> i) { c_dev[i] = a[i] + b[i]; });
|
||||
|
||||
q.submit([&](auto &h) {
|
||||
h.depends_on(e1);
|
||||
h.memcpy(c_host.data(), c_dev, sizeof(int) * N);
|
||||
}).wait();
|
||||
|
||||
free(a,q);
|
||||
free(b,q);
|
||||
free(c_dev,q);
|
||||
}
|
||||
|
||||
if (std::equal(c_host.begin(), c_host.end(), c_res.begin())) {
|
||||
std::cout << "DONE.\n";
|
||||
} else {
|
||||
std::cout << "ERROR. Mismatch in resulting data!\n";
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
#include <CL/sycl/INTEL/fpga_extensions.hpp>
|
||||
|
||||
#define SIZE 1024
|
||||
|
||||
using namespace sycl;
|
||||
|
||||
int main() {
|
||||
|
||||
{
|
||||
range<1> r{SIZE};
|
||||
#ifdef FPGA_EMULATOR
|
||||
INTEL::fpga_emulator_selector device_selector;
|
||||
#else
|
||||
INTEL::fpga_selector device_selector;
|
||||
#endif
|
||||
queue q(device_selector);
|
||||
|
||||
buffer<int, 1> a_buf{r};
|
||||
buffer<int, 1> b_buf{r};
|
||||
buffer<int, 1> c_buf{r};
|
||||
|
||||
// a ---- c --- d
|
||||
// b __/
|
||||
|
||||
q.submit([&](handler& h) {
|
||||
accessor a(a_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
a[idx] = idx; });
|
||||
});
|
||||
q.submit([&](handler& h) {
|
||||
accessor b(b_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
b[idx] = -idx; });
|
||||
});
|
||||
q.submit([&](handler& h) {
|
||||
accessor a(a_buf, h, read_only);
|
||||
accessor b(b_buf, h, read_only);
|
||||
accessor c(c_buf, h, write_only);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
c[idx] = a[idx] + b[idx]; });
|
||||
});
|
||||
q.submit([&](handler& h) {
|
||||
accessor c(c_buf, h, read_write);
|
||||
h.parallel_for(r, [=](auto idx) {
|
||||
c[idx] += 1; });
|
||||
}).wait();
|
||||
}
|
||||
std::cout << "DONE.\n";
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
#define SIZE 1024
|
||||
|
||||
using namespace cl::sycl;
|
||||
|
||||
int main() {
|
||||
// Initialize container.
|
||||
std::array<int, SIZE> a, b, c;
|
||||
for (int i = 0; i<SIZE; ++i) {
|
||||
a[i] = i + 1;
|
||||
b[i] = -i;
|
||||
c[i] = 0;
|
||||
}
|
||||
{
|
||||
std::cout << "\nAvailable devices:\n";
|
||||
// Report available devices.
|
||||
auto platforms = platform::get_platforms();
|
||||
for (auto &platform : platforms) {
|
||||
std::cout << "Platform: "
|
||||
<< platform.get_info<info::platform::name>() << std::endl;
|
||||
auto devices = platform.get_devices();
|
||||
for (auto &device : devices ) {
|
||||
std::cout << " Device: "
|
||||
<< device.get_info<info::device::name>()
|
||||
<< std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
range<1> r{SIZE};
|
||||
gpu_selector selector;
|
||||
|
||||
queue q(selector);
|
||||
|
||||
// Print out the device information.
|
||||
std::cout << "\nRunning on device: "
|
||||
<< q.get_device().get_info<info::device::name>() << "\n";
|
||||
|
||||
buffer<int, 1> a_buf(a.data(), r);
|
||||
buffer<int, 1> b_buf(b.data(), r);
|
||||
buffer<int, 1> c_buf(c.data(), r);
|
||||
q.submit([&](auto &h) {
|
||||
accessor a(a_buf, h, read_only);
|
||||
accessor b(b_buf, h, read_only);
|
||||
accessor c(c_buf, h, write_only);
|
||||
h.parallel_for(r,[=](id<1> idx) {
|
||||
c[idx] = a[idx] + b[idx];
|
||||
});
|
||||
}).wait();
|
||||
}
|
||||
std::cout << "DONE.\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
//==============================================================
|
||||
// Copyright (c) 2020 Intel Corporation
|
||||
//
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
// =============================================================
|
||||
|
||||
#include <CL/sycl.hpp>
|
||||
#define SIZE 1024
|
||||
|
||||
using namespace cl::sycl;
|
||||
|
||||
int main() {
|
||||
std::array<int, SIZE> a, b, c;
|
||||
for (int i = 0; i<SIZE; ++i) {
|
||||
a[i] = i + 1;
|
||||
b[i] = -i;
|
||||
c[i] = 0;
|
||||
}
|
||||
{
|
||||
range<1> r{SIZE};
|
||||
queue q;
|
||||
buffer<int, 1> a_buf(a.data(), r);
|
||||
buffer<int, 1> b_buf(b.data(), r);
|
||||
buffer<int, 1> c_buf(c.data(), r);
|
||||
q.submit([&](handler &h) {
|
||||
accessor a(a_buf, h, read_only);
|
||||
accessor b(b_buf, h, read_only);
|
||||
accessor c(c_buf, h, write_only);
|
||||
h.parallel_for(r,[=](id<1> idx) {
|
||||
c[idx] = a[idx] + b[idx];
|
||||
});
|
||||
}).wait();
|
||||
}
|
||||
std::cout << "DONE.\n";
|
||||
return 0;
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
macro(set_common_project_settings required_components)
|
||||
# Path to common headers
|
||||
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/../../)
|
||||
|
||||
if (NOT TARGET TBB::tbb)
|
||||
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/../../common/cmake/modules)
|
||||
find_package(TBB REQUIRED COMPONENTS ${required_components})
|
||||
endif()
|
||||
find_package(Threads REQUIRED)
|
||||
|
||||
# ---------------------------------------------------------------------------------------------------------
|
||||
# Handle C++ standard version.
|
||||
if (NOT MSVC) # no need to cover MSVC as it uses C++14 by default.
|
||||
if (NOT CMAKE_CXX_STANDARD)
|
||||
set(CMAKE_CXX_STANDARD 11)
|
||||
endif()
|
||||
if (CMAKE_CXX${CMAKE_CXX_STANDARD}_STANDARD_COMPILE_OPTION) # if standard option was detected by CMake
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
set(CMAKE_CXX_EXTENSIONS OFF) # use -std=c++... instead of -std=gnu++...
|
||||
# ---------------------------------------------------------------------------------------------------------
|
||||
endmacro()
|
||||
|
||||
macro(add_execution_target TARGET_NAME TARGET_DEPENDENCIES EXECUTABLE ARGS)
|
||||
if (WIN32)
|
||||
add_custom_target(${TARGET_NAME} set "PATH=$<TARGET_FILE_DIR:TBB::tbb>\\;$ENV{PATH}" & ${EXECUTABLE} ${ARGS})
|
||||
else()
|
||||
add_custom_target(${TARGET_NAME} ${EXECUTABLE} ${ARGS})
|
||||
endif()
|
||||
|
||||
add_dependencies(${TARGET_NAME} ${TARGET_DEPENDENCIES})
|
||||
endmacro()
|
||||
@@ -1,89 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
include(FindPackageHandleStandardArgs)
|
||||
|
||||
# Firstly search for TBB in config mode (i.e. search for TBBConfig.cmake).
|
||||
find_package(TBB QUIET CONFIG)
|
||||
if (TBB_FOUND)
|
||||
find_package_handle_standard_args(TBB CONFIG_MODE)
|
||||
return()
|
||||
endif()
|
||||
|
||||
if (NOT TBB_FIND_COMPONENTS)
|
||||
set(TBB_FIND_COMPONENTS tbb tbbmalloc)
|
||||
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
|
||||
set(TBB_FIND_REQUIRED_${_tbb_component} 1)
|
||||
endforeach()
|
||||
endif()
|
||||
|
||||
if (WIN32)
|
||||
list(APPEND ADDITIONAL_LIB_DIRS ENV PATH ENV LIB)
|
||||
list(APPEND ADDITIONAL_INCLUDE_DIRS ENV INCLUDE ENV CPATH)
|
||||
else()
|
||||
list(APPEND ADDITIONAL_LIB_DIRS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH ENV DYLD_LIBRARY_PATH)
|
||||
list(APPEND ADDITIONAL_INCLUDE_DIRS ENV CPATH ENV C_INCLUDE_PATH ENV CPLUS_INCLUDE_PATH ENV INCLUDE_PATH)
|
||||
endif()
|
||||
|
||||
find_path(_tbb_include_dir NAMES tbb/tbb.h PATHS ${ADDITIONAL_INCLUDE_DIRS})
|
||||
|
||||
if (_tbb_include_dir)
|
||||
# TODO: consider TBB_VERSION handling
|
||||
set(_TBB_BUILD_MODES RELEASE DEBUG)
|
||||
set(_TBB_DEBUG_SUFFIX _debug)
|
||||
|
||||
foreach (_tbb_component ${TBB_FIND_COMPONENTS})
|
||||
if (NOT TARGET TBB::${_tbb_component})
|
||||
add_library(TBB::${_tbb_component} SHARED IMPORTED)
|
||||
set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY INTERFACE_INCLUDE_DIRECTORIES ${_tbb_include_dir})
|
||||
|
||||
foreach(_TBB_BUILD_MODE ${_TBB_BUILD_MODES})
|
||||
set(_tbb_component_lib_name ${_tbb_component}${_TBB_${_TBB_BUILD_MODE}_SUFFIX})
|
||||
if (WIN32)
|
||||
find_library(${_tbb_component_lib_name}_lib ${_tbb_component_lib_name} PATHS ${ADDITIONAL_LIB_DIRS})
|
||||
find_file(${_tbb_component_lib_name}_dll ${_tbb_component_lib_name}.dll PATHS ${ADDITIONAL_LIB_DIRS})
|
||||
|
||||
set_target_properties(TBB::${_tbb_component} PROPERTIES
|
||||
IMPORTED_LOCATION_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_dll}"
|
||||
IMPORTED_IMPLIB_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_lib}"
|
||||
)
|
||||
else()
|
||||
find_library(${_tbb_component_lib_name}_so ${_tbb_component_lib_name} PATHS ${ADDITIONAL_LIB_DIRS})
|
||||
|
||||
set_target_properties(TBB::${_tbb_component} PROPERTIES
|
||||
IMPORTED_LOCATION_${_TBB_BUILD_MODE} "${${_tbb_component_lib_name}_so}"
|
||||
)
|
||||
endif()
|
||||
if (${_tbb_component_lib_name}_lib AND ${_tbb_component_lib_name}_dll OR ${_tbb_component_lib_name}_so)
|
||||
set_property(TARGET TBB::${_tbb_component} APPEND PROPERTY IMPORTED_CONFIGURATIONS ${_TBB_BUILD_MODE})
|
||||
list(APPEND TBB_IMPORTED_TARGETS TBB::${_tbb_component})
|
||||
set(TBB_${_tbb_component}_FOUND 1)
|
||||
endif()
|
||||
unset(${_tbb_component_lib_name}_lib CACHE)
|
||||
unset(${_tbb_component_lib_name}_dll CACHE)
|
||||
unset(${_tbb_component_lib_name}_so CACHE)
|
||||
unset(_tbb_component_lib_name)
|
||||
endforeach()
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_TBB_BUILD_MODESS)
|
||||
unset(_TBB_DEBUG_SUFFIX)
|
||||
endif()
|
||||
unset(_tbb_include_dir CACHE)
|
||||
|
||||
list(REMOVE_DUPLICATES TBB_IMPORTED_TARGETS)
|
||||
|
||||
find_package_handle_standard_args(TBB
|
||||
REQUIRED_VARS TBB_IMPORTED_TARGETS
|
||||
HANDLE_COMPONENTS)
|
||||
@@ -1,127 +0,0 @@
|
||||
# Copyright (c) 2020-2021 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.
|
||||
|
||||
cmake_minimum_required(VERSION 3.1)
|
||||
|
||||
set(EXAMPLES_UI_MODE "con" CACHE STRING "EXAMPLES_UI_MODE")
|
||||
|
||||
if (WIN32)
|
||||
set_property(CACHE EXAMPLES_UI_MODE PROPERTY STRINGS "con" "gdi" "d2d")
|
||||
elseif (APPLE)
|
||||
set_property(CACHE EXAMPLES_UI_MODE PROPERTY STRINGS "con" "mac")
|
||||
else()
|
||||
set_property(CACHE EXAMPLES_UI_MODE PROPERTY STRINGS "con" "x")
|
||||
endif()
|
||||
|
||||
get_property(_available_ui_modes CACHE EXAMPLES_UI_MODE PROPERTY STRINGS)
|
||||
|
||||
list(FIND _available_ui_modes ${EXAMPLES_UI_MODE} _find_index)
|
||||
if (NOT _find_index EQUAL -1)
|
||||
add_library(UI_LIB_${PROJECT_NAME} STATIC ${CMAKE_CURRENT_LIST_DIR}/${EXAMPLES_UI_MODE}video.cpp)
|
||||
|
||||
if (EXAMPLES_UI_MODE STREQUAL "mac")
|
||||
enable_language(C)
|
||||
add_library(UI_LIB_OBJECT_${PROJECT_NAME} OBJECT
|
||||
${CMAKE_CURRENT_LIST_DIR}/xcode/tbbExample/main.m
|
||||
${CMAKE_CURRENT_LIST_DIR}/xcode/tbbExample/OpenGLView.m
|
||||
${CMAKE_CURRENT_LIST_DIR}/xcode/tbbExample/tbbAppDelegate.m
|
||||
)
|
||||
target_sources(UI_LIB_${PROJECT_NAME} PUBLIC $<TARGET_OBJECTS:UI_LIB_OBJECT_${PROJECT_NAME}>)
|
||||
endif()
|
||||
else()
|
||||
string(REPLACE ";" ", " _available_ui_modes "${_available_ui_modes}")
|
||||
message(FATAL_ERROR
|
||||
"Selected UI mode (${EXAMPLES_UI_MODE}) is not supported on ${CMAKE_SYSTEM_NAME}.
|
||||
Supported UI modes: ${_available_ui_modes}"
|
||||
)
|
||||
endif()
|
||||
|
||||
macro(set_gdi_ui_project_settings)
|
||||
find_program(RC rc REQUIRED)
|
||||
add_custom_command(TARGET UI_LIB_${PROJECT_NAME} PRE_BUILD COMMAND
|
||||
${RC} /r -fo ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.res ${PROJECT_SOURCE_DIR}/gui/${PROJECT_NAME}.rc
|
||||
)
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES WIN32_EXECUTABLE TRUE)
|
||||
if (COMMAND target_link_options)
|
||||
target_link_options(UI_LIB_${PROJECT_NAME} PUBLIC ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.res)
|
||||
else()
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES LINK_FLAGS ${PROJECT_BINARY_DIR}/${PROJECT_NAME}.res)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(set_d2d_ui_project_settings)
|
||||
set_gdi_ui_project_settings()
|
||||
|
||||
if (IS_DIRECTORY $ENV{DXSDK_DIR})
|
||||
target_include_directories(UI_LIB_${PROJECT_NAME} PUBLIC $ENV{DXSDK_DIR}\\include)
|
||||
target_link_directories(UI_LIB_${PROJECT_NAME} PUBLIC $ENV{DXSDK_DIR}\\lib\\x64)
|
||||
else()
|
||||
message(FATAL_ERROR "Cannot find the DirectX library (required by the 'd2d' UI mode)")
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(set_x_ui_project_settings)
|
||||
find_package(X11 REQUIRED)
|
||||
target_link_libraries(UI_LIB_${PROJECT_NAME} PUBLIC ${X11_LIBRARIES})
|
||||
target_include_directories(UI_LIB_${PROJECT_NAME} PUBLIC ${X11_INCLUDE_DIR})
|
||||
|
||||
find_library(LIB_Xext Xext PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH ENV DYLD_LIBRARY_PATH)
|
||||
if (LIB_Xext)
|
||||
target_link_libraries(UI_LIB_${PROJECT_NAME} PUBLIC ${LIB_Xext})
|
||||
else()
|
||||
target_compile_definitions(UI_LIB_${PROJECT_NAME} PUBLIC -DX_NOSHMEM)
|
||||
endif()
|
||||
endmacro()
|
||||
|
||||
macro(set_mac_ui_project_settings)
|
||||
find_package(OpenGL REQUIRED)
|
||||
|
||||
find_library(FOUNDATION_LIBRARY Foundation PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH ENV DYLD_LIBRARY_PATH)
|
||||
if (NOT FOUNDATION_LIBRARY)
|
||||
message(FATAL_ERROR "Cannot find the Foundation library (required by the 'mac' UI mode)")
|
||||
endif()
|
||||
|
||||
find_library(COCOA_LIBRARY Cocoa PATHS ENV LIBRARY_PATH ENV LD_LIBRARY_PATH ENV DYLD_LIBRARY_PATH)
|
||||
if (NOT COCOA_LIBRARY)
|
||||
message(FATAL_ERROR "Cannot find the Cocoa library (required by the 'mac' UI mode)")
|
||||
endif()
|
||||
|
||||
target_link_libraries(UI_LIB_${PROJECT_NAME} PUBLIC ${OPENGL_LIBRARIES} ${FOUNDATION_LIBRARY} ${COCOA_LIBRARY})
|
||||
target_include_directories(UI_LIB_${PROJECT_NAME} PUBLIC ${OPENGL_INCLUDE_DIR})
|
||||
|
||||
file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MacUI/${PROJECT_NAME}.app/Contents/Resources)
|
||||
file(MAKE_DIRECTORY ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MacUI/${PROJECT_NAME}.app/Contents/MacOS)
|
||||
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../../common/gui/xcode/tbbExample/PkgInfo DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MacUI/${PROJECT_NAME}.app/Contents)
|
||||
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/../../common/gui/xcode/tbbExample/en.lproj DESTINATION ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MacUI/${PROJECT_NAME}.app/Contents/Resources)
|
||||
configure_file(${CMAKE_CURRENT_SOURCE_DIR}/../../common/gui/xcode/tbbExample/tbbExample-Info.plist ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/MacUI/${PROJECT_NAME}.app/Contents/Info.plist COPYONLY)
|
||||
|
||||
set_target_properties(${PROJECT_NAME} PROPERTIES PREFIX "MacUI/${PROJECT_NAME}.app/Contents/MacOS/")
|
||||
endmacro()
|
||||
|
||||
if (NOT _find_index EQUAL -1)
|
||||
if ("${EXAMPLES_UI_MODE}" STREQUAL "gdi")
|
||||
set_gdi_ui_project_settings()
|
||||
elseif ("${EXAMPLES_UI_MODE}" STREQUAL "d2d")
|
||||
set_d2d_ui_project_settings()
|
||||
elseif ("${EXAMPLES_UI_MODE}" STREQUAL "mac")
|
||||
set_mac_ui_project_settings()
|
||||
elseif ("${EXAMPLES_UI_MODE}" STREQUAL "x")
|
||||
set_x_ui_project_settings()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
unset(_available_ui_modes)
|
||||
unset(_find_index)
|
||||
@@ -1,149 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
|
||||
#include "video.hpp"
|
||||
|
||||
unsigned int *g_pImg = 0;
|
||||
int g_sizex, g_sizey;
|
||||
static video *g_video = 0;
|
||||
static int g_fps = 0;
|
||||
|
||||
#if _WIN32 || _WIN64
|
||||
|
||||
static DWORD g_msec = 0;
|
||||
|
||||
#ifdef _WINDOWS
|
||||
HINSTANCE video::win_hInstance = 0;
|
||||
int video::win_iCmdShow = 0;
|
||||
void video::win_set_class(WNDCLASSEX &wcex) {}
|
||||
void video::win_load_accelerators(int idc) {}
|
||||
#endif //_WINDOWS
|
||||
|
||||
#else
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
struct timeval g_time;
|
||||
#endif //_WIN32||_WIN64
|
||||
|
||||
#define CALC_FPS_ENABLED ((WINAPI_FAMILY != WINAPI_FAMILY_APP) && (!__ANDROID__))
|
||||
|
||||
video::video()
|
||||
// OpenGL* RGBA byte order for little-endian CPU
|
||||
: depth(24),
|
||||
red_shift(0),
|
||||
green_shift(8),
|
||||
blue_shift(16),
|
||||
red_mask(0xff),
|
||||
green_mask(0xff00),
|
||||
blue_mask(0xff0000) {
|
||||
assert(g_video == 0);
|
||||
g_video = this;
|
||||
title = "Video";
|
||||
updating = calc_fps = false;
|
||||
}
|
||||
|
||||
bool video::init_window(int x, int y) {
|
||||
g_sizex = x;
|
||||
g_sizey = y;
|
||||
g_pImg = new unsigned int[x * y];
|
||||
running = true;
|
||||
return false;
|
||||
}
|
||||
|
||||
bool video::init_console() {
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
#if CALC_FPS_ENABLED
|
||||
if (calc_fps) {
|
||||
double fps = g_fps;
|
||||
#if _WIN32 || _WIN64
|
||||
fps /= (GetTickCount() - g_msec) / 1000.0;
|
||||
#else
|
||||
struct timezone tz;
|
||||
struct timeval end_time;
|
||||
gettimeofday(&end_time, &tz);
|
||||
fps /= (end_time.tv_sec + 1.0 * end_time.tv_usec / 1000000.0) -
|
||||
(g_time.tv_sec + 1.0 * g_time.tv_usec / 1000000.0);
|
||||
#endif
|
||||
printf("%s: %.1f fps\n", title, fps);
|
||||
}
|
||||
#endif
|
||||
g_video = 0;
|
||||
running = false;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
if (g_video)
|
||||
terminate();
|
||||
}
|
||||
|
||||
//! Count and display FPS count in titlebar
|
||||
bool video::next_frame() {
|
||||
#if CALC_FPS_ENABLED
|
||||
if (calc_fps) {
|
||||
if (!g_fps) {
|
||||
#if _WIN32 || _WIN64
|
||||
g_msec = GetTickCount();
|
||||
#else
|
||||
struct timezone tz;
|
||||
gettimeofday(&g_time, &tz);
|
||||
#endif
|
||||
}
|
||||
g_fps++;
|
||||
}
|
||||
#endif
|
||||
return running;
|
||||
}
|
||||
|
||||
//! Do standard loop
|
||||
void video::main_loop() {
|
||||
on_process();
|
||||
}
|
||||
|
||||
//! Change window title
|
||||
void video::show_title() {}
|
||||
|
||||
///////////////////////////////////////////// public methods of video class ///////////////////////
|
||||
|
||||
drawing_area::drawing_area(int x, int y, int sizex, int sizey)
|
||||
: base_index(y * g_sizex + x),
|
||||
max_index(g_sizex * g_sizey),
|
||||
index_stride(g_sizex),
|
||||
pixel_depth(24),
|
||||
ptr32(g_pImg),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < g_sizex);
|
||||
assert(y < g_sizey);
|
||||
assert(x + sizex <= g_sizex);
|
||||
assert(y + sizey <= g_sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
void drawing_area::update() {}
|
||||
@@ -1,202 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
// common Windows parts
|
||||
#include "winvideo.hpp"
|
||||
|
||||
// and another headers
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
#include <dxsdkver.h>
|
||||
#if _DXSDK_PRODUCT_MAJOR < 9
|
||||
#error DXSDK Version 9 and above required.
|
||||
#endif
|
||||
#include <d2d1.h>
|
||||
#include <d2d1helper.h>
|
||||
#pragma comment(lib, "d2d1.lib")
|
||||
|
||||
ID2D1Factory *m_pD2DFactory;
|
||||
ID2D1HwndRenderTarget *m_pRenderTarget;
|
||||
ID2D1Bitmap *m_pBitmap;
|
||||
D2D1_SIZE_U bitmapSize;
|
||||
|
||||
HANDLE g_hVSync;
|
||||
|
||||
#include <DXErr.h>
|
||||
#pragma comment(lib, "DxErr.lib")
|
||||
|
||||
//! Create a dialog box and tell the user what went wrong
|
||||
bool DisplayError(LPSTR lpstrErr, HRESULT hres) {
|
||||
if (hres != S_OK) {
|
||||
static bool InError = false;
|
||||
int retval = 0;
|
||||
if (!InError) {
|
||||
InError = true;
|
||||
const char *message = hres ? DXGetErrorString(hres) : 0;
|
||||
retval =
|
||||
MessageBoxA(g_hAppWnd, lpstrErr, hres ? message : "Error!", MB_OK | MB_ICONERROR);
|
||||
InError = false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void DrawBitmap() {
|
||||
HRESULT hr = S_OK;
|
||||
if (m_pRenderTarget) {
|
||||
m_pRenderTarget->BeginDraw();
|
||||
if (m_pBitmap)
|
||||
hr = m_pBitmap->CopyFromMemory(NULL, (BYTE *)g_pImg, 4 * g_sizex);
|
||||
DisplayError("DrawBitmap error", hr);
|
||||
m_pRenderTarget->DrawBitmap(m_pBitmap);
|
||||
m_pRenderTarget->EndDraw();
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
inline void mouse(int k, LPARAM lParam) {
|
||||
int x = (int)LOWORD(lParam);
|
||||
int y = (int)HIWORD(lParam);
|
||||
RECT rc;
|
||||
GetClientRect(g_hAppWnd, &rc);
|
||||
g_video->on_mouse(x * g_sizex / (rc.right - rc.left), y * g_sizey / (rc.bottom - rc.top), k);
|
||||
}
|
||||
|
||||
//! Win event processing function
|
||||
LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (iMsg) {
|
||||
case WM_MOVE:
|
||||
// Check to make sure our window exists before we tell it to repaint.
|
||||
// This will fail the first time (while the window is being created).
|
||||
if (hwnd) {
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
UpdateWindow(hwnd);
|
||||
}
|
||||
return 0L;
|
||||
|
||||
case WM_SIZE:
|
||||
case WM_PAINT:
|
||||
if (g_video->running && g_video->updating) {
|
||||
DrawBitmap();
|
||||
Sleep(0);
|
||||
}
|
||||
break;
|
||||
// Process all mouse and keyboard events
|
||||
case WM_LBUTTONDOWN: mouse(1, lParam); break;
|
||||
case WM_LBUTTONUP: mouse(-1, lParam); break;
|
||||
case WM_RBUTTONDOWN: mouse(2, lParam); break;
|
||||
case WM_RBUTTONUP: mouse(-2, lParam); break;
|
||||
case WM_MBUTTONDOWN: mouse(3, lParam); break;
|
||||
case WM_MBUTTONUP: mouse(-3, lParam); break;
|
||||
case WM_CHAR: g_video->on_key((int)wParam); break;
|
||||
|
||||
// some useless stuff
|
||||
case WM_ERASEBKGND: return 1; // keeps erase-background events from happening, reduces chop
|
||||
case WM_DISPLAYCHANGE: return 0;
|
||||
|
||||
// Now, shut down the window...
|
||||
case WM_DESTROY: PostQuitMessage(0); return 0;
|
||||
}
|
||||
// call user defined proc, if exists
|
||||
return g_pUserProc ? g_pUserProc(hwnd, iMsg, wParam, lParam)
|
||||
: DefWindowProc(hwnd, iMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
bool video::init_window(int sizex, int sizey) {
|
||||
assert(win_hInstance != 0);
|
||||
g_sizex = sizex;
|
||||
g_sizey = sizey;
|
||||
if (!WinInit(win_hInstance, win_iCmdShow, gWndClass, title, false)) {
|
||||
DisplayError("Unable to initialize the program's window.");
|
||||
return false;
|
||||
}
|
||||
ShowWindow(g_hAppWnd, SW_SHOW);
|
||||
g_pImg = new unsigned int[sizex * sizey];
|
||||
|
||||
HRESULT hr = S_OK;
|
||||
|
||||
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &m_pD2DFactory);
|
||||
// Create a Direct2D render target.
|
||||
if (SUCCEEDED(hr) && !m_pRenderTarget) {
|
||||
RECT rc;
|
||||
GetClientRect(g_hAppWnd, &rc);
|
||||
|
||||
bitmapSize = D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top);
|
||||
|
||||
hr = m_pD2DFactory->CreateHwndRenderTarget(
|
||||
D2D1::RenderTargetProperties(),
|
||||
D2D1::HwndRenderTargetProperties(g_hAppWnd, bitmapSize),
|
||||
&m_pRenderTarget);
|
||||
if (SUCCEEDED(hr) && !m_pBitmap) {
|
||||
D2D1_PIXEL_FORMAT pixelFormat =
|
||||
D2D1::PixelFormat(DXGI_FORMAT_B8G8R8A8_UNORM, D2D1_ALPHA_MODE_IGNORE);
|
||||
D2D1_BITMAP_PROPERTIES bitmapProperties;
|
||||
bitmapProperties.pixelFormat = pixelFormat;
|
||||
m_pRenderTarget->GetDpi(&bitmapProperties.dpiX, &bitmapProperties.dpiY);
|
||||
m_pRenderTarget->CreateBitmap(bitmapSize, bitmapProperties, &m_pBitmap);
|
||||
m_pRenderTarget->DrawBitmap(m_pBitmap);
|
||||
}
|
||||
}
|
||||
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
if (m_pBitmap)
|
||||
m_pBitmap->Release();
|
||||
if (m_pRenderTarget)
|
||||
m_pRenderTarget->Release();
|
||||
if (m_pD2DFactory)
|
||||
m_pD2DFactory->Release();
|
||||
g_video = 0;
|
||||
running = false;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////// drawing area constructor & destructor /////////////
|
||||
|
||||
drawing_area::drawing_area(int x, int y, int sizex, int sizey)
|
||||
: base_index(y * g_sizex + x),
|
||||
max_index(g_sizex * g_sizey),
|
||||
index_stride(g_sizex),
|
||||
pixel_depth(24),
|
||||
ptr32(g_pImg),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < g_sizex);
|
||||
assert(y < g_sizey);
|
||||
assert(x + sizex <= g_sizex);
|
||||
assert(y + sizey <= g_sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
void drawing_area::update() {
|
||||
if (g_video->updating) {
|
||||
RECT r;
|
||||
r.left = start_x;
|
||||
r.right = start_x + size_x;
|
||||
r.top = start_y;
|
||||
r.bottom = start_y + size_y;
|
||||
InvalidateRect(g_hAppWnd, &r, false);
|
||||
}
|
||||
}
|
||||
@@ -1,168 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
// common Windows parts
|
||||
#include "winvideo.hpp"
|
||||
// include GDI+ headers
|
||||
#include <gdiplus.h>
|
||||
// and another headers
|
||||
#include <stdio.h>
|
||||
|
||||
// tag linking library
|
||||
#pragma comment(lib, "gdiplus.lib")
|
||||
|
||||
// global specific variables
|
||||
Gdiplus::Bitmap* g_pBitmap; // main drawing bitmap
|
||||
ULONG_PTR gdiplusToken;
|
||||
Gdiplus::GdiplusStartupInput gdiplusStartupInput; // GDI+
|
||||
|
||||
//! display system error
|
||||
bool DisplayError(LPSTR lpstrErr, HRESULT hres) {
|
||||
static bool InError = false;
|
||||
int retval = 0;
|
||||
if (!InError) {
|
||||
InError = true;
|
||||
LPCSTR lpMsgBuf;
|
||||
if (!hres)
|
||||
hres = GetLastError();
|
||||
FormatMessage(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM |
|
||||
FORMAT_MESSAGE_IGNORE_INSERTS,
|
||||
NULL,
|
||||
hres,
|
||||
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
|
||||
(LPTSTR)&lpMsgBuf,
|
||||
0,
|
||||
NULL);
|
||||
retval = MessageBox(g_hAppWnd, lpstrErr, lpMsgBuf, MB_OK | MB_ICONERROR);
|
||||
LocalFree((HLOCAL)lpMsgBuf);
|
||||
InError = false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Win event processing function
|
||||
LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam) {
|
||||
switch (iMsg) {
|
||||
case WM_MOVE:
|
||||
// Check to make sure our window exists before we tell it to repaint.
|
||||
// This will fail the first time (while the window is being created).
|
||||
if (hwnd) {
|
||||
InvalidateRect(hwnd, NULL, FALSE);
|
||||
UpdateWindow(hwnd);
|
||||
}
|
||||
return 0L;
|
||||
|
||||
case WM_PAINT: {
|
||||
PAINTSTRUCT ps;
|
||||
Gdiplus::Graphics graphics(BeginPaint(hwnd, &ps));
|
||||
// redraw just requested area. This call is as fast as simple DrawImage() call.
|
||||
if (g_video->updating)
|
||||
graphics.DrawImage(g_pBitmap,
|
||||
ps.rcPaint.left,
|
||||
ps.rcPaint.top,
|
||||
ps.rcPaint.left,
|
||||
ps.rcPaint.top,
|
||||
ps.rcPaint.right,
|
||||
ps.rcPaint.bottom,
|
||||
Gdiplus::UnitPixel);
|
||||
EndPaint(hwnd, &ps);
|
||||
}
|
||||
return 0L;
|
||||
|
||||
// Process all mouse and keyboard events
|
||||
case WM_LBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 1); break;
|
||||
case WM_LBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -1); break;
|
||||
case WM_RBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 2); break;
|
||||
case WM_RBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -2); break;
|
||||
case WM_MBUTTONDOWN: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), 3); break;
|
||||
case WM_MBUTTONUP: g_video->on_mouse((int)LOWORD(lParam), (int)HIWORD(lParam), -3); break;
|
||||
case WM_CHAR: g_video->on_key((int)wParam); break;
|
||||
|
||||
// some useless stuff
|
||||
case WM_ERASEBKGND: return 1; // keeps erase-background events from happening, reduces chop
|
||||
case WM_DISPLAYCHANGE: return 0;
|
||||
|
||||
// Now, shut down the window...
|
||||
case WM_DESTROY: PostQuitMessage(0); return 0;
|
||||
}
|
||||
// call user defined proc, if exists
|
||||
return g_pUserProc ? g_pUserProc(hwnd, iMsg, wParam, lParam)
|
||||
: DefWindowProc(hwnd, iMsg, wParam, lParam);
|
||||
}
|
||||
|
||||
///////////// video functions ////////////////
|
||||
|
||||
bool video::init_window(int sizex, int sizey) {
|
||||
assert(win_hInstance != 0);
|
||||
g_sizex = sizex;
|
||||
g_sizey = sizey;
|
||||
if (!WinInit(win_hInstance, win_iCmdShow, gWndClass, title, true)) {
|
||||
DisplayError("Unable to initialize the program's window.");
|
||||
return false;
|
||||
}
|
||||
ShowWindow(g_hAppWnd, SW_SHOW);
|
||||
Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);
|
||||
g_pImg = new unsigned int[sizex * sizey];
|
||||
g_pBitmap =
|
||||
new Gdiplus::Bitmap(g_sizex, g_sizey, 4 * g_sizex, PixelFormat32bppRGB, (BYTE*)g_pImg);
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
if (g_pBitmap) {
|
||||
delete g_pBitmap;
|
||||
g_pBitmap = 0;
|
||||
}
|
||||
Gdiplus::GdiplusShutdown(gdiplusToken);
|
||||
g_video = 0;
|
||||
running = false;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
//////////// drawing area constructor & destructor /////////////
|
||||
|
||||
drawing_area::drawing_area(int x, int y, int sizex, int sizey)
|
||||
: base_index(y * g_sizex + x),
|
||||
max_index(g_sizex * g_sizey),
|
||||
index_stride(g_sizex),
|
||||
pixel_depth(24),
|
||||
ptr32(g_pImg),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < g_sizex);
|
||||
assert(y < g_sizey);
|
||||
assert(x + sizex <= g_sizex);
|
||||
assert(y + sizey <= g_sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
void drawing_area::update() {
|
||||
if (g_video->updating) {
|
||||
RECT r;
|
||||
r.left = start_x;
|
||||
r.right = start_x + size_x;
|
||||
r.top = start_y;
|
||||
r.bottom = start_y + size_y;
|
||||
InvalidateRect(g_hAppWnd, &r, false);
|
||||
}
|
||||
}
|
||||
@@ -1,188 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#include "video.hpp"
|
||||
#include <cassert>
|
||||
#include <stdio.h>
|
||||
#include <iostream>
|
||||
#include <pthread.h>
|
||||
|
||||
unsigned int *g_pImg = 0;
|
||||
int g_sizex = 0, g_sizey = 0;
|
||||
static video *g_video = 0;
|
||||
static int g_fps = 0;
|
||||
char *window_title = NULL;
|
||||
#define WINDOW_TITLE_SIZE 256
|
||||
int cocoa_update = 0;
|
||||
|
||||
#include <sched.h>
|
||||
#include <sys/time.h>
|
||||
struct timeval g_time;
|
||||
|
||||
video::video()
|
||||
#if __ENVIRONMENT_IPHONE_OS_VERSION_MIN_REQUIRED__
|
||||
: depth(24),
|
||||
red_shift(0),
|
||||
green_shift(8),
|
||||
blue_shift(16),
|
||||
red_mask(0xff),
|
||||
green_mask(0xff00),
|
||||
blue_mask(0xff0000)
|
||||
#else
|
||||
: depth(24),
|
||||
red_shift(16),
|
||||
green_shift(8),
|
||||
blue_shift(0),
|
||||
red_mask(0xff0000),
|
||||
green_mask(0xff00),
|
||||
blue_mask(0xff)
|
||||
#endif
|
||||
{
|
||||
assert(g_video == 0);
|
||||
g_video = this;
|
||||
title = "Video";
|
||||
cocoa_update = 1;
|
||||
updating = true;
|
||||
calc_fps = false;
|
||||
}
|
||||
|
||||
bool video::init_window(int x, int y) {
|
||||
g_sizex = x;
|
||||
g_sizey = y;
|
||||
g_pImg = new unsigned int[x * y];
|
||||
if (window_title == NULL)
|
||||
window_title = (char *)malloc(WINDOW_TITLE_SIZE);
|
||||
strncpy(window_title, title, WINDOW_TITLE_SIZE - 1);
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool video::init_console() {
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
if (calc_fps) {
|
||||
double fps = g_fps;
|
||||
struct timezone tz;
|
||||
struct timeval end_time;
|
||||
gettimeofday(&end_time, &tz);
|
||||
fps /= (end_time.tv_sec + 1.0 * end_time.tv_usec / 1000000.0) -
|
||||
(g_time.tv_sec + 1.0 * g_time.tv_usec / 1000000.0);
|
||||
printf("%s: %.1f fps\n", title, fps);
|
||||
}
|
||||
g_video = 0;
|
||||
running = false;
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
}
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
if (g_video)
|
||||
terminate();
|
||||
}
|
||||
|
||||
//! Count and display FPS count in titlebar
|
||||
bool video::next_frame() {
|
||||
if (calc_fps) {
|
||||
if (!g_fps) {
|
||||
struct timezone tz;
|
||||
gettimeofday(&g_time, &tz);
|
||||
}
|
||||
g_fps++;
|
||||
}
|
||||
struct timezone tz;
|
||||
struct timeval now_time;
|
||||
gettimeofday(&now_time, &tz);
|
||||
double sec = ((now_time.tv_sec + 1.0 * now_time.tv_usec / 1000000.0) -
|
||||
(g_time.tv_sec + 1.0 * g_time.tv_usec / 1000000.0));
|
||||
if (sec > 1) {
|
||||
if (calc_fps) {
|
||||
memcpy(&g_time, &now_time, sizeof(g_time));
|
||||
int fps;
|
||||
fps = g_fps / sec;
|
||||
cocoa_update = (int)updating;
|
||||
snprintf(window_title,
|
||||
WINDOW_TITLE_SIZE,
|
||||
"%s%s: %d fps",
|
||||
title,
|
||||
updating ? "" : " (no updating)",
|
||||
int(fps));
|
||||
g_fps = 0;
|
||||
}
|
||||
}
|
||||
return running;
|
||||
}
|
||||
|
||||
void *thread_func(void *) {
|
||||
g_video->on_process();
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
extern "C" void on_mouse_func(int x, int y, int k) {
|
||||
g_video->on_mouse(x, y, k);
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" void on_key_func(int x) {
|
||||
g_video->on_key(x);
|
||||
return;
|
||||
}
|
||||
|
||||
extern "C" int cocoa_main(int argc, char *argv[]);
|
||||
//! Do standard loop
|
||||
void video::main_loop() {
|
||||
pthread_t handle;
|
||||
pthread_attr_t attr;
|
||||
pthread_attr_init(&attr);
|
||||
pthread_create(&handle, &attr, &thread_func, (void *)NULL);
|
||||
pthread_detach(handle);
|
||||
cocoa_main(0, NULL);
|
||||
}
|
||||
|
||||
//! Change window title
|
||||
void video::show_title() {
|
||||
if (title)
|
||||
strncpy(window_title, title, WINDOW_TITLE_SIZE);
|
||||
return;
|
||||
}
|
||||
|
||||
///////////////////////////////////////////// public methods of video class ///////////////////////
|
||||
|
||||
drawing_area::drawing_area(int x, int y, int sizex, int sizey)
|
||||
: base_index(y * g_sizex + x),
|
||||
max_index(g_sizex * g_sizey),
|
||||
index_stride(g_sizex),
|
||||
pixel_depth(24),
|
||||
ptr32(g_pImg),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < g_sizex);
|
||||
assert(y < g_sizey);
|
||||
assert(x + sizex <= g_sizex);
|
||||
assert(y + sizey <= g_sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
void drawing_area::update() {
|
||||
//nothing to do, updating via timer in cocoa part.
|
||||
}
|
||||
@@ -1,249 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#ifndef TBB_examples_video_H
|
||||
#define TBB_examples_video_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstddef>
|
||||
#if _MSC_VER
|
||||
#include <stddef.h> // for uintptr_t
|
||||
#else
|
||||
#include <stdint.h> // for uintptr_t
|
||||
#endif
|
||||
#if _WIN32 || _WIN64
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
typedef unsigned int color_t;
|
||||
typedef unsigned char colorcomp_t;
|
||||
typedef signed char depth_t;
|
||||
|
||||
//! Class for getting access to drawing memory
|
||||
class drawing_memory {
|
||||
uintptr_t my_address;
|
||||
|
||||
public:
|
||||
depth_t pixel_depth;
|
||||
int sizex, sizey;
|
||||
//! Get drawing memory
|
||||
inline char *get_address() const {
|
||||
return reinterpret_cast<char *>(my_address);
|
||||
}
|
||||
//! Get drawing memory size
|
||||
inline int get_size() const {
|
||||
return ((pixel_depth > 16) ? 4 : 2) * sizex * sizey;
|
||||
}
|
||||
//! Set drawing memory
|
||||
inline void set_address(char *mem) {
|
||||
my_address = reinterpret_cast<uintptr_t>(mem);
|
||||
}
|
||||
|
||||
friend class drawing_area;
|
||||
friend class video;
|
||||
};
|
||||
|
||||
//! Simple proxy class for managing of different video systems
|
||||
class video {
|
||||
//! colorspace information
|
||||
depth_t depth, red_shift, green_shift, blue_shift;
|
||||
color_t red_mask, green_mask, blue_mask;
|
||||
friend class drawing_area;
|
||||
|
||||
public:
|
||||
//! Constructor
|
||||
video();
|
||||
//! Destructor
|
||||
~video();
|
||||
//! member to set window name
|
||||
const char *title;
|
||||
//! true is enable to show fps
|
||||
bool calc_fps;
|
||||
//! if true: on windows fork processing thread for on_process(), on non-windows note that next_frame() is called concurrently.
|
||||
bool threaded;
|
||||
//! true while running within main_loop()
|
||||
bool running;
|
||||
//! if true, do gui updating
|
||||
bool updating;
|
||||
//! initialize graphical video system
|
||||
bool init_window(int sizex, int sizey);
|
||||
//! initialize console. returns true if console is available
|
||||
bool init_console();
|
||||
//! terminate video system
|
||||
void terminate();
|
||||
//! Do standard event & processing loop. Use threaded = true to separate event/updating loop from frame processing
|
||||
void main_loop();
|
||||
//! Process next frame
|
||||
bool next_frame();
|
||||
//! Change window title
|
||||
void show_title();
|
||||
//! translate RGB components into packed type
|
||||
inline color_t get_color(colorcomp_t red, colorcomp_t green, colorcomp_t blue) const;
|
||||
//! Get drawing memory descriptor
|
||||
inline drawing_memory get_drawing_memory() const;
|
||||
|
||||
//! code of the ESCape key
|
||||
static const int esc_key = 27;
|
||||
//! Mouse events handler.
|
||||
virtual void on_mouse(int x, int y, int key) {}
|
||||
//! Mouse events handler.
|
||||
virtual void on_key(int key) {}
|
||||
//! Main processing loop. Redefine with your own
|
||||
virtual void on_process() {
|
||||
while (next_frame())
|
||||
;
|
||||
}
|
||||
|
||||
#ifdef _WINDOWS
|
||||
//! Windows specific members
|
||||
//! if VIDEO_WINMAIN isn't defined then set this just before init() by arguments of WinMain
|
||||
static HINSTANCE win_hInstance;
|
||||
static int win_iCmdShow;
|
||||
//! optionally call it just before init() to set own. Use ascii strings convention
|
||||
void win_set_class(WNDCLASSEX &);
|
||||
//! load and set accelerator table from resources
|
||||
void win_load_accelerators(int idc);
|
||||
#endif
|
||||
};
|
||||
|
||||
//! Drawing class
|
||||
class drawing_area {
|
||||
const std::size_t base_index, max_index, index_stride;
|
||||
const depth_t pixel_depth;
|
||||
unsigned int *const ptr32;
|
||||
std::size_t index;
|
||||
|
||||
public:
|
||||
const int start_x, start_y, size_x, size_y;
|
||||
//! constructors
|
||||
drawing_area(int x, int y, int sizex, int sizey);
|
||||
inline drawing_area(int x, int y, int sizex, int sizey, const drawing_memory &dmem);
|
||||
//! destructor
|
||||
inline ~drawing_area();
|
||||
//! update the image
|
||||
void update();
|
||||
//! set current position. local_x could be bigger then size_x
|
||||
inline void set_pos(int local_x, int local_y);
|
||||
//! put pixel in current position with incremental address calculating to next right pixel
|
||||
inline void put_pixel(color_t color);
|
||||
//! draw pixel at position by packed color
|
||||
void set_pixel(int localx, int localy, color_t color) {
|
||||
set_pos(localx, localy);
|
||||
put_pixel(color);
|
||||
}
|
||||
};
|
||||
|
||||
extern int g_sizex;
|
||||
extern int g_sizey;
|
||||
extern unsigned int *g_pImg;
|
||||
|
||||
inline drawing_memory video::get_drawing_memory() const {
|
||||
drawing_memory dmem;
|
||||
dmem.pixel_depth = depth;
|
||||
dmem.my_address = reinterpret_cast<uintptr_t>(g_pImg);
|
||||
dmem.sizex = g_sizex;
|
||||
dmem.sizey = g_sizey;
|
||||
return dmem;
|
||||
}
|
||||
|
||||
inline color_t video::get_color(colorcomp_t red, colorcomp_t green, colorcomp_t blue) const {
|
||||
if (red_shift == 16) // only for depth == 24 && red_shift > blue_shift
|
||||
return (red << 16) | (green << 8) | blue;
|
||||
else if (depth >= 24)
|
||||
return
|
||||
#if __ANDROID__
|
||||
// Setting Alpha to 0xFF
|
||||
0xFF000000 |
|
||||
#endif
|
||||
(red << red_shift) | (green << green_shift) | (blue << blue_shift);
|
||||
else if (depth > 0) {
|
||||
depth_t bs = blue_shift, rs = red_shift;
|
||||
if (blue_shift < 0)
|
||||
blue >>= -bs, bs = 0;
|
||||
else /*red_shift < 0*/
|
||||
red >>= -rs, rs = 0;
|
||||
return ((red << rs) & red_mask) | ((green << green_shift) & green_mask) |
|
||||
((blue << bs) & blue_mask);
|
||||
}
|
||||
else { // UYVY colorspace
|
||||
unsigned y, u, v;
|
||||
y = red * 77 + green * 150 + blue * 29; // sum(77+150+29=256) * max(=255): limit->2^16
|
||||
u = (2048 + (blue << 3) - (y >> 5)) >> 4; // (limit->2^12)>>4
|
||||
v = (2048 + (red << 3) - (y >> 5)) >> 4;
|
||||
y = y >> 8;
|
||||
return u | (y << 8) | (v << 16) | (y << 24);
|
||||
}
|
||||
}
|
||||
|
||||
inline drawing_area::drawing_area(int x, int y, int sizex, int sizey, const drawing_memory &dmem)
|
||||
: base_index(y * dmem.sizex + x),
|
||||
max_index(dmem.sizex * dmem.sizey),
|
||||
index_stride(dmem.sizex),
|
||||
pixel_depth(dmem.pixel_depth),
|
||||
ptr32(reinterpret_cast<unsigned int *>(dmem.my_address)),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < dmem.sizex);
|
||||
assert(y < dmem.sizey);
|
||||
assert(x + sizex <= dmem.sizex);
|
||||
assert(y + sizey <= dmem.sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
inline void drawing_area::set_pos(int local_x, int local_y) {
|
||||
index = base_index + local_x + local_y * index_stride;
|
||||
}
|
||||
|
||||
inline void drawing_area::put_pixel(color_t color) {
|
||||
assert(index < max_index);
|
||||
if (pixel_depth > 16)
|
||||
ptr32[index++] = color;
|
||||
else if (pixel_depth > 0)
|
||||
((unsigned short *)ptr32)[index++] = (unsigned short)color;
|
||||
else { // UYVY colorspace
|
||||
if (index & 1)
|
||||
color >>= 16;
|
||||
((unsigned short *)ptr32)[index++] = (unsigned short)color;
|
||||
}
|
||||
}
|
||||
|
||||
inline drawing_area::~drawing_area() {}
|
||||
|
||||
#if defined(_WINDOWS) && (defined(VIDEO_WINMAIN) || defined(VIDEO_WINMAIN_ARGS))
|
||||
#include <cstdlib>
|
||||
//! define WinMain for subsystem:windows.
|
||||
#ifdef VIDEO_WINMAIN_ARGS
|
||||
int main(int, char *[]);
|
||||
#else
|
||||
int main();
|
||||
#endif
|
||||
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE, PSTR szCmdLine, int iCmdShow) {
|
||||
video::win_hInstance = hInstance;
|
||||
video::win_iCmdShow = iCmdShow;
|
||||
#ifdef VIDEO_WINMAIN_ARGS
|
||||
return main(__argc, __argv);
|
||||
#else
|
||||
return main();
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* TBB_examples_video_H */
|
||||
@@ -1,315 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
/////// Common internal implementation of Windows-specific stuff //////////////
|
||||
/////// Must be the first included header //////////////
|
||||
|
||||
#ifndef __WINVIDEO_H__
|
||||
#define __WINVIDEO_H__
|
||||
|
||||
#ifndef _CRT_SECURE_NO_DEPRECATE
|
||||
#define _CRT_SECURE_NO_DEPRECATE
|
||||
#endif
|
||||
// Check that the target Windows version has all API calls required.
|
||||
#ifndef _WIN32_WINNT
|
||||
#define _WIN32_WINNT 0x0400
|
||||
#endif
|
||||
#if _WIN32_WINNT < 0x0400
|
||||
#define YIELD_TO_THREAD() Sleep(0)
|
||||
#else
|
||||
#define YIELD_TO_THREAD() SwitchToThread()
|
||||
#endif
|
||||
#include "video.hpp"
|
||||
#include <fcntl.h>
|
||||
#include <io.h>
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#pragma comment(lib, "gdi32.lib")
|
||||
#pragma comment(lib, "user32.lib")
|
||||
|
||||
// maximum number of lines the output console should have
|
||||
static const WORD MAX_CONSOLE_LINES = 500;
|
||||
const COLORREF RGBKEY = RGB(8, 8, 16); // at least 8 for 16-bit palette
|
||||
HWND g_hAppWnd; // The program's window handle
|
||||
HANDLE g_handles[2] = { 0, 0 }; // thread and wake up event
|
||||
unsigned int *g_pImg = 0; // drawing memory
|
||||
int g_sizex, g_sizey;
|
||||
static video *g_video = 0;
|
||||
WNDPROC g_pUserProc = 0;
|
||||
HINSTANCE video::win_hInstance = 0;
|
||||
int video::win_iCmdShow = 0;
|
||||
static WNDCLASSEX *gWndClass = 0;
|
||||
static HACCEL hAccelTable = 0;
|
||||
static DWORD g_msec = 0;
|
||||
static int g_fps = 0, g_updates = 0, g_skips = 0;
|
||||
|
||||
bool DisplayError(LPSTR lpstrErr, HRESULT hres = 0); // always returns false
|
||||
LRESULT CALLBACK InternalWndProc(HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam);
|
||||
|
||||
//! Create window
|
||||
bool WinInit(HINSTANCE hInstance,
|
||||
int nCmdShow,
|
||||
WNDCLASSEX *uwc,
|
||||
const char *title,
|
||||
bool fixedsize) {
|
||||
WNDCLASSEX wndclass; // Our app's windows class
|
||||
if (uwc) {
|
||||
memcpy(&wndclass, uwc, sizeof(wndclass));
|
||||
g_pUserProc = uwc->lpfnWndProc;
|
||||
}
|
||||
else {
|
||||
memset(&wndclass, 0, sizeof(wndclass));
|
||||
wndclass.hCursor = LoadCursor(NULL, IDC_ARROW);
|
||||
wndclass.lpszClassName = title;
|
||||
}
|
||||
wndclass.cbSize = sizeof(wndclass);
|
||||
wndclass.hInstance = hInstance;
|
||||
wndclass.lpfnWndProc = InternalWndProc;
|
||||
wndclass.style |= CS_HREDRAW | CS_VREDRAW;
|
||||
wndclass.hbrBackground = CreateSolidBrush(RGBKEY);
|
||||
|
||||
if (!RegisterClassExA(&wndclass))
|
||||
return false;
|
||||
int xaddend = GetSystemMetrics(fixedsize ? SM_CXFIXEDFRAME : SM_CXFRAME) * 2;
|
||||
int yaddend = GetSystemMetrics(fixedsize ? SM_CYFIXEDFRAME : SM_CYFRAME) * 2 +
|
||||
GetSystemMetrics(SM_CYCAPTION);
|
||||
if (wndclass.lpszMenuName)
|
||||
yaddend += GetSystemMetrics(SM_CYMENU);
|
||||
|
||||
// Setup the new window's physical parameters - and tell Windows to create it
|
||||
g_hAppWnd = CreateWindowA(wndclass.lpszClassName, // Window class name
|
||||
title, // Window caption
|
||||
!fixedsize ? WS_OVERLAPPEDWINDOW : // Window style
|
||||
WS_OVERLAPPED | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
|
||||
CW_USEDEFAULT, // Initial x pos: use default placement
|
||||
0, // Initial y pos: not used here
|
||||
g_sizex + xaddend, // Initial x size
|
||||
g_sizey + yaddend, // Initial y size
|
||||
NULL, // parent window handle
|
||||
NULL, // window menu handle
|
||||
hInstance, // program instance handle
|
||||
NULL); // Creation parameters
|
||||
return g_hAppWnd != NULL;
|
||||
}
|
||||
|
||||
//! create console window with redirection
|
||||
static bool RedirectIOToConsole(void) {
|
||||
int hConHandle;
|
||||
size_t lStdHandle;
|
||||
CONSOLE_SCREEN_BUFFER_INFO coninfo;
|
||||
FILE *fp;
|
||||
// allocate a console for this app
|
||||
AllocConsole();
|
||||
|
||||
// set the screen buffer to be big enough to let us scroll text
|
||||
GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &coninfo);
|
||||
coninfo.dwSize.Y = MAX_CONSOLE_LINES;
|
||||
SetConsoleScreenBufferSize(GetStdHandle(STD_OUTPUT_HANDLE), coninfo.dwSize);
|
||||
|
||||
// redirect unbuffered STDOUT to the console
|
||||
lStdHandle = (size_t)GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
if (hConHandle <= 0)
|
||||
return false;
|
||||
fp = _fdopen(hConHandle, "w");
|
||||
*stdout = *fp;
|
||||
setvbuf(stdout, NULL, _IONBF, 0);
|
||||
|
||||
// redirect unbuffered STDERR to the console
|
||||
lStdHandle = (size_t)GetStdHandle(STD_ERROR_HANDLE);
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
if (hConHandle > 0) {
|
||||
fp = _fdopen(hConHandle, "w");
|
||||
*stderr = *fp;
|
||||
setvbuf(stderr, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
// redirect unbuffered STDIN to the console
|
||||
lStdHandle = (size_t)GetStdHandle(STD_INPUT_HANDLE);
|
||||
hConHandle = _open_osfhandle(lStdHandle, _O_TEXT);
|
||||
if (hConHandle > 0) {
|
||||
fp = _fdopen(hConHandle, "r");
|
||||
*stdin = *fp;
|
||||
setvbuf(stdin, NULL, _IONBF, 0);
|
||||
}
|
||||
|
||||
// make cout, wcout, cin, wcin, wcerr, cerr, wclog and clog
|
||||
// point to console as well
|
||||
std::ios::sync_with_stdio();
|
||||
return true;
|
||||
}
|
||||
|
||||
video::video()
|
||||
: depth(24),
|
||||
red_shift(16),
|
||||
green_shift(8),
|
||||
blue_shift(0),
|
||||
red_mask(0xff0000),
|
||||
green_mask(0xff00),
|
||||
blue_mask(0xff) {
|
||||
assert(g_video == 0);
|
||||
g_video = this;
|
||||
title = "Video";
|
||||
running = threaded = calc_fps = false;
|
||||
updating = true;
|
||||
}
|
||||
|
||||
//! optionally call it just before init() to set own
|
||||
void video::win_set_class(WNDCLASSEX &wcex) {
|
||||
gWndClass = &wcex;
|
||||
}
|
||||
|
||||
void video::win_load_accelerators(int idc) {
|
||||
hAccelTable = LoadAccelerators(win_hInstance, MAKEINTRESOURCE(idc));
|
||||
}
|
||||
|
||||
bool video::init_console() {
|
||||
if (RedirectIOToConsole()) {
|
||||
if (!g_pImg && g_sizex && g_sizey)
|
||||
g_pImg = new unsigned int[g_sizex * g_sizey];
|
||||
if (g_pImg)
|
||||
running = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
if (g_video)
|
||||
terminate();
|
||||
}
|
||||
|
||||
DWORD WINAPI thread_video(LPVOID lpParameter) {
|
||||
video *v = (video *)lpParameter;
|
||||
v->on_process();
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool loop_once(video *v) {
|
||||
// screen update notify
|
||||
if (int updates = g_updates) {
|
||||
g_updates = 0;
|
||||
if (g_video->updating) {
|
||||
g_skips += updates - 1;
|
||||
g_fps++;
|
||||
}
|
||||
else
|
||||
g_skips += updates;
|
||||
UpdateWindow(g_hAppWnd);
|
||||
}
|
||||
// update fps
|
||||
DWORD msec = GetTickCount();
|
||||
if (v->calc_fps && msec >= g_msec + 1000) {
|
||||
double sec = (msec - g_msec) / 1000.0;
|
||||
char buffer[256],
|
||||
n = _snprintf(buffer, 128, "%s: %d fps", v->title, int(double(g_fps + g_skips) / sec));
|
||||
if (g_skips)
|
||||
_snprintf(buffer + n,
|
||||
128,
|
||||
" - %d skipped = %d updates",
|
||||
int(g_skips / sec),
|
||||
int(g_fps / sec));
|
||||
SetWindowTextA(g_hAppWnd, buffer);
|
||||
g_msec = msec;
|
||||
g_skips = g_fps = 0;
|
||||
}
|
||||
// event processing, including painting
|
||||
MSG msg;
|
||||
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
if (msg.message == WM_QUIT) {
|
||||
v->running = false;
|
||||
return false;
|
||||
}
|
||||
if (!hAccelTable || !TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) {
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
return true; // try again
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//! Do standard event loop
|
||||
void video::main_loop() {
|
||||
// let Windows draw and unroll the window
|
||||
InvalidateRect(g_hAppWnd, 0, false);
|
||||
g_msec = GetTickCount(); // let's stay for 0,5 sec
|
||||
while (g_msec + 500 > GetTickCount()) {
|
||||
loop_once(this);
|
||||
Sleep(1);
|
||||
}
|
||||
g_msec = GetTickCount();
|
||||
// now, start main process
|
||||
if (threaded) {
|
||||
g_handles[0] = CreateThread(NULL, // LPSECURITY_ATTRIBUTES security_attrs
|
||||
0, // SIZE_T stacksize
|
||||
(LPTHREAD_START_ROUTINE)thread_video,
|
||||
this, // argument
|
||||
0,
|
||||
0);
|
||||
if (!g_handles[0]) {
|
||||
DisplayError("Can't create thread");
|
||||
return;
|
||||
}
|
||||
else // harmless race is possible here
|
||||
g_handles[1] = CreateEvent(NULL, false, false, NULL);
|
||||
while (running) {
|
||||
while (loop_once(this))
|
||||
;
|
||||
YIELD_TO_THREAD(); // give time for processing when running on single CPU
|
||||
DWORD r = MsgWaitForMultipleObjects(
|
||||
2, g_handles, false, INFINITE, QS_ALLINPUT ^ QS_MOUSEMOVE);
|
||||
if (r == WAIT_OBJECT_0)
|
||||
break; // thread terminated
|
||||
}
|
||||
running = false;
|
||||
if (WaitForSingleObject(g_handles[0], 3000) == WAIT_TIMEOUT) {
|
||||
// there was not enough time for graceful shutdown, killing the example with code 1.
|
||||
exit(1);
|
||||
}
|
||||
if (g_handles[0])
|
||||
CloseHandle(g_handles[0]);
|
||||
if (g_handles[1])
|
||||
CloseHandle(g_handles[1]);
|
||||
g_handles[0] = g_handles[1] = 0;
|
||||
}
|
||||
else
|
||||
on_process();
|
||||
}
|
||||
|
||||
//! Refresh screen picture
|
||||
bool video::next_frame() {
|
||||
if (!running)
|
||||
return false;
|
||||
g_updates++; // Fast but inaccurate counter. The data race here is benign.
|
||||
if (!threaded)
|
||||
while (loop_once(this))
|
||||
;
|
||||
else if (g_handles[1]) {
|
||||
SetEvent(g_handles[1]);
|
||||
YIELD_TO_THREAD();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Change window title
|
||||
void video::show_title() {
|
||||
if (g_hAppWnd)
|
||||
SetWindowTextA(g_hAppWnd, title);
|
||||
}
|
||||
|
||||
#endif //__WINVIDEO_H__
|
||||
@@ -1,56 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "OpenGLES/ES2/gl.h"
|
||||
|
||||
@interface OpenGLView : UIView {
|
||||
NSTimer *timer;
|
||||
CGRect imageRect;
|
||||
}
|
||||
|
||||
@property (nonatomic, retain) NSTimer *timer;
|
||||
@property (nonatomic) CGRect imageRect;
|
||||
|
||||
- (void) drawRect:(CGRect)rect;
|
||||
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event;
|
||||
|
||||
@end
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface OpenGLView : NSOpenGLView{
|
||||
NSTimer *timer;
|
||||
}
|
||||
|
||||
@property (nonatomic,retain) NSTimer *timer;
|
||||
|
||||
- (void) drawRect:(NSRect)start;
|
||||
- (void) mouseDown:(NSEvent *)theEvent;
|
||||
- (void) keyDown:(NSEvent *)theEvent;
|
||||
- (BOOL) acceptsFirstResponder;
|
||||
- (void) viewDidEndLiveResize;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,143 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "OpenGLView.h"
|
||||
|
||||
// defined in macvideo.cpp
|
||||
extern char* window_title;
|
||||
extern int cocoa_update;
|
||||
extern int g_sizex, g_sizey;
|
||||
extern unsigned int *g_pImg;
|
||||
void on_mouse_func(int x, int y, int k);
|
||||
void on_key_func(int x);
|
||||
|
||||
bool initialized = false;
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import "OpenGLES/ES2/gl.h"
|
||||
|
||||
@implementation OpenGLView
|
||||
|
||||
@synthesize timer;
|
||||
@synthesize imageRect;
|
||||
|
||||
- (void)drawRect:(CGRect)start
|
||||
{
|
||||
if (initialized == false) {
|
||||
NSLog(@"INITIALIZE");
|
||||
timer = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:@selector(update_window) userInfo:nil repeats:YES];
|
||||
imageRect = [[UIScreen mainScreen] bounds];
|
||||
CGFloat full_height = imageRect.size.height;
|
||||
const float ratio=(float)g_sizex/g_sizey;
|
||||
imageRect.size.height=imageRect.size.width/ratio;
|
||||
imageRect.origin.y=(full_height-imageRect.size.height)/2;
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB();
|
||||
CGDataProviderRef dataProvider = CGDataProviderCreateWithData(NULL, g_pImg, 4*g_sizex*g_sizey, NULL);
|
||||
|
||||
CGImageRef inputImage = CGImageCreate(g_sizex, g_sizey, 8, 32, g_sizex * 4, colourSpace,(CGBitmapInfo)kCGImageAlphaNoneSkipLast, dataProvider, NULL, NO, kCGRenderingIntentDefault);
|
||||
UIImage *image = [UIImage imageWithCGImage:inputImage];
|
||||
|
||||
CGDataProviderRelease(dataProvider);
|
||||
CGColorSpaceRelease(colourSpace);
|
||||
CGImageRelease(inputImage);
|
||||
|
||||
[image drawInRect:imageRect];
|
||||
|
||||
}
|
||||
|
||||
- (void) touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
|
||||
{
|
||||
CGPoint point = [[touches anyObject] locationInView:self];
|
||||
const int x = point.x;
|
||||
const int y = point.y;
|
||||
if ( (y-imageRect.origin.y) > 0 && y < (imageRect.origin.y + imageRect.size.height ))
|
||||
on_mouse_func( x*g_sizex/(imageRect.size.width), (y-imageRect.origin.y)*g_sizey/imageRect.size.height,1);
|
||||
[self setNeedsDisplay];
|
||||
}
|
||||
|
||||
-(void) update_window{
|
||||
if( cocoa_update ) [self setNeedsDisplay];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
#import <OpenGL/gl.h>
|
||||
|
||||
@implementation OpenGLView
|
||||
|
||||
@synthesize timer;
|
||||
|
||||
- (void) drawRect:(NSRect)start
|
||||
{
|
||||
if (initialized == false) {
|
||||
NSLog(@"INITIALIZE");
|
||||
timer = [NSTimer scheduledTimerWithTimeInterval:0.03 target:self selector:@selector(update_window) userInfo:nil repeats:YES];
|
||||
initialized = true;
|
||||
}
|
||||
glWindowPos2i(0, (int)self.visibleRect.size.height);
|
||||
glPixelZoom( (float)self.visibleRect.size.width /(float)g_sizex,
|
||||
-(float)self.visibleRect.size.height/(float)g_sizey);
|
||||
glDrawPixels(g_sizex, g_sizey, GL_BGRA_EXT, GL_UNSIGNED_INT_8_8_8_8_REV, g_pImg);
|
||||
glFlush();
|
||||
}
|
||||
|
||||
-(void) update_window{
|
||||
if( cocoa_update ) [self setNeedsDisplay:YES];
|
||||
if( window_title ) [self.window setTitle:[NSString stringWithFormat:@"%s", window_title]];
|
||||
}
|
||||
|
||||
-(void) keyDown:(NSEvent *)theEvent{
|
||||
on_key_func([theEvent.characters characterAtIndex:0]);
|
||||
}
|
||||
|
||||
-(void) mouseDown:(NSEvent *)theEvent{
|
||||
// mouse event for seismic and fractal
|
||||
NSPoint point= theEvent.locationInWindow;
|
||||
const int x = (int)point.x;
|
||||
const int y = (int)point.y;
|
||||
NSRect rect = self.visibleRect;
|
||||
on_mouse_func(x*g_sizex/(int)rect.size.width,((int)rect.size.height-y)*g_sizey/(int)rect.size.height,1);
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
|
||||
- (BOOL) acceptsFirstResponder
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void) rightMouseDown:(NSEvent *)theEvent
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
-(void) viewDidEndLiveResize
|
||||
{
|
||||
NSRect rect = self.visibleRect;
|
||||
const int x=(int)rect.size.width;
|
||||
const int y=(int)rect.size.height;
|
||||
[self.window setTitle:[NSString stringWithFormat:@"X=%d Y=%d", x,y]];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1 +0,0 @@
|
||||
APPL????
|
||||
@@ -1,2 +0,0 @@
|
||||
/* Localized versions of Info.plist keys */
|
||||
|
||||
@@ -1,48 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none">
|
||||
<dependencies>
|
||||
<deployment identifier="macosx"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="9060"/>
|
||||
</dependencies>
|
||||
<objects>
|
||||
<customObject id="-2" userLabel="File's Owner" customClass="NSApplication">
|
||||
<connections>
|
||||
<outlet property="delegate" destination="494" id="495"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/>
|
||||
<customObject id="-3" userLabel="Application"/>
|
||||
<menu title="AMainMenu" systemMenu="main" id="29">
|
||||
<items>
|
||||
<menuItem title="tbbExample" id="56">
|
||||
<menu key="submenu" title="tbbExample" systemMenu="apple" id="57">
|
||||
<items>
|
||||
<menuItem title="Quit tbbExample" keyEquivalent="q" id="136">
|
||||
<connections>
|
||||
<action selector="terminate:" target="-3" id="449"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
</menuItem>
|
||||
</items>
|
||||
</menu>
|
||||
<window title="tbbExample" allowsToolTipsWhenApplicationIsInactive="NO" deferred="NO" oneShot="NO" releasedWhenClosed="NO" showsToolbarButton="NO" animationBehavior="default" id="371">
|
||||
<windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/>
|
||||
<windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/>
|
||||
<rect key="contentRect" x="100" y="100" width="480" height="360"/>
|
||||
<rect key="screenRect" x="0.0" y="0.0" width="1280" height="1002"/>
|
||||
<view key="contentView" focusRingType="none" horizontalHuggingPriority="1" verticalHuggingPriority="9" horizontalCompressionResistancePriority="1" verticalCompressionResistancePriority="1" id="372" customClass="OpenGLView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="480" height="360"/>
|
||||
<autoresizingMask key="autoresizingMask"/>
|
||||
<animations/>
|
||||
</view>
|
||||
</window>
|
||||
<customObject id="494" customClass="tbbAppDelegate">
|
||||
<connections>
|
||||
<outlet property="window" destination="371" id="532"/>
|
||||
</connections>
|
||||
</customObject>
|
||||
<customObject id="420" customClass="NSFontManager"/>
|
||||
</objects>
|
||||
</document>
|
||||
@@ -1,28 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="9060" systemVersion="15B42" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" initialViewController="AKo-RD-jUr">
|
||||
<dependencies>
|
||||
<deployment identifier="iOS"/>
|
||||
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="9051"/>
|
||||
</dependencies>
|
||||
<scenes>
|
||||
<!--View Controller-->
|
||||
<scene sceneID="aF8-QV-POo">
|
||||
<objects>
|
||||
<viewController id="AKo-RD-jUr" sceneMemberID="viewController">
|
||||
<layoutGuides>
|
||||
<viewControllerLayoutGuide type="top" id="SEe-ff-xUc"/>
|
||||
<viewControllerLayoutGuide type="bottom" id="Cp9-IV-SKb"/>
|
||||
</layoutGuides>
|
||||
<view key="view" contentMode="scaleToFill" id="1aY-my-944" customClass="OpenGLView">
|
||||
<rect key="frame" x="0.0" y="0.0" width="320" height="568"/>
|
||||
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
|
||||
<animations/>
|
||||
<color key="backgroundColor" white="0.0" alpha="1" colorSpace="custom" customColorSpace="calibratedWhite"/>
|
||||
</view>
|
||||
</viewController>
|
||||
<placeholder placeholderIdentifier="IBFirstResponder" id="wcZ-9q-FxX" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||
</objects>
|
||||
<point key="canvasLocation" x="90" y="88"/>
|
||||
</scene>
|
||||
</scenes>
|
||||
</document>
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#import <Availability.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
#import "tbbAppDelegate.h"
|
||||
|
||||
void get_screen_resolution(int *x, int *y) {
|
||||
// Getting landscape screen resolution in any case
|
||||
CGRect imageRect = [[UIScreen mainScreen] bounds];
|
||||
*x=imageRect.size.width>imageRect.size.height?imageRect.size.width:imageRect.size.height;
|
||||
*y=imageRect.size.width<imageRect.size.height?imageRect.size.width:imageRect.size.height;
|
||||
return;
|
||||
}
|
||||
|
||||
int cocoa_main(int argc, char * argv[]) {
|
||||
@autoreleasepool {
|
||||
return UIApplicationMain(argc, argv, nil, NSStringFromClass([tbbAppDelegate class]));
|
||||
}
|
||||
}
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
int cocoa_main(int argc, char *argv[])
|
||||
{
|
||||
return NSApplicationMain(argc, (const char **)argv);
|
||||
}
|
||||
#endif
|
||||
@@ -1,47 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
//
|
||||
// Created by Xcode* 4.3.2
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface tbbAppDelegate : UIResponder <UIApplicationDelegate>
|
||||
|
||||
@property (strong, nonatomic) UIWindow *window;
|
||||
|
||||
@end
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
@interface tbbAppDelegate : NSObject <NSApplicationDelegate>{
|
||||
__unsafe_unretained NSWindow *_window;
|
||||
}
|
||||
|
||||
@property (assign) IBOutlet NSWindow *window;
|
||||
|
||||
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *) sender;
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#import "tbbAppDelegate.h"
|
||||
|
||||
#if TARGET_OS_IPHONE
|
||||
|
||||
@implementation tbbAppDelegate
|
||||
|
||||
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (void)applicationDidEnterBackground:(UIApplication *)application
|
||||
{
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#elif TARGET_OS_MAC
|
||||
|
||||
@implementation tbbAppDelegate
|
||||
|
||||
@synthesize window = _window;
|
||||
|
||||
//declared in macvideo.cpp file
|
||||
extern int g_sizex, g_sizey;
|
||||
|
||||
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
|
||||
{
|
||||
// Insert code here to initialize your application
|
||||
NSRect windowSize;
|
||||
windowSize.size.height = g_sizey;
|
||||
windowSize.size.width = g_sizex;
|
||||
windowSize.origin=_window.frame.origin;
|
||||
[_window setFrame:windowSize display:YES];
|
||||
|
||||
}
|
||||
|
||||
- (BOOL) applicationShouldTerminateAfterLastWindowClosed:(NSApplication *) sender
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
@@ -1,44 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>$(EXECUTABLE_NAME)</string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>$(PRODUCT_NAME)</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSRequiresIPhoneOS</key>
|
||||
<true/>
|
||||
<key>UILaunchStoryboardName</key>
|
||||
<string>iOS</string>
|
||||
<key>UIMainStoryboardFile</key>
|
||||
<string>iOS</string>
|
||||
<key>UIRequiredDeviceCapabilities</key>
|
||||
<array>
|
||||
<string>armv7</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
<key>UISupportedInterfaceOrientations~ipad</key>
|
||||
<array>
|
||||
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||
</array>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,45 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleDevelopmentRegion</key>
|
||||
<string>en</string>
|
||||
<key>CFBundleDisplayName</key>
|
||||
<string></string>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>${EXECUTABLE_NAME}</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string></string>
|
||||
<key>CFBundleIdentifier</key>
|
||||
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>CFBundleName</key>
|
||||
<string>${PRODUCT_NAME}</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
<string>APPL</string>
|
||||
<key>CFBundleShortVersionString</key>
|
||||
<string>1.0</string>
|
||||
<key>CFBundleSignature</key>
|
||||
<string>????</string>
|
||||
<key>CFBundleVersion</key>
|
||||
<string>1</string>
|
||||
<key>LSApplicationCategoryType</key>
|
||||
<string>public.app-category.business</string>
|
||||
<key>LSEnvironment</key>
|
||||
<dict>
|
||||
<key>DYLD_LIBRARY_PATH</key>
|
||||
<string>Resources:.:../Resources:/tmp:$DYLD_LIBRARY_PATH</string>
|
||||
<key>LIBRARY_PATH</key>
|
||||
<string>Resources:.:../:/tmp:$DYLD_LIBRARY_PATH</string>
|
||||
</dict>
|
||||
<key>LSMinimumSystemVersion</key>
|
||||
<string>${MACOSX_DEPLOYMENT_TARGET}</string>
|
||||
<key>NSHumanReadableCopyright</key>
|
||||
<string>Copyright 2005-2021 Intel Corporation. All Rights Reserved.</string>
|
||||
<key>NSMainNibFile</key>
|
||||
<string>MainMenu</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
</dict>
|
||||
</plist>
|
||||
@@ -1,468 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
// Uncomment next line to disable shared memory features if you do not have libXext
|
||||
// (http://www.xfree86.org/current/mit-shm.html)
|
||||
//#define X_NOSHMEM
|
||||
|
||||
// Note that it may happen that the build environment supports the shared-memory extension
|
||||
// (so there's no build-time reason to disable the relevant code by defining X_NOSHMEM),
|
||||
// but that using shared memory still fails at run time.
|
||||
// This situation will (ultimately) cause the error handler set by XSetErrorHandler()
|
||||
// to be invoked with XErrorEvent::minor_code==X_ShmAttach. The code below tries to make
|
||||
// such a determination at XShmAttach() time, which seems plausible, but unfortunately
|
||||
// it has also been observed in a specific environment that the error may be reported
|
||||
// at a later time instead, even after video::init_window() has returned.
|
||||
// It is not clear whether this may happen in that way in any environment where it might
|
||||
// depend on the kind of display, e.g., local vs. over "ssh -X", so #define'ing X_NOSHMEM
|
||||
// may not always be the appropriate solution, therefore an environment variable
|
||||
// has been introduced to disable shared memory at run time.
|
||||
// A diagnostic has been added to advise the user about possible workarounds.
|
||||
// X_ShmAttach macro was changed to 1 due to recent changes to X11/extensions/XShm.h header.
|
||||
|
||||
#include "video.hpp"
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <X11/Xlib.h>
|
||||
#include <X11/Xutil.h>
|
||||
#include <X11/keysym.h>
|
||||
#include <sys/time.h>
|
||||
#include <signal.h>
|
||||
#include <pthread.h>
|
||||
|
||||
#ifndef X_NOSHMEM
|
||||
#include <errno.h>
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
static XShmSegmentInfo shmseginfo;
|
||||
static Pixmap pixmap = 0;
|
||||
static bool already_called_X_ShmAttach = false;
|
||||
static bool already_advised_about_NOSHMEM_workarounds = false;
|
||||
#endif
|
||||
static char *display_name = NULL;
|
||||
static Display *dpy = NULL;
|
||||
static Screen *scrn;
|
||||
static Visual *vis;
|
||||
static Colormap cmap;
|
||||
static GC gc;
|
||||
static Window win, rootW;
|
||||
static int dispdepth = 0;
|
||||
static XGCValues xgcv;
|
||||
static XImage *ximage;
|
||||
static int x_error = 0;
|
||||
static int vidtype = 3;
|
||||
int g_sizex, g_sizey;
|
||||
static video *g_video = 0;
|
||||
unsigned int *g_pImg = 0;
|
||||
static int g_fps = 0;
|
||||
struct timeval g_time;
|
||||
static pthread_mutex_t g_mutex = PTHREAD_MUTEX_INITIALIZER;
|
||||
Atom _XA_WM_DELETE_WINDOW = 0; // like in Xatom.h
|
||||
|
||||
///////////////////////////////////////////// public methods of video class ///////////////////////
|
||||
|
||||
video::video() {
|
||||
assert(g_video == 0);
|
||||
g_video = this;
|
||||
title = "Video";
|
||||
calc_fps = running = false;
|
||||
updating = true;
|
||||
}
|
||||
|
||||
inline void mask2bits(unsigned int mask, unsigned int &save, depth_t &shift) {
|
||||
save = mask;
|
||||
if (!mask) {
|
||||
shift = dispdepth / 3;
|
||||
return;
|
||||
}
|
||||
shift = 0;
|
||||
while (!(mask & 1))
|
||||
++shift, mask >>= 1;
|
||||
int bits = 0;
|
||||
while (mask & 1)
|
||||
++bits, mask >>= 1;
|
||||
shift += bits - 8;
|
||||
}
|
||||
|
||||
int xerr_handler(Display *dpy_, XErrorEvent *error) {
|
||||
x_error = error->error_code;
|
||||
if (g_video)
|
||||
g_video->running = false;
|
||||
#ifndef X_NOSHMEM
|
||||
if (error->minor_code == 1 /*X_ShmAttach*/ && already_called_X_ShmAttach &&
|
||||
!already_advised_about_NOSHMEM_workarounds) {
|
||||
char err[256];
|
||||
XGetErrorText(dpy_, x_error, err, 255);
|
||||
fprintf(stderr, "Warning: Can't attach shared memory to display: %s (%d)\n", err, x_error);
|
||||
fprintf(
|
||||
stderr,
|
||||
"If you are seeing a black output window, сheck if you have installed Xext library and rebuild project");
|
||||
already_advised_about_NOSHMEM_workarounds = true;
|
||||
}
|
||||
#else
|
||||
(void)dpy_; // warning prevention
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool video::init_window(int xsize, int ysize) {
|
||||
{ //enclose local variables before fail label
|
||||
g_sizex = xsize;
|
||||
g_sizey = ysize;
|
||||
|
||||
// Open the display
|
||||
if (!dpy) {
|
||||
dpy = XOpenDisplay(display_name);
|
||||
if (!dpy) {
|
||||
fprintf(stderr, "Can't open X11 display %s\n", XDisplayName(display_name));
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
int theScreen = DefaultScreen(dpy);
|
||||
scrn = ScreenOfDisplay(dpy, theScreen);
|
||||
dispdepth = DefaultDepth(dpy, theScreen);
|
||||
XVisualInfo vinfo;
|
||||
if (!((dispdepth >= 15 && dispdepth <= 32 &&
|
||||
XMatchVisualInfo(dpy, theScreen, dispdepth, TrueColor, &vinfo)) ||
|
||||
XMatchVisualInfo(dpy, theScreen, 24, TrueColor, &vinfo) ||
|
||||
XMatchVisualInfo(dpy, theScreen, 32, TrueColor, &vinfo) ||
|
||||
XMatchVisualInfo(dpy, theScreen, 16, TrueColor, &vinfo) ||
|
||||
XMatchVisualInfo(dpy, theScreen, 15, TrueColor, &vinfo))) {
|
||||
fprintf(stderr, "Display has no appropriate True Color visual\n");
|
||||
goto fail;
|
||||
}
|
||||
vis = vinfo.visual;
|
||||
depth = dispdepth = vinfo.depth;
|
||||
mask2bits(vinfo.red_mask, red_mask, red_shift);
|
||||
mask2bits(vinfo.green_mask, green_mask, green_shift);
|
||||
mask2bits(vinfo.blue_mask, blue_mask, blue_shift);
|
||||
rootW = RootWindow(dpy, theScreen);
|
||||
cmap = XCreateColormap(dpy, rootW, vis, AllocNone);
|
||||
XSetWindowAttributes attrs;
|
||||
attrs.backing_store = Always;
|
||||
attrs.colormap = cmap;
|
||||
attrs.event_mask = StructureNotifyMask | KeyPressMask | ButtonPressMask | ButtonReleaseMask;
|
||||
attrs.background_pixel = BlackPixelOfScreen(scrn);
|
||||
attrs.border_pixel = WhitePixelOfScreen(scrn);
|
||||
win = XCreateWindow(dpy,
|
||||
rootW,
|
||||
0,
|
||||
0,
|
||||
xsize,
|
||||
ysize,
|
||||
2,
|
||||
dispdepth,
|
||||
InputOutput,
|
||||
vis,
|
||||
CWBackingStore | CWColormap | CWEventMask | CWBackPixel | CWBorderPixel,
|
||||
&attrs);
|
||||
if (!win) {
|
||||
fprintf(stderr, "Can't create the window\n");
|
||||
goto fail;
|
||||
}
|
||||
XSizeHints sh;
|
||||
sh.flags = PSize | PMinSize | PMaxSize;
|
||||
sh.width = sh.min_width = sh.max_width = xsize;
|
||||
sh.height = sh.min_height = sh.max_height = ysize;
|
||||
XSetStandardProperties(dpy, win, g_video->title, g_video->title, None, NULL, 0, &sh);
|
||||
_XA_WM_DELETE_WINDOW = XInternAtom(dpy, "WM_DELETE_WINDOW", false);
|
||||
XSetWMProtocols(dpy, win, &_XA_WM_DELETE_WINDOW, 1);
|
||||
gc = XCreateGC(dpy, win, 0L, &xgcv);
|
||||
XMapRaised(dpy, win);
|
||||
XFlush(dpy);
|
||||
#ifdef X_FULLSYNC
|
||||
XSynchronize(dpy, true);
|
||||
#endif
|
||||
XSetErrorHandler(xerr_handler);
|
||||
|
||||
int imgbytes = xsize * ysize * (dispdepth <= 16 ? 2 : 4);
|
||||
const char *vidstr;
|
||||
#ifndef X_NOSHMEM
|
||||
int major, minor, pixmaps;
|
||||
if (XShmQueryExtension(dpy) &&
|
||||
XShmQueryVersion(dpy, &major, &minor, &pixmaps)) { // Shared memory
|
||||
shmseginfo.shmid = shmget(IPC_PRIVATE, imgbytes, IPC_CREAT | 0777);
|
||||
if (shmseginfo.shmid < 0) {
|
||||
fprintf(stderr, "Warning: Can't get shared memory: %s\n", strerror(errno));
|
||||
goto generic;
|
||||
}
|
||||
g_pImg = (unsigned int *)(shmseginfo.shmaddr = (char *)shmat(shmseginfo.shmid, 0, 0));
|
||||
if (g_pImg == (unsigned int *)-1) {
|
||||
fprintf(stderr, "Warning: Can't attach to shared memory: %s\n", strerror(errno));
|
||||
shmctl(shmseginfo.shmid, IPC_RMID, NULL);
|
||||
goto generic;
|
||||
}
|
||||
shmseginfo.readOnly = false;
|
||||
if (!XShmAttach(dpy, &shmseginfo) || x_error) {
|
||||
char err[256];
|
||||
XGetErrorText(dpy, x_error, err, 255);
|
||||
fprintf(stderr,
|
||||
"Warning: Can't attach shared memory to display: %s (%d)\n",
|
||||
err,
|
||||
x_error);
|
||||
shmdt(shmseginfo.shmaddr);
|
||||
shmctl(shmseginfo.shmid, IPC_RMID, NULL);
|
||||
goto generic;
|
||||
}
|
||||
already_called_X_ShmAttach = true;
|
||||
|
||||
#ifndef X_NOSHMPIX
|
||||
if (pixmaps && XShmPixmapFormat(dpy) == ZPixmap) { // Pixmaps
|
||||
vidtype = 2;
|
||||
vidstr = "X11 shared memory pixmap";
|
||||
pixmap = XShmCreatePixmap(
|
||||
dpy, win, (char *)g_pImg, &shmseginfo, xsize, ysize, dispdepth);
|
||||
XSetWindowBackgroundPixmap(dpy, win, pixmap);
|
||||
}
|
||||
else
|
||||
#endif //!X_NOSHMPIX
|
||||
{ // Standard
|
||||
vidtype = 1;
|
||||
vidstr = "X11 shared memory";
|
||||
ximage =
|
||||
XShmCreateImage(dpy, vis, dispdepth, ZPixmap, 0, &shmseginfo, xsize, ysize);
|
||||
if (!ximage) {
|
||||
fprintf(stderr, "Can't create the shared image\n");
|
||||
goto fail;
|
||||
}
|
||||
assert(ximage->bytes_per_line == xsize * (dispdepth <= 16 ? 2 : 4));
|
||||
ximage->data = shmseginfo.shmaddr;
|
||||
}
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
#ifndef X_NOSHMEM
|
||||
generic:
|
||||
#endif
|
||||
vidtype = 0;
|
||||
vidstr = "generic X11";
|
||||
g_pImg = new unsigned int[imgbytes / sizeof(int)];
|
||||
ximage = XCreateImage(dpy,
|
||||
vis,
|
||||
dispdepth,
|
||||
ZPixmap,
|
||||
0,
|
||||
(char *)g_pImg,
|
||||
xsize,
|
||||
ysize,
|
||||
32,
|
||||
imgbytes / ysize);
|
||||
if (!ximage) {
|
||||
fprintf(stderr, "Can't create the image\n");
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
if (ximage) {
|
||||
// Note: It may be more efficient to adopt the server's byte order
|
||||
// and swap once per get_color() call instead of once per pixel.
|
||||
const uint32_t probe = 0x03020100;
|
||||
const bool big_endian = (((const char *)(&probe))[0] == 0x03);
|
||||
ximage->byte_order = big_endian ? MSBFirst : LSBFirst;
|
||||
}
|
||||
printf("Note: using %s with %s visual for %d-bit color depth\n",
|
||||
vidstr,
|
||||
vis == DefaultVisual(dpy, theScreen) ? "default" : "non-default",
|
||||
dispdepth);
|
||||
running = true;
|
||||
return true;
|
||||
} // end of enclosing local variables
|
||||
fail:
|
||||
terminate();
|
||||
init_console();
|
||||
return false;
|
||||
}
|
||||
|
||||
bool video::init_console() {
|
||||
if (!g_pImg && g_sizex && g_sizey) {
|
||||
dispdepth = 24;
|
||||
red_shift = 16;
|
||||
vidtype = 3; // fake video
|
||||
g_pImg = new unsigned int[g_sizex * g_sizey];
|
||||
running = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void video::terminate() {
|
||||
running = false;
|
||||
if (dpy) {
|
||||
vidtype = 3; // stop video
|
||||
if (threaded) {
|
||||
pthread_mutex_lock(&g_mutex);
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
}
|
||||
if (ximage) {
|
||||
XDestroyImage(ximage);
|
||||
ximage = 0;
|
||||
g_pImg = 0;
|
||||
} // it frees g_pImg for vidtype == 0
|
||||
#ifndef X_NOSHMEM
|
||||
if (pixmap)
|
||||
XFreePixmap(dpy, pixmap);
|
||||
if (shmseginfo.shmaddr) {
|
||||
XShmDetach(dpy, &shmseginfo);
|
||||
shmdt(shmseginfo.shmaddr);
|
||||
g_pImg = 0;
|
||||
}
|
||||
if (shmseginfo.shmid >= 0)
|
||||
shmctl(shmseginfo.shmid, IPC_RMID, NULL);
|
||||
#endif
|
||||
if (gc)
|
||||
XFreeGC(dpy, gc);
|
||||
if (win)
|
||||
XDestroyWindow(dpy, win);
|
||||
XCloseDisplay(dpy);
|
||||
dpy = 0;
|
||||
}
|
||||
if (g_pImg) {
|
||||
delete[] g_pImg;
|
||||
g_pImg = 0;
|
||||
} // if was allocated for console mode
|
||||
}
|
||||
|
||||
video::~video() {
|
||||
if (g_video)
|
||||
terminate();
|
||||
g_video = 0;
|
||||
}
|
||||
|
||||
//! Do standard event loop
|
||||
void video::main_loop() {
|
||||
struct timezone tz;
|
||||
gettimeofday(&g_time, &tz);
|
||||
on_process();
|
||||
}
|
||||
|
||||
//! Check for pending events once
|
||||
bool video::next_frame() {
|
||||
if (!running)
|
||||
return false;
|
||||
//! try acquire mutex if threaded code, returns on failure
|
||||
if (vidtype == 3 || threaded && pthread_mutex_trylock(&g_mutex))
|
||||
return running;
|
||||
//! Refresh screen picture
|
||||
g_fps++;
|
||||
#ifndef X_NOSHMPIX
|
||||
if (vidtype == 2 && updating)
|
||||
XClearWindow(dpy, win);
|
||||
#endif
|
||||
while (XPending(dpy)) {
|
||||
XEvent report;
|
||||
XNextEvent(dpy, &report);
|
||||
switch (report.type) {
|
||||
case ClientMessage:
|
||||
if (report.xclient.format != 32 || report.xclient.data.l[0] != _XA_WM_DELETE_WINDOW)
|
||||
break;
|
||||
case DestroyNotify: running = false;
|
||||
case KeyPress: on_key(XLookupKeysym(&report.xkey, 0)); break;
|
||||
case ButtonPress:
|
||||
on_mouse(report.xbutton.x, report.xbutton.y, report.xbutton.button);
|
||||
break;
|
||||
case ButtonRelease:
|
||||
on_mouse(report.xbutton.x, report.xbutton.y, -report.xbutton.button);
|
||||
break;
|
||||
}
|
||||
}
|
||||
struct timezone tz;
|
||||
struct timeval now_time;
|
||||
gettimeofday(&now_time, &tz);
|
||||
double sec = (now_time.tv_sec + 1.0 * now_time.tv_usec / 1000000.0) -
|
||||
(g_time.tv_sec + 1.0 * g_time.tv_usec / 1000000.0);
|
||||
if (sec > 1) {
|
||||
memcpy(&g_time, &now_time, sizeof(g_time));
|
||||
if (calc_fps) {
|
||||
double fps = g_fps;
|
||||
g_fps = 0;
|
||||
char buffer[256];
|
||||
snprintf(buffer,
|
||||
256,
|
||||
"%s%s: %d fps",
|
||||
title,
|
||||
updating ? "" : " (no updating)",
|
||||
int(fps / sec));
|
||||
XStoreName(dpy, win, buffer);
|
||||
}
|
||||
#ifndef X_FULLSYNC
|
||||
XSync(dpy, false); // It is often better then using XSynchronize(dpy, true)
|
||||
#endif //X_FULLSYNC
|
||||
}
|
||||
if (threaded)
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
return true;
|
||||
}
|
||||
|
||||
//! Change window title
|
||||
void video::show_title() {
|
||||
if (vidtype < 3)
|
||||
XStoreName(dpy, win, title);
|
||||
}
|
||||
|
||||
drawing_area::drawing_area(int x, int y, int sizex, int sizey)
|
||||
: base_index(y * g_sizex + x),
|
||||
max_index(g_sizex * g_sizey),
|
||||
index_stride(g_sizex),
|
||||
pixel_depth(dispdepth),
|
||||
ptr32(g_pImg),
|
||||
start_x(x),
|
||||
start_y(y),
|
||||
size_x(sizex),
|
||||
size_y(sizey) {
|
||||
assert(x < g_sizex);
|
||||
assert(y < g_sizey);
|
||||
assert(x + sizex <= g_sizex);
|
||||
assert(y + sizey <= g_sizey);
|
||||
|
||||
index = base_index; // current index
|
||||
}
|
||||
|
||||
void drawing_area::update() {
|
||||
if (!g_video->updating)
|
||||
return;
|
||||
#ifndef X_NOSHMEM
|
||||
switch (vidtype) {
|
||||
case 0:
|
||||
#endif
|
||||
pthread_mutex_lock(&g_mutex);
|
||||
if (vidtype == 0)
|
||||
XPutImage(dpy, win, gc, ximage, start_x, start_y, start_x, start_y, size_x, size_y);
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
#ifndef X_NOSHMEM
|
||||
break;
|
||||
case 1:
|
||||
pthread_mutex_lock(&g_mutex);
|
||||
if (vidtype == 1)
|
||||
XShmPutImage(dpy,
|
||||
win,
|
||||
gc,
|
||||
ximage,
|
||||
start_x,
|
||||
start_y,
|
||||
start_x,
|
||||
start_y,
|
||||
size_x,
|
||||
size_y,
|
||||
false);
|
||||
pthread_mutex_unlock(&g_mutex);
|
||||
break;
|
||||
/*case 2: make it in next_frame(); break;*/
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#ifndef TBB_examples_fast_random_H
|
||||
#define TBB_examples_fast_random_H
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
namespace utility {
|
||||
//------------------------------------------------------------------------
|
||||
// FastRandom
|
||||
//------------------------------------------------------------------------
|
||||
|
||||
namespace internal {
|
||||
std::size_t GetPrime(std::size_t seed);
|
||||
}
|
||||
|
||||
//! A fast random number generator.
|
||||
/** Uses linear congruential method. */
|
||||
class FastRandom {
|
||||
std::size_t x, a;
|
||||
|
||||
public:
|
||||
//! Get a random number.
|
||||
unsigned short get() {
|
||||
return get(x);
|
||||
}
|
||||
//! Get a random number for the given seed; update the seed for next use.
|
||||
unsigned short get(std::size_t& seed) {
|
||||
unsigned short r = (unsigned short)(seed >> 16);
|
||||
seed = seed * a + 1;
|
||||
return r;
|
||||
}
|
||||
//! Construct a random number generator.
|
||||
FastRandom(std::size_t seed) {
|
||||
x = seed * internal::GetPrime(seed);
|
||||
a = internal::GetPrime(x);
|
||||
}
|
||||
};
|
||||
} // namespace utility
|
||||
|
||||
namespace utility {
|
||||
namespace internal {
|
||||
//! Table of primes used by fast random-number generator (FastRandom).
|
||||
static const unsigned Primes[] = {
|
||||
0x9e3779b1, 0xffe6cc59, 0x2109f6dd, 0x43977ab5, 0xba5703f5, 0xb495a877, 0xe1626741, 0x79695e6b,
|
||||
0xbc98c09f, 0xd5bee2b3, 0x287488f9, 0x3af18231, 0x9677cd4d, 0xbe3a6929, 0xadc6a877, 0xdcf0674b,
|
||||
0xbe4d6fe9, 0x5f15e201, 0x99afc3fd, 0xf3f16801, 0xe222cfff, 0x24ba5fdb, 0x0620452d, 0x79f149e3,
|
||||
0xc8b93f49, 0x972702cd, 0xb07dd827, 0x6c97d5ed, 0x085a3d61, 0x46eb5ea7, 0x3d9910ed, 0x2e687b5b,
|
||||
0x29609227, 0x6eb081f1, 0x0954c4e1, 0x9d114db9, 0x542acfa9, 0xb3e6bd7b, 0x0742d917, 0xe9f3ffa7,
|
||||
0x54581edb, 0xf2480f45, 0x0bb9288f, 0xef1affc7, 0x85fa0ca7, 0x3ccc14db, 0xe6baf34b, 0x343377f7,
|
||||
0x5ca19031, 0xe6d9293b, 0xf0a9f391, 0x5d2e980b, 0xfc411073, 0xc3749363, 0xb892d829, 0x3549366b,
|
||||
0x629750ad, 0xb98294e5, 0x892d9483, 0xc235baf3, 0x3d2402a3, 0x6bdef3c9, 0xbec333cd, 0x40c9520f
|
||||
};
|
||||
std::size_t GetPrime(std::size_t seed) {
|
||||
return Primes[seed % (sizeof(Primes) / sizeof(Primes[0]))];
|
||||
}
|
||||
} // namespace internal
|
||||
} // namespace utility
|
||||
|
||||
#endif /* TBB_examples_fast_random_H */
|
||||
@@ -1,575 +0,0 @@
|
||||
/*
|
||||
Copyright (c) 2005-2021 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.
|
||||
*/
|
||||
|
||||
#ifndef TBB_examples_utility_H
|
||||
#define TBB_examples_utility_H
|
||||
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
#include <cstdlib>
|
||||
|
||||
#include <utility>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
#include <set>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <numeric>
|
||||
#include <stdexcept>
|
||||
#include <memory>
|
||||
#include <iostream>
|
||||
// TBB headers should not be used, as some examples may need to be built without TBB.
|
||||
|
||||
namespace utility {
|
||||
namespace internal {
|
||||
|
||||
//TODO: add tcs
|
||||
template <class dest_type>
|
||||
dest_type& string_to(std::string const& s, dest_type& result) {
|
||||
std::stringstream stream(s);
|
||||
stream >> result;
|
||||
if ((!stream) || (stream.fail())) {
|
||||
throw std::invalid_argument("error converting string '" + std::string(s) + "'");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class dest_type>
|
||||
dest_type string_to(std::string const& s) {
|
||||
dest_type result;
|
||||
return string_to(s, result);
|
||||
}
|
||||
|
||||
template <typename>
|
||||
struct is_bool {
|
||||
static bool value() {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
template <>
|
||||
struct is_bool<bool> {
|
||||
static bool value() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
class type_base {
|
||||
type_base& operator=(const type_base&);
|
||||
|
||||
public:
|
||||
const std::string name;
|
||||
const std::string description;
|
||||
|
||||
type_base(std::string a_name, std::string a_description)
|
||||
: name(a_name),
|
||||
description(a_description) {}
|
||||
virtual void parse_and_store(const std::string& s) = 0;
|
||||
virtual std::string value() const = 0;
|
||||
virtual std::unique_ptr<type_base> clone() const = 0;
|
||||
virtual ~type_base() {}
|
||||
};
|
||||
template <typename type>
|
||||
class type_impl : public type_base {
|
||||
private:
|
||||
type_impl(const type_impl& src)
|
||||
: type_base(src.name, src.description),
|
||||
target(src.target),
|
||||
validating_function(src.validating_function) {}
|
||||
type_impl& operator=(const type_impl&);
|
||||
typedef bool (*validating_function_type)(const type&);
|
||||
type& target;
|
||||
validating_function_type validating_function;
|
||||
|
||||
public:
|
||||
type_impl(std::string a_name,
|
||||
std::string a_description,
|
||||
type& a_target,
|
||||
validating_function_type a_validating_function = nullptr)
|
||||
: type_base(a_name, a_description),
|
||||
target(a_target),
|
||||
validating_function(a_validating_function){};
|
||||
void parse_and_store(const std::string& s) /*override*/ {
|
||||
try {
|
||||
const bool is_bool = internal::is_bool<type>::value();
|
||||
if (is_bool && s.empty()) {
|
||||
//to avoid directly assigning true
|
||||
//(as it will impose additional layer of indirection)
|
||||
//so, simply pass it as string
|
||||
internal::string_to("1", target);
|
||||
}
|
||||
else {
|
||||
internal::string_to(s, target);
|
||||
}
|
||||
}
|
||||
catch (std::invalid_argument& e) {
|
||||
std::stringstream str;
|
||||
str << "'" << s << "' is incorrect input for argument '" << name << "'"
|
||||
<< " (" << e.what() << ")";
|
||||
throw std::invalid_argument(str.str());
|
||||
}
|
||||
if (validating_function) {
|
||||
if (!((validating_function)(target))) {
|
||||
std::stringstream str;
|
||||
str << "'" << target << "' is invalid value for argument '" << name << "'";
|
||||
throw std::invalid_argument(str.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
template <typename t>
|
||||
static bool is_null_c_str(t&) {
|
||||
return false;
|
||||
}
|
||||
static bool is_null_c_str(char* s) {
|
||||
return s == nullptr;
|
||||
}
|
||||
std::string value() const /*override*/ {
|
||||
std::stringstream str;
|
||||
if (!is_null_c_str(target))
|
||||
str << target;
|
||||
return str.str();
|
||||
}
|
||||
std::unique_ptr<type_base> clone() const /*override*/ {
|
||||
return std::unique_ptr<type_base>(new type_impl(*this));
|
||||
}
|
||||
};
|
||||
|
||||
class argument {
|
||||
private:
|
||||
std::unique_ptr<type_base> p_type;
|
||||
bool matched_;
|
||||
|
||||
public:
|
||||
argument(argument const& other)
|
||||
: p_type(other.p_type.get() ? (other.p_type->clone()).release() : nullptr),
|
||||
matched_(other.matched_) {}
|
||||
argument& operator=(argument a) {
|
||||
this->swap(a);
|
||||
return *this;
|
||||
}
|
||||
void swap(argument& other) {
|
||||
std::swap(p_type, other.p_type);
|
||||
std::swap(matched_, other.matched_);
|
||||
}
|
||||
template <class type>
|
||||
argument(std::string a_name,
|
||||
std::string a_description,
|
||||
type& dest,
|
||||
bool (*a_validating_function)(const type&) = nullptr)
|
||||
: p_type(new type_impl<type>(a_name, a_description, dest, a_validating_function)),
|
||||
matched_(false) {}
|
||||
std::string value() const {
|
||||
return p_type->value();
|
||||
}
|
||||
std::string name() const {
|
||||
return p_type->name;
|
||||
}
|
||||
std::string description() const {
|
||||
return p_type->description;
|
||||
}
|
||||
void parse_and_store(const std::string& s) {
|
||||
p_type->parse_and_store(s);
|
||||
matched_ = true;
|
||||
}
|
||||
bool is_matched() const {
|
||||
return matched_;
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
class cli_argument_pack {
|
||||
typedef std::map<std::string, internal::argument> args_map_type;
|
||||
typedef std::vector<std::string> args_display_order_type;
|
||||
typedef std::vector<std::string> positional_arg_names_type;
|
||||
|
||||
private:
|
||||
args_map_type args_map;
|
||||
args_display_order_type args_display_order;
|
||||
positional_arg_names_type positional_arg_names;
|
||||
std::set<std::string> bool_args_names;
|
||||
|
||||
private:
|
||||
void add_arg(internal::argument const& a) {
|
||||
std::pair<args_map_type::iterator, bool> result =
|
||||
args_map.insert(std::make_pair(a.name(), a));
|
||||
if (!result.second) {
|
||||
throw std::invalid_argument("argument with name: '" + a.name() +
|
||||
"' already registered");
|
||||
}
|
||||
args_display_order.push_back(a.name());
|
||||
}
|
||||
|
||||
public:
|
||||
template <typename type>
|
||||
cli_argument_pack& arg(type& dest,
|
||||
std::string const& name,
|
||||
std::string const& description,
|
||||
bool (*validate)(const type&) = nullptr) {
|
||||
internal::argument a(name, description, dest, validate);
|
||||
add_arg(a);
|
||||
if (internal::is_bool<type>::value()) {
|
||||
bool_args_names.insert(name);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
//Positional means that argument name can be omitted in actual CL
|
||||
//only key to match values for parameters with
|
||||
template <typename type>
|
||||
cli_argument_pack& positional_arg(type& dest,
|
||||
std::string const& name,
|
||||
std::string const& description,
|
||||
bool (*validate)(const type&) = nullptr) {
|
||||
internal::argument a(name, description, dest, validate);
|
||||
add_arg(a);
|
||||
if (internal::is_bool<type>::value()) {
|
||||
bool_args_names.insert(name);
|
||||
}
|
||||
positional_arg_names.push_back(name);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void parse(std::size_t argc, char const* argv[]) {
|
||||
{
|
||||
std::size_t current_positional_index = 0;
|
||||
for (std::size_t j = 1; j < argc; j++) {
|
||||
internal::argument* pa = nullptr;
|
||||
std::string argument_value;
|
||||
|
||||
const char* const begin = argv[j];
|
||||
const char* const end = begin + std::strlen(argv[j]);
|
||||
|
||||
const char* const assign_sign = std::find(begin, end, '=');
|
||||
|
||||
struct throw_unknown_parameter {
|
||||
static void _(std::string const& location) {
|
||||
throw std::invalid_argument(std::string("unknown parameter starting at:'") +
|
||||
location + "'");
|
||||
}
|
||||
};
|
||||
//first try to interpret it like parameter=value string
|
||||
if (assign_sign != end) {
|
||||
std::string name_found = std::string(begin, assign_sign);
|
||||
args_map_type::iterator it = args_map.find(name_found);
|
||||
|
||||
if (it != args_map.end()) {
|
||||
pa = &((*it).second);
|
||||
argument_value = std::string(assign_sign + 1, end);
|
||||
}
|
||||
else {
|
||||
throw_unknown_parameter::_(argv[j]);
|
||||
}
|
||||
}
|
||||
//then see is it a named flag
|
||||
else {
|
||||
args_map_type::iterator it = args_map.find(argv[j]);
|
||||
if (it != args_map.end()) {
|
||||
pa = &((*it).second);
|
||||
argument_value = "";
|
||||
}
|
||||
//then try it as positional argument without name specified
|
||||
else if (current_positional_index < positional_arg_names.size()) {
|
||||
std::stringstream str(argv[j]);
|
||||
args_map_type::iterator found_positional_arg =
|
||||
args_map.find(positional_arg_names.at(current_positional_index));
|
||||
//TODO: probably use of smarter assert would help here
|
||||
assert(
|
||||
found_positional_arg !=
|
||||
args_map
|
||||
.end() /*&&"positional_arg_names and args_map are out of sync"*/);
|
||||
if (found_positional_arg == args_map.end()) {
|
||||
throw std::logic_error(
|
||||
"positional_arg_names and args_map are out of sync");
|
||||
}
|
||||
pa = &((*found_positional_arg).second);
|
||||
argument_value = argv[j];
|
||||
|
||||
current_positional_index++;
|
||||
}
|
||||
else {
|
||||
//TODO: add tc to check
|
||||
throw_unknown_parameter::_(argv[j]);
|
||||
}
|
||||
}
|
||||
assert(pa);
|
||||
if (pa->is_matched()) {
|
||||
throw std::invalid_argument(std::string("several values specified for: '") +
|
||||
pa->name() + "' argument");
|
||||
}
|
||||
pa->parse_and_store(argument_value);
|
||||
}
|
||||
}
|
||||
}
|
||||
std::string usage_string(const std::string& binary_name) const {
|
||||
std::string command_line_params;
|
||||
std::string summary_description;
|
||||
|
||||
for (args_display_order_type::const_iterator it = args_display_order.begin();
|
||||
it != args_display_order.end();
|
||||
++it) {
|
||||
const bool is_bool = (0 != bool_args_names.count((*it)));
|
||||
args_map_type::const_iterator argument_it = args_map.find(*it);
|
||||
//TODO: probably use of smarter assert would help here
|
||||
assert(argument_it !=
|
||||
args_map.end() /*&&"args_display_order and args_map are out of sync"*/);
|
||||
if (argument_it == args_map.end()) {
|
||||
throw std::logic_error("args_display_order and args_map are out of sync");
|
||||
}
|
||||
const internal::argument& a = (*argument_it).second;
|
||||
command_line_params += " [" + a.name() + (is_bool ? "" : "=value") + "]";
|
||||
summary_description +=
|
||||
" " + a.name() + " - " + a.description() + " (" + a.value() + ")" + "\n";
|
||||
}
|
||||
|
||||
std::string positional_arg_cl;
|
||||
for (positional_arg_names_type::const_iterator it = positional_arg_names.begin();
|
||||
it != positional_arg_names.end();
|
||||
++it) {
|
||||
positional_arg_cl += " [" + (*it);
|
||||
}
|
||||
for (std::size_t i = 0; i < positional_arg_names.size(); ++i) {
|
||||
positional_arg_cl += "]";
|
||||
}
|
||||
command_line_params += positional_arg_cl;
|
||||
std::stringstream str;
|
||||
str << " Program usage is:"
|
||||
<< "\n"
|
||||
<< " " << binary_name << command_line_params << "\n"
|
||||
<< "\n"
|
||||
<< " where:"
|
||||
<< "\n"
|
||||
<< summary_description;
|
||||
return str.str();
|
||||
}
|
||||
}; // class cli_argument_pack
|
||||
|
||||
namespace internal {
|
||||
template <typename T>
|
||||
bool is_power_of_2(T val) {
|
||||
std::size_t intval = std::size_t(val);
|
||||
return (intval & (intval - 1)) == std::size_t(0);
|
||||
}
|
||||
int step_function_plus(int previous, double step) {
|
||||
return static_cast<int>(previous + step);
|
||||
}
|
||||
int step_function_multiply(int previous, double multiply) {
|
||||
return static_cast<int>(previous * multiply);
|
||||
}
|
||||
// "Power-of-2 ladder": nsteps is the desired number of steps between any subsequent powers of 2.
|
||||
// The actual step is the quotient of the nearest smaller power of 2 divided by that number (but at least 1).
|
||||
// E.g., '1:32:#4' means 1,2,3,4,5,6,7,8,10,12,14,16,20,24,28,32
|
||||
int step_function_power2_ladder(int previous, double nsteps) {
|
||||
int steps = int(nsteps);
|
||||
assert(is_power_of_2(steps)); // must be a power of 2
|
||||
// The actual step is 1 until the value is twice as big as nsteps
|
||||
if (previous < 2 * steps)
|
||||
return previous + 1;
|
||||
// calculate the previous power of 2
|
||||
int prev_power2 = previous / 2; // start with half the given value
|
||||
int rshift = 1; // and with the shift of 1;
|
||||
while (int shifted =
|
||||
prev_power2 >> rshift) { // shift the value right; while the result is non-zero,
|
||||
prev_power2 |= shifted; // add the bits set in 'shifted';
|
||||
rshift <<= 1; // double the shift, as twice as many top bits are set;
|
||||
} // repeat.
|
||||
++prev_power2; // all low bits set; now it's just one less than the desired power of 2
|
||||
assert(is_power_of_2(prev_power2));
|
||||
assert((prev_power2 <= previous) && (2 * prev_power2 > previous));
|
||||
// The actual step value is the previous power of 2 divided by steps
|
||||
return previous + (prev_power2 / steps);
|
||||
}
|
||||
typedef int (*step_function_ptr_type)(int, double);
|
||||
|
||||
struct step_function_descriptor {
|
||||
char mnemonic;
|
||||
step_function_ptr_type function;
|
||||
|
||||
public:
|
||||
step_function_descriptor(char a_mnemonic, step_function_ptr_type a_function)
|
||||
: mnemonic(a_mnemonic),
|
||||
function(a_function) {}
|
||||
|
||||
private:
|
||||
void operator=(step_function_descriptor const&);
|
||||
};
|
||||
step_function_descriptor step_function_descriptors[] = {
|
||||
step_function_descriptor('*', step_function_multiply),
|
||||
step_function_descriptor('+', step_function_plus),
|
||||
step_function_descriptor('#', step_function_power2_ladder)
|
||||
};
|
||||
|
||||
template <typename T, std::size_t N>
|
||||
inline std::size_t array_length(const T (&)[N]) {
|
||||
return N;
|
||||
}
|
||||
|
||||
struct thread_range_step {
|
||||
step_function_ptr_type step_function;
|
||||
double step_function_argument;
|
||||
|
||||
thread_range_step(step_function_ptr_type step_function_, double step_function_argument_)
|
||||
: step_function(step_function_),
|
||||
step_function_argument(step_function_argument_) {
|
||||
if (!step_function_)
|
||||
throw std::invalid_argument(
|
||||
"step_function for thread range step should not be nullptr");
|
||||
}
|
||||
int operator()(int previous) const {
|
||||
assert(0 <= previous); // test 0<=first and loop discipline
|
||||
const int ret = step_function(previous, step_function_argument);
|
||||
assert(previous < ret);
|
||||
return ret;
|
||||
}
|
||||
friend std::istream& operator>>(std::istream& input_stream, thread_range_step& step) {
|
||||
char function_char;
|
||||
double function_argument;
|
||||
input_stream >> function_char >> function_argument;
|
||||
std::size_t i = 0;
|
||||
while ((i < array_length(step_function_descriptors)) &&
|
||||
(step_function_descriptors[i].mnemonic != function_char))
|
||||
++i;
|
||||
if (i >= array_length(step_function_descriptors)) {
|
||||
throw std::invalid_argument("unknown step function mnemonic: " +
|
||||
std::string(1, function_char));
|
||||
}
|
||||
else if ((function_char == '#') && !is_power_of_2(function_argument)) {
|
||||
throw std::invalid_argument("the argument of # should be a power of 2");
|
||||
}
|
||||
step.step_function = step_function_descriptors[i].function;
|
||||
step.step_function_argument = function_argument;
|
||||
return input_stream;
|
||||
}
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
struct thread_number_range {
|
||||
int (*auto_number_of_threads)();
|
||||
int first; // 0<=first (0 can be used as a special value)
|
||||
int last; // first<=last
|
||||
|
||||
::utility::internal::thread_range_step step;
|
||||
|
||||
thread_number_range(
|
||||
int (*auto_number_of_threads_)(),
|
||||
int low_ = 1,
|
||||
int high_ = -1,
|
||||
::utility::internal::thread_range_step step_ =
|
||||
::utility::internal::thread_range_step(::utility::internal::step_function_power2_ladder,
|
||||
4))
|
||||
: auto_number_of_threads(auto_number_of_threads_),
|
||||
first(low_),
|
||||
last((high_ > -1) ? high_ : auto_number_of_threads_()),
|
||||
step(step_) {
|
||||
if (first < 0) {
|
||||
throw std::invalid_argument("negative value not allowed");
|
||||
}
|
||||
if (first > last) {
|
||||
throw std::invalid_argument("decreasing sequence not allowed");
|
||||
}
|
||||
}
|
||||
friend std::istream& operator>>(std::istream& i, thread_number_range& range) {
|
||||
try {
|
||||
std::string s;
|
||||
i >> s;
|
||||
struct string_to_number_of_threads {
|
||||
int auto_value;
|
||||
string_to_number_of_threads(int auto_value_) : auto_value(auto_value_) {}
|
||||
int operator()(const std::string& value) const {
|
||||
return (value == "auto") ? auto_value : internal::string_to<int>(value);
|
||||
}
|
||||
};
|
||||
string_to_number_of_threads string_to_number_of_threads(range.auto_number_of_threads());
|
||||
int low, high;
|
||||
std::size_t colon = s.find(':');
|
||||
if (colon == std::string::npos) {
|
||||
low = high = string_to_number_of_threads(s);
|
||||
}
|
||||
else {
|
||||
//it is a range
|
||||
std::size_t second_colon = s.find(':', colon + 1);
|
||||
|
||||
low = string_to_number_of_threads(std::string(s, 0, colon)); //not copying the colon
|
||||
high = string_to_number_of_threads(
|
||||
std::string(s, colon + 1, second_colon - (colon + 1))); //not copying the colons
|
||||
if (second_colon != std::string::npos) {
|
||||
internal::string_to(std::string(s, second_colon + 1), range.step);
|
||||
}
|
||||
}
|
||||
range = thread_number_range(range.auto_number_of_threads, low, high, range.step);
|
||||
}
|
||||
catch (std::invalid_argument&) {
|
||||
i.setstate(std::ios::failbit);
|
||||
throw;
|
||||
}
|
||||
return i;
|
||||
}
|
||||
friend std::ostream& operator<<(std::ostream& o, thread_number_range const& range) {
|
||||
using namespace internal;
|
||||
std::size_t i = 0;
|
||||
for (; i < array_length(step_function_descriptors) &&
|
||||
step_function_descriptors[i].function != range.step.step_function;
|
||||
++i) {
|
||||
}
|
||||
if (i >= array_length(step_function_descriptors)) {
|
||||
throw std::invalid_argument("unknown step function for thread range");
|
||||
}
|
||||
o << range.first << ":" << range.last << ":" << step_function_descriptors[i].mnemonic
|
||||
<< range.step.step_function_argument;
|
||||
return o;
|
||||
}
|
||||
}; // struct thread_number_range
|
||||
//TODO: fix unused warning here
|
||||
static const char* thread_number_range_desc =
|
||||
"number of threads to use; a range of the form low[:high[:(+|*|#)step]],"
|
||||
"\n\twhere low and optional high are non-negative integers or 'auto' for the default choice,"
|
||||
"\n\tand optional step expression specifies how thread numbers are chosen within the range.";
|
||||
|
||||
inline void report_elapsed_time(double seconds) {
|
||||
std::cout << "elapsed time : " << seconds << " seconds"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
inline void report_skipped() {
|
||||
std::cout << "skip"
|
||||
<< "\n";
|
||||
}
|
||||
|
||||
inline void parse_cli_arguments(int argc, const char* argv[], utility::cli_argument_pack cli_pack) {
|
||||
bool show_help = false;
|
||||
cli_pack.arg(show_help, "-h", "show this message");
|
||||
|
||||
bool invalid_input = false;
|
||||
try {
|
||||
cli_pack.parse(argc, argv);
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::cerr << "error occurred while parsing command line."
|
||||
<< "\n"
|
||||
<< "error text: " << e.what() << "\n"
|
||||
<< std::flush;
|
||||
invalid_input = true;
|
||||
}
|
||||
if (show_help || invalid_input) {
|
||||
std::cout << cli_pack.usage_string(argv[0]) << std::flush;
|
||||
std::exit(0);
|
||||
}
|
||||
}
|
||||
inline void parse_cli_arguments(int argc, char* argv[], utility::cli_argument_pack cli_pack) {
|
||||
parse_cli_arguments(argc, const_cast<const char**>(argv), cli_pack);
|
||||
}
|
||||
} // namespace utility
|
||||
|
||||
#endif /* TBB_examples_utility_H */
|
||||