Creating release candidate final from release_502 branch

git-svn-id: https://llvm.org/svn/llvm-project/openmp/tags/RELEASE_502@331335 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Tom Stellard
2018-05-02 03:24:22 +00:00
parent ff57ae9408
commit 3883091592
509 changed files with 299673 additions and 0 deletions
+4
View File
@@ -0,0 +1,4 @@
{
"project_id" : "openmp",
"conduit_uri" : "https://reviews.llvm.org/"
}
+42
View File
@@ -0,0 +1,42 @@
#==============================================================================#
# This file specifies intentionally untracked files that git should ignore.
# See: http://www.kernel.org/pub/software/scm/git/docs/gitignore.html
#
# This file is intentionally different from the output of `git svn show-ignore`,
# as most of those are useless.
#==============================================================================#
#==============================================================================#
# File extensions to be ignored anywhere in the tree.
#==============================================================================#
# Temp files created by most text editors.
*~
# Merge files created by git.
*.orig
# Byte compiled python modules.
*.pyc
# vim swap files
.*.sw?
.sw?
#OS X specific files.
.DS_store
#==============================================================================#
# Explicit files to ignore (only matches one).
#==============================================================================#
# Various tag programs
tags
/TAGS
/GPATH
/GRTAGS
/GSYMS
/GTAGS
.gitusers
#==============================================================================#
# Directories to ignore (do not add trailing '/'s, they skip symlinks).
#==============================================================================#
runtime/exports
# Nested build directory
/build
+23
View File
@@ -0,0 +1,23 @@
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
set(OPENMP_LLVM_TOOLS_DIR "" CACHE PATH "Path to LLVM tools for testing")
add_subdirectory(runtime)
# The tests currently don't pass if the generic ELF plugin is built.
# TODO: Fix the tests and enable libomptarget by default on supported
# architectures and platforms.
set(ENABLE_LIBOMPTARGET OFF)
# Currently libomptarget cannot be compiled on Windows or MacOS X.
# Since the device plugins are only supported on Linux anyway,
# there is no point in trying to compile libomptarget on other OSes.
if (WIN32 OR ${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
set(ENABLE_LIBOMPTARGET OFF)
endif()
option(OPENMP_ENABLE_LIBOMPTARGET "Enable building libomptarget for offloading."
${ENABLE_LIBOMPTARGET})
if (OPENMP_ENABLE_LIBOMPTARGET)
add_subdirectory(libomptarget)
endif()
+57
View File
@@ -0,0 +1,57 @@
This file is a partial list of people who have contributed to the LLVM/openmp
project. If you have contributed a patch or made some other contribution to
LLVM/openmp, please submit a patch to this file to add yourself, and it will be
done!
The list is sorted by surname and formatted to allow easy grepping and
beautification by scripts. The fields are: name (N), email (E), web-address
(W), PGP key ID and fingerprint (P), description (D), and snail-mail address
(S).
N: Carlo Bertolli
W: http://ibm.com
D: IBM contributor to PowerPC support in CMake files and elsewhere.
N: Sunita Chandrasekaran
D: Contributor to testsuite from OpenUH
N: Barbara Chapman
D: Contributor to testsuite from OpenUH
N: University of Houston
W: http://web.cs.uh.edu/~openuh/download/
D: OpenUH test suite
N: Intel Corporation OpenMP runtime team
W: http://openmprtl.org
D: Created the runtime.
N: John Mellor-Crummey and other members of the OpenMP Tools Working Group
E: johnmc@rice.edu
D: OpenMP Tools Interface (OMPT)
N: Matthias Muller
D: Contributor to testsuite from OpenUH
N: Tal Nevo
E: tal@scalemp.com
D: ScaleMP contributor to improve runtime performance there.
W: http://scalemp.com
N: Pavel Neytchev
D: Contributor to testsuite from OpenUH
N: Steven Noonan
E: steven@uplinklabs.net
D: Patches for the ARM architecture and removal of several inconsistencies.
N: Alp Toker
E: alp@nuanti.com
D: Making build work for FreeBSD.
N: Cheng Wang
D: Contributor to testsuite from OpenUH
N: Diego Caballero
E: diego.l.caballero@gmail.com
D: Fork performance improvements
+174
View File
@@ -0,0 +1,174 @@
==============================================================================
The software contained in this directory tree is dual licensed under both the
University of Illinois "BSD-Like" license and the MIT license. As a user of
this code you may choose to use it under either license. As a contributor,
you agree to allow your code to be used under both. The full text of the
relevant licenses is included below.
In addition, a license agreement from the copyright/patent holders of the
software contained in this directory tree is included below.
==============================================================================
University of Illinois/NCSA
Open Source License
Copyright (c) 1997-2016 Intel Corporation
All rights reserved.
Developed by:
OpenMP Runtime Team
Intel Corporation
http://www.openmprtl.org
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal with
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
* Redistributions of source code must retain the above copyright notice,
this list of conditions and the following disclaimers.
* Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimers in the
documentation and/or other materials provided with the distribution.
* Neither the names of Intel Corporation OpenMP Runtime Team nor the
names of its contributors may be used to endorse or promote products
derived from this Software without specific prior written permission.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
CONTRIBUTORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE
SOFTWARE.
==============================================================================
Copyright (c) 1997-2016 Intel Corporation
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
==============================================================================
Intel Corporation
Software Grant License Agreement ("Agreement")
Except for the license granted herein to you, Intel Corporation ("Intel") reserves
all right, title, and interest in and to the Software (defined below).
Definition
"Software" means the code and documentation as well as any original work of
authorship, including any modifications or additions to an existing work, that
is intentionally submitted by Intel to llvm.org (http://llvm.org) ("LLVM") for
inclusion in, or documentation of, any of the products owned or managed by LLVM
(the "Work"). For the purposes of this definition, "submitted" means any form of
electronic, verbal, or written communication sent to LLVM or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that are
managed by, or on behalf of, LLVM for the purpose of discussing and improving
the Work, but excluding communication that is conspicuously marked otherwise.
1. Grant of Copyright License. Subject to the terms and conditions of this
Agreement, Intel hereby grants to you and to recipients of the Software
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable copyright license to reproduce, prepare derivative
works of, publicly display, publicly perform, sublicense, and distribute the
Software and such derivative works.
2. Grant of Patent License. Subject to the terms and conditions of this
Agreement, Intel hereby grants you and to recipients of the Software
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable (except as stated in this section) patent license
to make, have made, use, offer to sell, sell, import, and otherwise transfer
the Work, where such license applies only to those patent claims licensable
by Intel that are necessarily infringed by Intel's Software alone or by
combination of the Software with the Work to which such Software was
submitted. If any entity institutes patent litigation against Intel or any
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
that Intel's Software, or the Work to which Intel has contributed constitutes
direct or contributory patent infringement, then any patent licenses granted
to that entity under this Agreement for the Software or Work shall terminate
as of the date such litigation is filed.
Unless required by applicable law or agreed to in writing, the software is
provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied, including, without limitation, any warranties or
conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE.
==============================================================================
ARM Limited
Software Grant License Agreement ("Agreement")
Except for the license granted herein to you, ARM Limited ("ARM") reserves all
right, title, and interest in and to the Software (defined below).
Definition
"Software" means the code and documentation as well as any original work of
authorship, including any modifications or additions to an existing work, that
is intentionally submitted by ARM to llvm.org (http://llvm.org) ("LLVM") for
inclusion in, or documentation of, any of the products owned or managed by LLVM
(the "Work"). For the purposes of this definition, "submitted" means any form of
electronic, verbal, or written communication sent to LLVM or its
representatives, including but not limited to communication on electronic
mailing lists, source code control systems, and issue tracking systems that are
managed by, or on behalf of, LLVM for the purpose of discussing and improving
the Work, but excluding communication that is conspicuously marked otherwise.
1. Grant of Copyright License. Subject to the terms and conditions of this
Agreement, ARM hereby grants to you and to recipients of the Software
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable copyright license to reproduce, prepare derivative
works of, publicly display, publicly perform, sublicense, and distribute the
Software and such derivative works.
2. Grant of Patent License. Subject to the terms and conditions of this
Agreement, ARM hereby grants you and to recipients of the Software
distributed by LLVM a perpetual, worldwide, non-exclusive, no-charge,
royalty-free, irrevocable (except as stated in this section) patent license
to make, have made, use, offer to sell, sell, import, and otherwise transfer
the Work, where such license applies only to those patent claims licensable
by ARM that are necessarily infringed by ARM's Software alone or by
combination of the Software with the Work to which such Software was
submitted. If any entity institutes patent litigation against ARM or any
other entity (including a cross-claim or counterclaim in a lawsuit) alleging
that ARM's Software, or the Work to which ARM has contributed constitutes
direct or contributory patent infringement, then any patent licenses granted
to that entity under this Agreement for the Software or Work shall terminate
as of the date such litigation is filed.
Unless required by applicable law or agreed to in writing, the software is
provided on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
either express or implied, including, without limitation, any warranties or
conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE.
==============================================================================
+142
View File
@@ -0,0 +1,142 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
=====================================================================
How to Build the LLVM* OpenMP* Offloading Runtime Library using CMake
=====================================================================
==== Version of CMake required: v2.8.0 or above ====
============================================
How to call cmake initially, then repeatedly
============================================
- When calling cmake for the first time, all needed compiler options
must be specified on the command line. After this initial call to
cmake, the compiler definitions must not be included for further calls
to cmake. Other options can be specified on the command line multiple
times including all definitions in the Build options section below.
- Example of configuring, building, reconfiguring, rebuilding:
$ mkdir build
$ cd build
$ cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ .. # Initial configuration
$ make
...
$ make clean
$ cmake -DCMAKE_BUILD_TYPE=Debug .. # Second configuration
$ make
...
$ rm -rf *
$ cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ .. # Third configuration
$ make
- Notice in the example how the compiler definitions are only specified
for an empty build directory, but other Build options are used at any time.
- The file CMakeCache.txt which is created after the first call to cmake
is a configuration file which holds all the values for the Build options.
These configuration values can be changed using a text editor to modify
CMakeCache.txt as opposed to using definitions on the command line.
- To have cmake create a particular type of build generator file simply
inlude the -G <Generator name> option:
$ cmake -G "Unix Makefiles" ...
You can see a list of generators cmake supports by executing cmake with
no arguments and a list will be printed.
=====================
Instructions to Build
=====================
$ cd libomptarget_top_level/ [ directory with plugins/ , deviceRTLs/ , etc. ]
$ mkdir build
$ cd build
[ Unix* Libraries ]
$ cmake -DCMAKE_C_COMPILER=<C Compiler> -DCMAKE_CXX_COMPILER=<C++ Compiler> ..
$ make
$ make install
===========
Tests
===========
After the library has been built, there are optional tests that can be
performed. Some will be skipped based upon the platform.
To run the tests,
$ make check-libomptarget
=============
CMake options
=============
-DCMAKE_C_COMPILER=<C compiler name>
Specify the C compiler
-DCMAKE_CXX_COMPILER=<C++ compiler name>
Specify the C++ compiler
==== First values listed are the default value ====
-DCMAKE_BUILD_TYPE=Release|Debug|RelWithDebInfo
Build type can be Release, Debug, or RelWithDebInfo.
-DLIBOMPTARGET_ENABLE_WERROR=true|false
Should consider warnings as errors.
-DLIBOMPTARGET_LLVM_LIT_EXECUTABLE=""
Full path to the llvm-lit tool. Required for testing in out-of-tree builds.
-DLIBOMPTARGET_FILECHECK_EXECUTABLE=""
Full path to the FileCheck tool. Required for testing in out-of-tree builds.
-DLIBOMPTARGET_OPENMP_HEADER_FOLDER=""
Path of the folder that contains omp.h. This is required for testing
out-of-tree builds.
-DLIBOMPTARGET_OPENMP_HOST_RTL_FOLDER=""
Path of the folder that contains libomp.so. This is required for testing
out-of-tree builds.
==== NVPTX device RTL specific ====
-DLIBOMPTARGET_NVPTX_ENABLE_BCLIB=false|true
Enable CUDA LLVM bitcode offloading device RTL. This is used for
link time optimization of the omp runtime and application code.
-DLIBOMPTARGET_NVPTX_CUDA_COMPILER=<CUDA compiler name>
Location of a CUDA compiler capable of emitting LLVM bitcode.
Currently only the Clang compiler is supported. This is only used
when building the CUDA LLVM bitcode offloading device RTL. If
unspecified, the default paths are inspected.
-DLIBOMPTARGET_NVPTX_BC_LINKER=<LLVM bitcode linker>
Location of a linker capable of linking LLVM bitcode objects.
This is only used when building the CUDA LLVM bitcode offloading
device RTL. If unspecified, the default paths are inspected.
-DLIBOMPTARGET_NVPTX_ALTERNATE_HOST_COMPILER=""
Host compiler to use with NVCC. This compiler is not going to be used to produce
any binary. Instead, this is used to overcome the input compiler checks done by
NVCC. E.g. if using a default host compiler that is not compatible with NVCC,
this option can be use to pass to NVCC a valid compiler to avoid the error.
-DLIBOMPTARGET_NVPTX_COMPUTE_CAPABILITY="35"
Comma-separated list of CUDA compute capabilities that should be supported by
the NVPTX device RTL. E.g. for compute capabilities 3.0 and 3.5, the option
"30,35" should be used.
=======================
Example usages of CMake
=======================
---- Typical usage ----
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
---- Request an NVPTX runtime library that supports compute capability 5.0 ----
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLIBOMPTARGET_NVPTX_COMPUTE_CAPABILITY="50"
=========
Footnotes
=========
[*] Other names and brands may be claimed as the property of others.
+119
View File
@@ -0,0 +1,119 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build offloading library libomptarget.so.
#
##===----------------------------------------------------------------------===##
# CMAKE libomptarget
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
# Add cmake directory to search for custom cmake functions.
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake/Modules ${CMAKE_MODULE_PATH})
# Standalone build or part of LLVM?
set(LIBOMPTARGET_STANDALONE_BUILD FALSE)
if("${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}" OR
"${CMAKE_SOURCE_DIR}/libomptarget" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
project(libomptarget C CXX)
set(LIBOMPTARGET_STANDALONE_BUILD TRUE)
endif()
if(${LIBOMPTARGET_STANDALONE_BUILD})
set(LIBOMPTARGET_ENABLE_WERROR FALSE CACHE BOOL
"Enable -Werror flags to turn warnings into errors for supporting compilers.")
# CMAKE_BUILD_TYPE was not defined, set default to Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
set(LIBOMPTARGET_LIBDIR_SUFFIX "" CACHE STRING
"suffix of lib installation directory, e.g. 64 => lib64")
else()
set(LIBOMPTARGET_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
# If building in tree, we honor the same install suffix LLVM uses.
set(LIBOMPTARGET_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX})
endif()
# Compiler flag checks.
include(config-ix)
# Message utilities.
include(LibomptargetUtils)
# Get dependencies for the different components of the project.
include(LibomptargetGetDependencies)
# This is a list of all the targets that are supported/tested right now.
set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} aarch64-unknown-linux-gnu")
set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} powerpc64le-ibm-linux-gnu")
set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} powerpc64-ibm-linux-gnu")
set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} x86_64-pc-linux-gnu")
set (LIBOMPTARGET_ALL_TARGETS "${LIBOMPTARGET_ALL_TARGETS} nvptx64-nvidia-cuda")
# Once the plugins for the different targets are validated, they will be added to
# the list of supported targets in the current system.
set (LIBOMPTARGET_SYSTEM_TARGETS "")
# Set base directories - required for lit to locate the tests.
set(LIBOMPTARGET_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LIBOMPTARGET_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# We need C++11 support.
if(LIBOMPTARGET_HAVE_STD_CPP11_FLAG)
libomptarget_say("Building offloading runtime library libomptarget.")
# Enable support for C++11.
add_definitions(-std=c++11)
if(LIBOMPTARGET_ENABLE_WERROR AND LIBOMPTARGET_HAVE_WERROR_FLAG)
add_definitions(-Werror)
endif()
# If building this library in debug mode, we define a macro to enable
# dumping progress messages at runtime.
string( TOLOWER "${CMAKE_BUILD_TYPE}" LIBOMPTARGET_CMAKE_BUILD_TYPE)
if(LIBOMPTARGET_CMAKE_BUILD_TYPE MATCHES debug)
add_definitions(-DOMPTARGET_DEBUG)
add_definitions(-g)
add_definitions(-O0)
endif()
set(src_files
src/omptarget.cpp
)
include_directories(src/)
# Build libomptarget library with libdl dependency.
add_library(omptarget SHARED ${src_files})
target_link_libraries(omptarget
${CMAKE_DL_LIBS}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/exports")
# Install libomptarget under the lib destination folder.
install(TARGETS omptarget LIBRARY DESTINATION lib${LIBOMPTARGET_LIBDIR_SUFFIX})
# Retrieve the path to the resulting library so that it can be used for
# testing.
get_target_property(LIBOMPTARGET_LIBRARY_DIR omptarget LIBRARY_OUTPUT_DIRECTORY)
if(NOT LIBOMPTARGET_LIBRARY_DIR)
set(LIBOMPTARGET_LIBRARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
endif()
# Build offloading plugins and device RTLs if they are available.
add_subdirectory(plugins)
# Add tests.
add_subdirectory(test)
else(LIBOMPTARGET_HAVE_STD_CPP11_FLAG)
libomptarget_say("Not building offloading runtime library libomptarget: host compiler must have c++11 support.")
endif(LIBOMPTARGET_HAVE_STD_CPP11_FLAG)
+74
View File
@@ -0,0 +1,74 @@
README for the LLVM* OpenMP* Offloading Runtime Library (libomptarget)
======================================================================
How to Build the LLVM* OpenMP* Offloading Runtime Library (libomptarget)
========================================================================
In-tree build:
$ cd where-you-want-to-live
Check out openmp (libomptarget lives under ./libomptarget) into llvm/projects
$ cd where-you-want-to-build
$ mkdir build && cd build
$ cmake path/to/llvm -DCMAKE_C_COMPILER=<C compiler> -DCMAKE_CXX_COMPILER=<C++ compiler>
$ make omptarget
Out-of-tree build:
$ cd where-you-want-to-live
Check out openmp (libomptarget lives under ./libomptarget)
$ cd where-you-want-to-live/openmp/libomptarget
$ mkdir build && cd build
$ cmake path/to/openmp -DCMAKE_C_COMPILER=<C compiler> -DCMAKE_CXX_COMPILER=<C++ compiler>
$ make
For details about building, please look at Build_With_CMake.txt
Architectures Supported
=======================
The current library has been only tested in Linux operating system and the
following host architectures:
* Intel(R) 64 architecture
* IBM(R) Power architecture (big endian)
* IBM(R) Power architecture (little endian)
* ARM(R) AArch64 architecture (little endian)
The currently supported offloading device architectures are:
* Intel(R) 64 architecture (generic 64-bit plugin - mostly for testing purposes)
* IBM(R) Power architecture (big endian) (generic 64-bit plugin - mostly for testing purposes)
* IBM(R) Power architecture (little endian) (generic 64-bit plugin - mostly for testing purposes)
* ARM(R) AArch64 architecture (little endian) (generic 64-bit plugin - mostly for testing purposes)
* CUDA(R) enabled 64-bit NVIDIA(R) GPU architectures
Supported RTL Build Configurations
==================================
Supported Architectures: Intel(R) 64, IBM(R) Power 7 and Power 8
---------------------------
| gcc | clang |
--------------|------------|------------|
| Linux* OS | Yes(1) | Yes(2) |
-----------------------------------------
(1) gcc version 4.8.2 or later is supported.
(2) clang version 3.7 or later is supported.
Front-end Compilers that work with this RTL
===========================================
The following compilers are known to do compatible code generation for
this RTL:
- clang (from https://github.com/clang-ykt )
- clang (development branch at http://clang.llvm.org - several features still
under development)
-----------------------------------------------------------------------
Notices
=======
This library and related compiler support is still under development, so the
employed interface is likely to change in the future.
*Other names and brands may be claimed as the property of others.
@@ -0,0 +1,124 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# Try to detect in the system several dependencies required by the different
# components of libomptarget. These are the dependencies we have:
#
# libelf : required by some targets to handle the ELF files at runtime.
# libffi : required to launch target kernels given function and argument
# pointers.
# CUDA : required to control offloading to NVIDIA GPUs.
include (FindPackageHandleStandardArgs)
################################################################################
# Looking for libelf...
################################################################################
find_path (
LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR
NAMES
libelf.h
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
ENV CPATH
PATH_SUFFIXES
libelf)
find_library (
LIBOMPTARGET_DEP_LIBELF_LIBRARIES
NAMES
elf
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
ENV LIBRARY_PATH
ENV LD_LIBRARY_PATH)
set(LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS ${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR})
find_package_handle_standard_args(
LIBOMPTARGET_DEP_LIBELF
DEFAULT_MSG
LIBOMPTARGET_DEP_LIBELF_LIBRARIES
LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS)
mark_as_advanced(
LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS
LIBOMPTARGET_DEP_LIBELF_LIBRARIES)
################################################################################
# Looking for libffi...
################################################################################
find_package(PkgConfig)
pkg_check_modules(LIBOMPTARGET_SEARCH_LIBFFI QUIET libffi)
find_path (
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR
NAMES
ffi.h
HINTS
${LIBOMPTARGET_SEARCH_LIBFFI_INCLUDEDIR}
${LIBOMPTARGET_SEARCH_LIBFFI_INCLUDE_DIRS}
PATHS
/usr/include
/usr/local/include
/opt/local/include
/sw/include
ENV CPATH)
# Don't bother look for the library if the header files were not found.
if (LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR)
find_library (
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES
NAMES
ffi
HINTS
${LIBOMPTARGET_SEARCH_LIBFFI_LIBDIR}
${LIBOMPTARGET_SEARCH_LIBFFI_LIBRARY_DIRS}
PATHS
/usr/lib
/usr/local/lib
/opt/local/lib
/sw/lib
ENV LIBRARY_PATH
ENV LD_LIBRARY_PATH)
endif()
set(LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS ${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR})
find_package_handle_standard_args(
LIBOMPTARGET_DEP_LIBFFI
DEFAULT_MSG
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS)
mark_as_advanced(
LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIRS
LIBOMPTARGET_DEP_LIBFFI_LIBRARIES)
################################################################################
# Looking for CUDA...
################################################################################
find_package(CUDA QUIET)
set(LIBOMPTARGET_DEP_CUDA_FOUND ${CUDA_FOUND})
set(LIBOMPTARGET_DEP_CUDA_LIBRARIES ${CUDA_LIBRARIES})
set(LIBOMPTARGET_DEP_CUDA_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS})
mark_as_advanced(
LIBOMPTARGET_DEP_CUDA_FOUND
LIBOMPTARGET_DEP_CUDA_INCLUDE_DIRS
LIBOMPTARGET_DEP_CUDA_LIBRARIES)
@@ -0,0 +1,28 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# void libomptarget_say(string message_to_user);
# - prints out message_to_user
macro(libomptarget_say message_to_user)
message(STATUS "LIBOMPTARGET: ${message_to_user}")
endmacro()
# void libomptarget_warning_say(string message_to_user);
# - prints out message_to_user with a warning
macro(libomptarget_warning_say message_to_user)
message(WARNING "LIBOMPTARGET: ${message_to_user}")
endmacro()
# void libomptarget_error_say(string message_to_user);
# - prints out message_to_user with an error and exits cmake
macro(libomptarget_error_say message_to_user)
message(FATAL_ERROR "LIBOMPTARGET: ${message_to_user}")
endmacro()
@@ -0,0 +1,17 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
include(CheckCCompilerFlag)
include(CheckCXXCompilerFlag)
# Checking C, CXX
check_cxx_compiler_flag(-std=c++11 LIBOMPTARGET_HAVE_STD_CPP11_FLAG)
check_c_compiler_flag(-Werror LIBOMPTARGET_HAVE_WERROR_FLAG)
+28
View File
@@ -0,0 +1,28 @@
VERS1.0 {
global:
__tgt_register_lib;
__tgt_unregister_lib;
__tgt_target_data_begin;
__tgt_target_data_end;
__tgt_target_data_update;
__tgt_target;
__tgt_target_teams;
__tgt_target_data_begin_nowait;
__tgt_target_data_end_nowait;
__tgt_target_data_update_nowait;
__tgt_target_nowait;
__tgt_target_teams_nowait;
omp_get_num_devices;
omp_get_initial_device;
omp_target_alloc;
omp_target_free;
omp_target_is_present;
omp_target_memcpy;
omp_target_memcpy_rect;
omp_target_associate_ptr;
omp_target_disassociate_ptr;
__kmpc_push_target_tripcount;
local:
*;
};
+72
View File
@@ -0,0 +1,72 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build plugins for the user system if available.
#
##===----------------------------------------------------------------------===##
# void build_generic_elf64(string tmachine, string tmachine_name, string tmachine_libname, string elf_machine_id);
# - build a plugin for an ELF based generic 64-bit target based on libffi.
# - tmachine: name of the machine processor as used in the cmake build system.
# - tmachine_name: name of the machine to be printed with the debug messages.
# - tmachine_libname: machine name to be appended to the plugin library name.
macro(build_generic_elf64 tmachine tmachine_name tmachine_libname tmachine_triple elf_machine_id)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "${tmachine}$")
if(LIBOMPTARGET_DEP_LIBELF_FOUND)
if(LIBOMPTARGET_DEP_LIBFFI_FOUND)
libomptarget_say("Building ${tmachine_name} offloading plugin.")
include_directories(${LIBOMPTARGET_DEP_LIBFFI_INCLUDE_DIR})
include_directories(${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIR})
# Define macro to be used as prefix of the runtime messages for this target.
add_definitions("-DTARGET_NAME=${tmachine_name}")
# Define macro with the ELF ID for this target.
add_definitions("-DTARGET_ELF_ID=${elf_machine_id}")
add_library("omptarget.rtl.${tmachine_libname}" SHARED
${CMAKE_CURRENT_SOURCE_DIR}/../generic-elf-64bit/src/rtl.cpp)
# Install plugin under the lib destination folder.
install(TARGETS "omptarget.rtl.${tmachine_libname}"
LIBRARY DESTINATION lib${LIBOMPTARGET_LIBDIR_SUFFIX})
target_link_libraries(
"omptarget.rtl.${tmachine_libname}"
${LIBOMPTARGET_DEP_LIBFFI_LIBRARIES}
${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
dl
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports")
# Report to the parent scope that we are building a plugin.
set(LIBOMPTARGET_SYSTEM_TARGETS
"${LIBOMPTARGET_SYSTEM_TARGETS} ${tmachine_triple}" PARENT_SCOPE)
else(LIBOMPTARGET_DEP_LIBFFI_FOUND)
libomptarget_say("Not building ${tmachine_name} offloading plugin: libffi dependency not found.")
endif(LIBOMPTARGET_DEP_LIBFFI_FOUND)
else(LIBOMPTARGET_DEP_LIBELF_FOUND)
libomptarget_say("Not building ${tmachine_name} offloading plugin: libelf dependency not found.")
endif(LIBOMPTARGET_DEP_LIBELF_FOUND)
else()
libomptarget_say("Not building ${tmachine_name} offloading plugin: machine not found in the system.")
endif()
endmacro()
add_subdirectory(aarch64)
add_subdirectory(cuda)
add_subdirectory(ppc64)
add_subdirectory(ppc64le)
add_subdirectory(x86_64)
# Make sure the parent scope can see the plugins that will be created.
set(LIBOMPTARGET_SYSTEM_TARGETS "${LIBOMPTARGET_SYSTEM_TARGETS}" PARENT_SCOPE)
@@ -0,0 +1,18 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for an aarch64 machine if available.
#
##===----------------------------------------------------------------------===##
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64("aarch64" "aarch64" "aarch64" "aarch64-unknown-linux-gnu" "183")
else()
libomptarget_say("Not building aarch64 offloading plugin: machine not found in the system.")
endif()
@@ -0,0 +1,73 @@
//===-- elf_common.c - Common ELF functionality -------------------*- C -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//
// Common ELF functionality for target plugins.
// Must be included in the plugin source file AFTER omptarget.h has been
// included and macro DP(...) has been defined.
// .
//
//===----------------------------------------------------------------------===//
#if !(defined(_OMPTARGET_H_) && defined(DP))
#error Include elf_common.c in the plugin source AFTER omptarget.h has been\
included and macro DP(...) has been defined.
#endif
#include <elf.h>
#include <libelf.h>
// Check whether an image is valid for execution on target_id
static inline int32_t elf_check_machine(__tgt_device_image *image,
uint16_t target_id) {
// Is the library version incompatible with the header file?
if (elf_version(EV_CURRENT) == EV_NONE) {
DP("Incompatible ELF library!\n");
return 0;
}
char *img_begin = (char *)image->ImageStart;
char *img_end = (char *)image->ImageEnd;
size_t img_size = img_end - img_begin;
// Obtain elf handler
Elf *e = elf_memory(img_begin, img_size);
if (!e) {
DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1));
return 0;
}
// Check if ELF is the right kind.
if (elf_kind(e) != ELF_K_ELF) {
DP("Unexpected ELF type!\n");
return 0;
}
Elf64_Ehdr *eh64 = elf64_getehdr(e);
Elf32_Ehdr *eh32 = elf32_getehdr(e);
if (!eh64 && !eh32) {
DP("Unable to get machine ID from ELF file!\n");
elf_end(e);
return 0;
}
uint16_t MachineID;
if (eh64 && !eh32)
MachineID = eh64->e_machine;
else if (eh32 && !eh64)
MachineID = eh32->e_machine;
else {
DP("Ambiguous ELF header!\n");
elf_end(e);
return 0;
}
elf_end(e);
return MachineID == target_id;
}
@@ -0,0 +1,50 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a CUDA machine if available.
#
##===----------------------------------------------------------------------===##
if(LIBOMPTARGET_DEP_LIBELF_FOUND)
if(LIBOMPTARGET_DEP_CUDA_FOUND)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "(x86_64)|(ppc64le)$" AND CMAKE_SYSTEM_NAME MATCHES "Linux")
libomptarget_say("Building CUDA offloading plugin.")
# Define the suffix for the runtime messaging dumps.
add_definitions(-DTARGET_NAME=CUDA)
if(LIBOMPTARGET_CMAKE_BUILD_TYPE MATCHES debug)
add_definitions(-DCUDA_ERROR_REPORT)
endif()
include_directories(${LIBOMPTARGET_DEP_CUDA_INCLUDE_DIRS})
include_directories(${LIBOMPTARGET_DEP_LIBELF_INCLUDE_DIRS})
add_library(omptarget.rtl.cuda SHARED src/rtl.cpp)
# Install plugin under the lib destination folder.
install(TARGETS omptarget.rtl.cuda LIBRARY DESTINATION lib${LIBOMPTARGET_LIBDIR_SUFFIX})
target_link_libraries(omptarget.rtl.cuda
${LIBOMPTARGET_DEP_CUDA_LIBRARIES}
cuda
${LIBOMPTARGET_DEP_LIBELF_LIBRARIES}
"-Wl,--version-script=${CMAKE_CURRENT_SOURCE_DIR}/../exports")
# Report to the parent scope that we are building a plugin for CUDA.
set(LIBOMPTARGET_SYSTEM_TARGETS "${LIBOMPTARGET_SYSTEM_TARGETS} nvptx64-nvidia-cuda" PARENT_SCOPE)
else()
libomptarget_say("Not building CUDA offloading plugin: only support CUDA in Linux x86_64 or ppc64le hosts.")
endif()
else()
libomptarget_say("Not building CUDA offloading plugin: CUDA not found in system.")
endif()
else(LIBOMPTARGET_DEP_LIBELF_FOUND)
libomptarget_say("Not building CUDA offloading plugin: libelf dependency not found.")
endif(LIBOMPTARGET_DEP_LIBELF_FOUND)
+694
View File
@@ -0,0 +1,694 @@
//===----RTLs/cuda/src/rtl.cpp - Target RTLs Implementation ------- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//
// RTL for CUDA machine
//
//===----------------------------------------------------------------------===//
#include <cassert>
#include <cstddef>
#include <cuda.h>
#include <cuda_runtime_api.h>
#include <list>
#include <string>
#include <vector>
#include "omptargetplugin.h"
#ifndef TARGET_NAME
#define TARGET_NAME CUDA
#endif
#define GETNAME2(name) #name
#define GETNAME(name) GETNAME2(name)
#define DP(...) DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__)
#include "../../common/elf_common.c"
// Utility for retrieving and printing CUDA error string.
#ifdef CUDA_ERROR_REPORT
#define CUDA_ERR_STRING(err) \
do { \
const char *errStr; \
cuGetErrorString(err, &errStr); \
DP("CUDA error is: %s\n", errStr); \
} while (0)
#else
#define CUDA_ERR_STRING(err) \
{}
#endif
/// Keep entries table per device.
struct FuncOrGblEntryTy {
__tgt_target_table Table;
std::vector<__tgt_offload_entry> Entries;
};
enum ExecutionModeType {
SPMD, // constructors, destructors,
// combined constructs (`teams distribute parallel for [simd]`)
GENERIC, // everything else
NONE
};
/// Use a single entity to encode a kernel and a set of flags
struct KernelTy {
CUfunction Func;
// execution mode of kernel
// 0 - SPMD mode (without master warp)
// 1 - Generic mode (with master warp)
int8_t ExecutionMode;
KernelTy(CUfunction _Func, int8_t _ExecutionMode)
: Func(_Func), ExecutionMode(_ExecutionMode) {}
};
/// List that contains all the kernels.
/// FIXME: we may need this to be per device and per library.
std::list<KernelTy> KernelsList;
/// Class containing all the device information.
class RTLDeviceInfoTy {
std::vector<FuncOrGblEntryTy> FuncGblEntries;
public:
int NumberOfDevices;
std::vector<CUmodule> Modules;
std::vector<CUcontext> Contexts;
// Device properties
std::vector<int> ThreadsPerBlock;
std::vector<int> BlocksPerGrid;
std::vector<int> WarpSize;
// OpenMP properties
std::vector<int> NumTeams;
std::vector<int> NumThreads;
// OpenMP Environment properties
int EnvNumTeams;
int EnvTeamLimit;
//static int EnvNumThreads;
static const int HardTeamLimit = 1<<16; // 64k
static const int HardThreadLimit = 1024;
static const int DefaultNumTeams = 128;
static const int DefaultNumThreads = 128;
// Record entry point associated with device
void addOffloadEntry(int32_t device_id, __tgt_offload_entry entry) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
E.Entries.push_back(entry);
}
// Return true if the entry is associated with device
bool findOffloadEntry(int32_t device_id, void *addr) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
for (auto &it : E.Entries) {
if (it.addr == addr)
return true;
}
return false;
}
// Return the pointer to the target entries table
__tgt_target_table *getOffloadEntriesTable(int32_t device_id) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
int32_t size = E.Entries.size();
// Table is empty
if (!size)
return 0;
__tgt_offload_entry *begin = &E.Entries[0];
__tgt_offload_entry *end = &E.Entries[size - 1];
// Update table info according to the entries and return the pointer
E.Table.EntriesBegin = begin;
E.Table.EntriesEnd = ++end;
return &E.Table;
}
// Clear entries table for a device
void clearOffloadEntriesTable(int32_t device_id) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
E.Entries.clear();
E.Table.EntriesBegin = E.Table.EntriesEnd = 0;
}
RTLDeviceInfoTy() {
DP("Start initializing CUDA\n");
CUresult err = cuInit(0);
if (err != CUDA_SUCCESS) {
DP("Error when initializing CUDA\n");
CUDA_ERR_STRING(err);
return;
}
NumberOfDevices = 0;
err = cuDeviceGetCount(&NumberOfDevices);
if (err != CUDA_SUCCESS) {
DP("Error when getting CUDA device count\n");
CUDA_ERR_STRING(err);
return;
}
if (NumberOfDevices == 0) {
DP("There are no devices supporting CUDA.\n");
return;
}
FuncGblEntries.resize(NumberOfDevices);
Contexts.resize(NumberOfDevices);
ThreadsPerBlock.resize(NumberOfDevices);
BlocksPerGrid.resize(NumberOfDevices);
WarpSize.resize(NumberOfDevices);
NumTeams.resize(NumberOfDevices);
NumThreads.resize(NumberOfDevices);
// Get environment variables regarding teams
char *envStr = getenv("OMP_TEAM_LIMIT");
if (envStr) {
// OMP_TEAM_LIMIT has been set
EnvTeamLimit = std::stoi(envStr);
DP("Parsed OMP_TEAM_LIMIT=%d\n", EnvTeamLimit);
} else {
EnvTeamLimit = -1;
}
envStr = getenv("OMP_NUM_TEAMS");
if (envStr) {
// OMP_NUM_TEAMS has been set
EnvNumTeams = std::stoi(envStr);
DP("Parsed OMP_NUM_TEAMS=%d\n", EnvNumTeams);
} else {
EnvNumTeams = -1;
}
}
~RTLDeviceInfoTy() {
// Close modules
for (auto &module : Modules)
if (module) {
CUresult err = cuModuleUnload(module);
if (err != CUDA_SUCCESS) {
DP("Error when unloading CUDA module\n");
CUDA_ERR_STRING(err);
}
}
// Destroy contexts
for (auto &ctx : Contexts)
if (ctx) {
CUresult err = cuCtxDestroy(ctx);
if (err != CUDA_SUCCESS) {
DP("Error when destroying CUDA context\n");
CUDA_ERR_STRING(err);
}
}
}
};
static RTLDeviceInfoTy DeviceInfo;
#ifdef __cplusplus
extern "C" {
#endif
int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) {
return elf_check_machine(image, 190); // EM_CUDA = 190.
}
int32_t __tgt_rtl_number_of_devices() { return DeviceInfo.NumberOfDevices; }
int32_t __tgt_rtl_init_device(int32_t device_id) {
CUdevice cuDevice;
DP("Getting device %d\n", device_id);
CUresult err = cuDeviceGet(&cuDevice, device_id);
if (err != CUDA_SUCCESS) {
DP("Error when getting CUDA device with id = %d\n", device_id);
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
// Create the context and save it to use whenever this device is selected.
err = cuCtxCreate(&DeviceInfo.Contexts[device_id], CU_CTX_SCHED_BLOCKING_SYNC,
cuDevice);
if (err != CUDA_SUCCESS) {
DP("Error when creating a CUDA context\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
// scan properties to determine number of threads/block and blocks/grid.
struct cudaDeviceProp Properties;
cudaError_t error = cudaGetDeviceProperties(&Properties, device_id);
if (error != cudaSuccess) {
DP("Error getting device Properties, use defaults\n");
DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::DefaultNumTeams;
DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::DefaultNumThreads;
DeviceInfo.WarpSize[device_id] = 32;
} else {
// Get blocks per grid
if (Properties.maxGridSize[0] <= RTLDeviceInfoTy::HardTeamLimit) {
DeviceInfo.BlocksPerGrid[device_id] = Properties.maxGridSize[0];
DP("Using %d CUDA blocks per grid\n", Properties.maxGridSize[0]);
} else {
DeviceInfo.BlocksPerGrid[device_id] = RTLDeviceInfoTy::HardTeamLimit;
DP("Max CUDA blocks per grid %d exceeds the hard team limit %d, capping "
"at the hard limit\n", Properties.maxGridSize[0],
RTLDeviceInfoTy::HardTeamLimit);
}
// Get threads per block, exploit threads only along x axis
if (Properties.maxThreadsDim[0] <= RTLDeviceInfoTy::HardThreadLimit) {
DeviceInfo.ThreadsPerBlock[device_id] = Properties.maxThreadsDim[0];
DP("Using %d CUDA threads per block\n", Properties.maxThreadsDim[0]);
if (Properties.maxThreadsDim[0] < Properties.maxThreadsPerBlock) {
DP("(fewer than max per block along all xyz dims %d)\n",
Properties.maxThreadsPerBlock);
}
} else {
DeviceInfo.ThreadsPerBlock[device_id] = RTLDeviceInfoTy::HardThreadLimit;
DP("Max CUDA threads per block %d exceeds the hard thread limit %d, "
"capping at the hard limit\n", Properties.maxThreadsDim[0],
RTLDeviceInfoTy::HardThreadLimit);
}
// Get warp size
DeviceInfo.WarpSize[device_id] = Properties.warpSize;
}
// Adjust teams to the env variables
if (DeviceInfo.EnvTeamLimit > 0 &&
DeviceInfo.BlocksPerGrid[device_id] > DeviceInfo.EnvTeamLimit) {
DeviceInfo.BlocksPerGrid[device_id] = DeviceInfo.EnvTeamLimit;
DP("Capping max CUDA blocks per grid to OMP_TEAM_LIMIT=%d\n",
DeviceInfo.EnvTeamLimit);
}
DP("Max number of CUDA blocks %d, threads %d & warp size %d\n",
DeviceInfo.BlocksPerGrid[device_id], DeviceInfo.ThreadsPerBlock[device_id],
DeviceInfo.WarpSize[device_id]);
// Set default number of teams
if (DeviceInfo.EnvNumTeams > 0) {
DeviceInfo.NumTeams[device_id] = DeviceInfo.EnvNumTeams;
DP("Default number of teams set according to environment %d\n",
DeviceInfo.EnvNumTeams);
} else {
DeviceInfo.NumTeams[device_id] = RTLDeviceInfoTy::DefaultNumTeams;
DP("Default number of teams set according to library's default %d\n",
RTLDeviceInfoTy::DefaultNumTeams);
}
if (DeviceInfo.NumTeams[device_id] > DeviceInfo.BlocksPerGrid[device_id]) {
DeviceInfo.NumTeams[device_id] = DeviceInfo.BlocksPerGrid[device_id];
DP("Default number of teams exceeds device limit, capping at %d\n",
DeviceInfo.BlocksPerGrid[device_id]);
}
// Set default number of threads
DeviceInfo.NumThreads[device_id] = RTLDeviceInfoTy::DefaultNumThreads;
DP("Default number of threads set according to library's default %d\n",
RTLDeviceInfoTy::DefaultNumThreads);
if (DeviceInfo.NumThreads[device_id] >
DeviceInfo.ThreadsPerBlock[device_id]) {
DeviceInfo.NumTeams[device_id] = DeviceInfo.ThreadsPerBlock[device_id];
DP("Default number of threads exceeds device limit, capping at %d\n",
DeviceInfo.ThreadsPerBlock[device_id]);
}
return OFFLOAD_SUCCESS;
}
__tgt_target_table *__tgt_rtl_load_binary(int32_t device_id,
__tgt_device_image *image) {
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error when setting a CUDA context for device %d\n", device_id);
CUDA_ERR_STRING(err);
return NULL;
}
// Clear the offload table as we are going to create a new one.
DeviceInfo.clearOffloadEntriesTable(device_id);
// Create the module and extract the function pointers.
CUmodule cumod;
DP("Load data from image " DPxMOD "\n", DPxPTR(image->ImageStart));
err = cuModuleLoadDataEx(&cumod, image->ImageStart, 0, NULL, NULL);
if (err != CUDA_SUCCESS) {
DP("Error when loading CUDA module\n");
CUDA_ERR_STRING(err);
return NULL;
}
DP("CUDA module successfully loaded!\n");
DeviceInfo.Modules.push_back(cumod);
// Find the symbols in the module by name.
__tgt_offload_entry *HostBegin = image->EntriesBegin;
__tgt_offload_entry *HostEnd = image->EntriesEnd;
for (__tgt_offload_entry *e = HostBegin; e != HostEnd; ++e) {
if (!e->addr) {
// We return NULL when something like this happens, the host should have
// always something in the address to uniquely identify the target region.
DP("Invalid binary: host entry '<null>' (size = %zd)...\n", e->size);
return NULL;
}
if (e->size) {
__tgt_offload_entry entry = *e;
CUdeviceptr cuptr;
size_t cusize;
err = cuModuleGetGlobal(&cuptr, &cusize, cumod, e->name);
if (err != CUDA_SUCCESS) {
DP("Loading global '%s' (Failed)\n", e->name);
CUDA_ERR_STRING(err);
return NULL;
}
if (cusize != e->size) {
DP("Loading global '%s' - size mismatch (%zd != %zd)\n", e->name,
cusize, e->size);
CUDA_ERR_STRING(err);
return NULL;
}
DP("Entry point " DPxMOD " maps to global %s (" DPxMOD ")\n",
DPxPTR(e - HostBegin), e->name, DPxPTR(cuptr));
entry.addr = (void *)cuptr;
DeviceInfo.addOffloadEntry(device_id, entry);
continue;
}
CUfunction fun;
err = cuModuleGetFunction(&fun, cumod, e->name);
if (err != CUDA_SUCCESS) {
DP("Loading '%s' (Failed)\n", e->name);
CUDA_ERR_STRING(err);
return NULL;
}
DP("Entry point " DPxMOD " maps to %s (" DPxMOD ")\n",
DPxPTR(e - HostBegin), e->name, DPxPTR(fun));
// default value GENERIC (in case symbol is missing from cubin file)
int8_t ExecModeVal = ExecutionModeType::GENERIC;
std::string ExecModeNameStr (e->name);
ExecModeNameStr += "_exec_mode";
const char *ExecModeName = ExecModeNameStr.c_str();
CUdeviceptr ExecModePtr;
size_t cusize;
err = cuModuleGetGlobal(&ExecModePtr, &cusize, cumod, ExecModeName);
if (err == CUDA_SUCCESS) {
if ((size_t)cusize != sizeof(int8_t)) {
DP("Loading global exec_mode '%s' - size mismatch (%zd != %zd)\n",
ExecModeName, cusize, sizeof(int8_t));
CUDA_ERR_STRING(err);
return NULL;
}
err = cuMemcpyDtoH(&ExecModeVal, ExecModePtr, cusize);
if (err != CUDA_SUCCESS) {
DP("Error when copying data from device to host. Pointers: "
"host = " DPxMOD ", device = " DPxMOD ", size = %zd\n",
DPxPTR(&ExecModeVal), DPxPTR(ExecModePtr), cusize);
CUDA_ERR_STRING(err);
return NULL;
}
if (ExecModeVal < 0 || ExecModeVal > 1) {
DP("Error wrong exec_mode value specified in cubin file: %d\n",
ExecModeVal);
return NULL;
}
} else {
DP("Loading global exec_mode '%s' - symbol missing, using default value "
"GENERIC (1)\n", ExecModeName);
CUDA_ERR_STRING(err);
}
KernelsList.push_back(KernelTy(fun, ExecModeVal));
__tgt_offload_entry entry = *e;
entry.addr = (void *)&KernelsList.back();
DeviceInfo.addOffloadEntry(device_id, entry);
}
return DeviceInfo.getOffloadEntriesTable(device_id);
}
void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) {
if (size == 0) {
return NULL;
}
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error while trying to set CUDA current context\n");
CUDA_ERR_STRING(err);
return NULL;
}
CUdeviceptr ptr;
err = cuMemAlloc(&ptr, size);
if (err != CUDA_SUCCESS) {
DP("Error while trying to allocate %d\n", err);
CUDA_ERR_STRING(err);
return NULL;
}
void *vptr = (void *)ptr;
return vptr;
}
int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr,
int64_t size) {
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error when setting CUDA context\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
err = cuMemcpyHtoD((CUdeviceptr)tgt_ptr, hst_ptr, size);
if (err != CUDA_SUCCESS) {
DP("Error when copying data from host to device. Pointers: host = " DPxMOD
", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr),
DPxPTR(tgt_ptr), size);
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr,
int64_t size) {
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error when setting CUDA context\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
err = cuMemcpyDtoH(hst_ptr, (CUdeviceptr)tgt_ptr, size);
if (err != CUDA_SUCCESS) {
DP("Error when copying data from device to host. Pointers: host = " DPxMOD
", device = " DPxMOD ", size = %" PRId64 "\n", DPxPTR(hst_ptr),
DPxPTR(tgt_ptr), size);
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) {
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error when setting CUDA context\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
err = cuMemFree((CUdeviceptr)tgt_ptr);
if (err != CUDA_SUCCESS) {
DP("Error when freeing CUDA memory\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr,
void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num,
int32_t thread_limit, uint64_t loop_tripcount) {
// Set the context we are using.
CUresult err = cuCtxSetCurrent(DeviceInfo.Contexts[device_id]);
if (err != CUDA_SUCCESS) {
DP("Error when setting CUDA context\n");
CUDA_ERR_STRING(err);
return OFFLOAD_FAIL;
}
// All args are references.
std::vector<void *> args(arg_num);
std::vector<void *> ptrs(arg_num);
for (int32_t i = 0; i < arg_num; ++i) {
ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]);
args[i] = &ptrs[i];
}
KernelTy *KernelInfo = (KernelTy *)tgt_entry_ptr;
int cudaThreadsPerBlock;
if (thread_limit > 0) {
cudaThreadsPerBlock = thread_limit;
DP("Setting CUDA threads per block to requested %d\n", thread_limit);
// Add master warp if necessary
if (KernelInfo->ExecutionMode == GENERIC) {
cudaThreadsPerBlock += DeviceInfo.WarpSize[device_id];
DP("Adding master warp: +%d threads\n", DeviceInfo.WarpSize[device_id]);
}
} else {
cudaThreadsPerBlock = DeviceInfo.NumThreads[device_id];
DP("Setting CUDA threads per block to default %d\n",
DeviceInfo.NumThreads[device_id]);
}
if (cudaThreadsPerBlock > DeviceInfo.ThreadsPerBlock[device_id]) {
cudaThreadsPerBlock = DeviceInfo.ThreadsPerBlock[device_id];
DP("Threads per block capped at device limit %d\n",
DeviceInfo.ThreadsPerBlock[device_id]);
}
int kernel_limit;
err = cuFuncGetAttribute(&kernel_limit,
CU_FUNC_ATTRIBUTE_MAX_THREADS_PER_BLOCK, KernelInfo->Func);
if (err == CUDA_SUCCESS) {
if (kernel_limit < cudaThreadsPerBlock) {
cudaThreadsPerBlock = kernel_limit;
DP("Threads per block capped at kernel limit %d\n", kernel_limit);
}
}
int cudaBlocksPerGrid;
if (team_num <= 0) {
if (loop_tripcount > 0 && DeviceInfo.EnvNumTeams < 0) {
if (KernelInfo->ExecutionMode == SPMD) {
// We have a combined construct, i.e. `target teams distribute parallel
// for [simd]`. We launch so many teams so that each thread will
// execute one iteration of the loop.
// round up to the nearest integer
cudaBlocksPerGrid = ((loop_tripcount - 1) / cudaThreadsPerBlock) + 1;
} else {
// If we reach this point, then we have a non-combined construct, i.e.
// `teams distribute` with a nested `parallel for` and each team is
// assigned one iteration of the `distribute` loop. E.g.:
//
// #pragma omp target teams distribute
// for(...loop_tripcount...) {
// #pragma omp parallel for
// for(...) {}
// }
//
// Threads within a team will execute the iterations of the `parallel`
// loop.
cudaBlocksPerGrid = loop_tripcount;
}
DP("Using %d teams due to loop trip count %" PRIu64 " and number of "
"threads per block %d\n", cudaBlocksPerGrid, loop_tripcount,
cudaThreadsPerBlock);
} else {
cudaBlocksPerGrid = DeviceInfo.NumTeams[device_id];
DP("Using default number of teams %d\n", DeviceInfo.NumTeams[device_id]);
}
} else if (team_num > DeviceInfo.BlocksPerGrid[device_id]) {
cudaBlocksPerGrid = DeviceInfo.BlocksPerGrid[device_id];
DP("Capping number of teams to team limit %d\n",
DeviceInfo.BlocksPerGrid[device_id]);
} else {
cudaBlocksPerGrid = team_num;
DP("Using requested number of teams %d\n", team_num);
}
// Run on the device.
DP("Launch kernel with %d blocks and %d threads\n", cudaBlocksPerGrid,
cudaThreadsPerBlock);
err = cuLaunchKernel(KernelInfo->Func, cudaBlocksPerGrid, 1, 1,
cudaThreadsPerBlock, 1, 1, 0 /*bytes of shared memory*/, 0, &args[0], 0);
if (err != CUDA_SUCCESS) {
DP("Device kernel launch failed!\n");
CUDA_ERR_STRING(err);
assert(err == CUDA_SUCCESS && "Unable to launch target execution!");
return OFFLOAD_FAIL;
}
DP("Launch of entry point at " DPxMOD " successful!\n",
DPxPTR(tgt_entry_ptr));
cudaError_t sync_error = cudaDeviceSynchronize();
if (sync_error != cudaSuccess) {
DP("Kernel execution error at " DPxMOD ", %s.\n", DPxPTR(tgt_entry_ptr),
cudaGetErrorString(sync_error));
return OFFLOAD_FAIL;
} else {
DP("Kernel execution at " DPxMOD " successful!\n", DPxPTR(tgt_entry_ptr));
}
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr,
void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num) {
// use one team and the default number of threads.
const int32_t team_num = 1;
const int32_t thread_limit = 0;
return __tgt_rtl_run_target_team_region(device_id, tgt_entry_ptr, tgt_args,
tgt_offsets, arg_num, team_num, thread_limit, 0);
}
#ifdef __cplusplus
}
#endif
+15
View File
@@ -0,0 +1,15 @@
VERS1.0 {
global:
__tgt_rtl_is_valid_binary;
__tgt_rtl_number_of_devices;
__tgt_rtl_init_device;
__tgt_rtl_load_binary;
__tgt_rtl_data_alloc;
__tgt_rtl_data_submit;
__tgt_rtl_data_retrieve;
__tgt_rtl_data_delete;
__tgt_rtl_run_target_team_region;
__tgt_rtl_run_target_region;
local:
*;
};
@@ -0,0 +1,319 @@
//===-RTLs/generic-64bit/src/rtl.cpp - Target RTLs Implementation - C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//
// RTL for generic 64-bit machine
//
//===----------------------------------------------------------------------===//
#include <cassert>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <dlfcn.h>
#include <ffi.h>
#include <gelf.h>
#include <link.h>
#include <list>
#include <vector>
#include "omptargetplugin.h"
#ifndef TARGET_NAME
#define TARGET_NAME Generic ELF - 64bit
#endif
#ifndef TARGET_ELF_ID
#define TARGET_ELF_ID 0
#endif
#define GETNAME2(name) #name
#define GETNAME(name) GETNAME2(name)
#define DP(...) DEBUGP("Target " GETNAME(TARGET_NAME) " RTL", __VA_ARGS__)
#include "../../common/elf_common.c"
#define NUMBER_OF_DEVICES 4
#define OFFLOADSECTIONNAME ".omp_offloading.entries"
/// Array of Dynamic libraries loaded for this target.
struct DynLibTy {
char *FileName;
void *Handle;
};
/// Keep entries table per device.
struct FuncOrGblEntryTy {
__tgt_target_table Table;
};
/// Class containing all the device information.
class RTLDeviceInfoTy {
std::vector<FuncOrGblEntryTy> FuncGblEntries;
public:
std::list<DynLibTy> DynLibs;
// Record entry point associated with device.
void createOffloadTable(int32_t device_id, __tgt_offload_entry *begin,
__tgt_offload_entry *end) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
E.Table.EntriesBegin = begin;
E.Table.EntriesEnd = end;
}
// Return true if the entry is associated with device.
bool findOffloadEntry(int32_t device_id, void *addr) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
for (__tgt_offload_entry *i = E.Table.EntriesBegin, *e = E.Table.EntriesEnd;
i < e; ++i) {
if (i->addr == addr)
return true;
}
return false;
}
// Return the pointer to the target entries table.
__tgt_target_table *getOffloadEntriesTable(int32_t device_id) {
assert(device_id < (int32_t)FuncGblEntries.size() &&
"Unexpected device id!");
FuncOrGblEntryTy &E = FuncGblEntries[device_id];
return &E.Table;
}
RTLDeviceInfoTy(int32_t num_devices) { FuncGblEntries.resize(num_devices); }
~RTLDeviceInfoTy() {
// Close dynamic libraries
for (auto &lib : DynLibs) {
if (lib.Handle) {
dlclose(lib.Handle);
remove(lib.FileName);
}
}
}
};
static RTLDeviceInfoTy DeviceInfo(NUMBER_OF_DEVICES);
#ifdef __cplusplus
extern "C" {
#endif
int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *image) {
// If we don't have a valid ELF ID we can just fail.
#if TARGET_ELF_ID < 1
return 0;
#else
return elf_check_machine(image, TARGET_ELF_ID);
#endif
}
int32_t __tgt_rtl_number_of_devices() { return NUMBER_OF_DEVICES; }
int32_t __tgt_rtl_init_device(int32_t device_id) { return OFFLOAD_SUCCESS; }
__tgt_target_table *__tgt_rtl_load_binary(int32_t device_id,
__tgt_device_image *image) {
DP("Dev %d: load binary from " DPxMOD " image\n", device_id,
DPxPTR(image->ImageStart));
assert(device_id >= 0 && device_id < NUMBER_OF_DEVICES && "bad dev id");
size_t ImageSize = (size_t)image->ImageEnd - (size_t)image->ImageStart;
size_t NumEntries = (size_t)(image->EntriesEnd - image->EntriesBegin);
DP("Expecting to have %zd entries defined.\n", NumEntries);
// Is the library version incompatible with the header file?
if (elf_version(EV_CURRENT) == EV_NONE) {
DP("Incompatible ELF library!\n");
return NULL;
}
// Obtain elf handler
Elf *e = elf_memory((char *)image->ImageStart, ImageSize);
if (!e) {
DP("Unable to get ELF handle: %s!\n", elf_errmsg(-1));
return NULL;
}
if (elf_kind(e) != ELF_K_ELF) {
DP("Invalid Elf kind!\n");
elf_end(e);
return NULL;
}
// Find the entries section offset
Elf_Scn *section = 0;
Elf64_Off entries_offset = 0;
size_t shstrndx;
if (elf_getshdrstrndx(e, &shstrndx)) {
DP("Unable to get ELF strings index!\n");
elf_end(e);
return NULL;
}
while ((section = elf_nextscn(e, section))) {
GElf_Shdr hdr;
gelf_getshdr(section, &hdr);
if (!strcmp(elf_strptr(e, shstrndx, hdr.sh_name), OFFLOADSECTIONNAME)) {
entries_offset = hdr.sh_addr;
break;
}
}
if (!entries_offset) {
DP("Entries Section Offset Not Found\n");
elf_end(e);
return NULL;
}
DP("Offset of entries section is (" DPxMOD ").\n", DPxPTR(entries_offset));
// load dynamic library and get the entry points. We use the dl library
// to do the loading of the library, but we could do it directly to avoid the
// dump to the temporary file.
//
// 1) Create tmp file with the library contents.
// 2) Use dlopen to load the file and dlsym to retrieve the symbols.
char tmp_name[] = "/tmp/tmpfile_XXXXXX";
int tmp_fd = mkstemp(tmp_name);
if (tmp_fd == -1) {
elf_end(e);
return NULL;
}
FILE *ftmp = fdopen(tmp_fd, "wb");
if (!ftmp) {
elf_end(e);
return NULL;
}
fwrite(image->ImageStart, ImageSize, 1, ftmp);
fclose(ftmp);
DynLibTy Lib = {tmp_name, dlopen(tmp_name, RTLD_LAZY)};
if (!Lib.Handle) {
DP("Target library loading error: %s\n", dlerror());
elf_end(e);
return NULL;
}
DeviceInfo.DynLibs.push_back(Lib);
struct link_map *libInfo = (struct link_map *)Lib.Handle;
// The place where the entries info is loaded is the library base address
// plus the offset determined from the ELF file.
Elf64_Addr entries_addr = libInfo->l_addr + entries_offset;
DP("Pointer to first entry to be loaded is (" DPxMOD ").\n",
DPxPTR(entries_addr));
// Table of pointers to all the entries in the target.
__tgt_offload_entry *entries_table = (__tgt_offload_entry *)entries_addr;
__tgt_offload_entry *entries_begin = &entries_table[0];
__tgt_offload_entry *entries_end = entries_begin + NumEntries;
if (!entries_begin) {
DP("Can't obtain entries begin\n");
elf_end(e);
return NULL;
}
DP("Entries table range is (" DPxMOD ")->(" DPxMOD ")\n",
DPxPTR(entries_begin), DPxPTR(entries_end));
DeviceInfo.createOffloadTable(device_id, entries_begin, entries_end);
elf_end(e);
return DeviceInfo.getOffloadEntriesTable(device_id);
}
void *__tgt_rtl_data_alloc(int32_t device_id, int64_t size, void *hst_ptr) {
void *ptr = malloc(size);
return ptr;
}
int32_t __tgt_rtl_data_submit(int32_t device_id, void *tgt_ptr, void *hst_ptr,
int64_t size) {
memcpy(tgt_ptr, hst_ptr, size);
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_data_retrieve(int32_t device_id, void *hst_ptr, void *tgt_ptr,
int64_t size) {
memcpy(hst_ptr, tgt_ptr, size);
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_data_delete(int32_t device_id, void *tgt_ptr) {
free(tgt_ptr);
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_run_target_team_region(int32_t device_id, void *tgt_entry_ptr,
void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num, int32_t team_num,
int32_t thread_limit, uint64_t loop_tripcount /*not used*/) {
// ignore team num and thread limit.
// Use libffi to launch execution.
ffi_cif cif;
// All args are references.
std::vector<ffi_type *> args_types(arg_num, &ffi_type_pointer);
std::vector<void *> args(arg_num);
std::vector<void *> ptrs(arg_num);
for (int32_t i = 0; i < arg_num; ++i) {
ptrs[i] = (void *)((intptr_t)tgt_args[i] + tgt_offsets[i]);
args[i] = &ptrs[i];
}
ffi_status status = ffi_prep_cif(&cif, FFI_DEFAULT_ABI, arg_num,
&ffi_type_void, &args_types[0]);
assert(status == FFI_OK && "Unable to prepare target launch!");
if (status != FFI_OK)
return OFFLOAD_FAIL;
DP("Running entry point at " DPxMOD "...\n", DPxPTR(tgt_entry_ptr));
void (*entry)(void);
*((void**) &entry) = tgt_entry_ptr;
ffi_call(&cif, entry, NULL, &args[0]);
return OFFLOAD_SUCCESS;
}
int32_t __tgt_rtl_run_target_region(int32_t device_id, void *tgt_entry_ptr,
void **tgt_args, ptrdiff_t *tgt_offsets, int32_t arg_num) {
// use one team and one thread.
return __tgt_rtl_run_target_team_region(device_id, tgt_entry_ptr, tgt_args,
tgt_offsets, arg_num, 1, 1, 0);
}
#ifdef __cplusplus
}
#endif
@@ -0,0 +1,18 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a ppc64 machine if available.
#
##===----------------------------------------------------------------------===##
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64("ppc64" "PPC64" "ppc64" "powerpc64-ibm-linux-gnu" "21")
else()
libomptarget_say("Not building ppc64 offloading plugin: machine not found in the system.")
endif()
@@ -0,0 +1,18 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a ppc64le machine if available.
#
##===----------------------------------------------------------------------===##
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64("ppc64le" "PPC64le" "ppc64" "powerpc64le-ibm-linux-gnu" "21")
else()
libomptarget_say("Not building ppc64le offloading plugin: machine not found in the system.")
endif()
@@ -0,0 +1,18 @@
##===----------------------------------------------------------------------===##
#
# The LLVM Compiler Infrastructure
#
# This file is dual licensed under the MIT and the University of Illinois Open
# Source Licenses. See LICENSE.txt for details.
#
##===----------------------------------------------------------------------===##
#
# Build a plugin for a x86_64 machine if available.
#
##===----------------------------------------------------------------------===##
if(CMAKE_SYSTEM_NAME MATCHES "Linux")
build_generic_elf64("x86_64" "x86_64" "x86_64" "x86_64-pc-linux-gnu" "62")
else()
libomptarget_say("Not building x86_64 offloading plugin: machine not found in the system.")
endif()
File diff suppressed because it is too large Load Diff
+237
View File
@@ -0,0 +1,237 @@
//===-------- omptarget.h - Target independent OpenMP target RTL -- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//
// Interface to be used by Clang during the codegen of a
// target region.
//
//===----------------------------------------------------------------------===//
#ifndef _OMPTARGET_H_
#define _OMPTARGET_H_
#include <stdint.h>
#include <stddef.h>
#define OFFLOAD_SUCCESS (0)
#define OFFLOAD_FAIL (~0)
#define OFFLOAD_DEVICE_DEFAULT -1
#define HOST_DEVICE -10
/// Data attributes for each data reference used in an OpenMP target region.
enum tgt_map_type {
// No flags
OMP_TGT_MAPTYPE_NONE = 0x000,
// copy data from host to device
OMP_TGT_MAPTYPE_TO = 0x001,
// copy data from device to host
OMP_TGT_MAPTYPE_FROM = 0x002,
// copy regardless of the reference count
OMP_TGT_MAPTYPE_ALWAYS = 0x004,
// force unmapping of data
OMP_TGT_MAPTYPE_DELETE = 0x008,
// map the pointer as well as the pointee
OMP_TGT_MAPTYPE_PTR_AND_OBJ = 0x010,
// pass device base address to kernel
OMP_TGT_MAPTYPE_TARGET_PARAM = 0x020,
// return base device address of mapped data
OMP_TGT_MAPTYPE_RETURN_PARAM = 0x040,
// private variable - not mapped
OMP_TGT_MAPTYPE_PRIVATE = 0x080,
// copy by value - not mapped
OMP_TGT_MAPTYPE_LITERAL = 0x100,
// mapping is implicit
OMP_TGT_MAPTYPE_IMPLICIT = 0x200,
// member of struct, member given by 4 MSBs - 1
OMP_TGT_MAPTYPE_MEMBER_OF = 0xffff000000000000
};
enum OpenMPOffloadingDeclareTargetFlags {
/// Mark the entry as having a 'link' attribute.
OMP_DECLARE_TARGET_LINK = 0x01,
/// Mark the entry as being a global constructor.
OMP_DECLARE_TARGET_CTOR = 0x02,
/// Mark the entry as being a global destructor.
OMP_DECLARE_TARGET_DTOR = 0x04
};
/// This struct is a record of an entry point or global. For a function
/// entry point the size is expected to be zero
struct __tgt_offload_entry {
void *addr; // Pointer to the offload entry info (function or global)
char *name; // Name of the function or global
size_t size; // Size of the entry info (0 if it is a function)
int32_t flags; // Flags associated with the entry, e.g. 'link'.
int32_t reserved; // Reserved, to be used by the runtime library.
};
/// This struct is a record of the device image information
struct __tgt_device_image {
void *ImageStart; // Pointer to the target code start
void *ImageEnd; // Pointer to the target code end
__tgt_offload_entry *EntriesBegin; // Begin of table with all target entries
__tgt_offload_entry *EntriesEnd; // End of table (non inclusive)
};
/// This struct is a record of all the host code that may be offloaded to a
/// target.
struct __tgt_bin_desc {
int32_t NumDeviceImages; // Number of device types supported
__tgt_device_image *DeviceImages; // Array of device images (1 per dev. type)
__tgt_offload_entry *HostEntriesBegin; // Begin of table with all host entries
__tgt_offload_entry *HostEntriesEnd; // End of table (non inclusive)
};
/// This struct contains the offload entries identified by the target runtime
struct __tgt_target_table {
__tgt_offload_entry *EntriesBegin; // Begin of the table with all the entries
__tgt_offload_entry
*EntriesEnd; // End of the table with all the entries (non inclusive)
};
#ifdef __cplusplus
extern "C" {
#endif
// Implemented in libomp, they are called from within __tgt_* functions.
int omp_get_default_device(void) __attribute__((weak));
int32_t __kmpc_omp_taskwait(void *loc_ref, int32_t gtid) __attribute__((weak));
int omp_get_num_devices(void);
int omp_get_initial_device(void);
void *omp_target_alloc(size_t size, int device_num);
void omp_target_free(void *device_ptr, int device_num);
int omp_target_is_present(void *ptr, int device_num);
int omp_target_memcpy(void *dst, void *src, size_t length, size_t dst_offset,
size_t src_offset, int dst_device, int src_device);
int omp_target_memcpy_rect(void *dst, void *src, size_t element_size,
int num_dims, const size_t *volume, const size_t *dst_offsets,
const size_t *src_offsets, const size_t *dst_dimensions,
const size_t *src_dimensions, int dst_device, int src_device);
int omp_target_associate_ptr(void *host_ptr, void *device_ptr, size_t size,
size_t device_offset, int device_num);
int omp_target_disassociate_ptr(void *host_ptr, int device_num);
/// adds a target shared library to the target execution image
void __tgt_register_lib(__tgt_bin_desc *desc);
/// removes a target shared library from the target execution image
void __tgt_unregister_lib(__tgt_bin_desc *desc);
// creates the host to target data mapping, stores it in the
// libomptarget.so internal structure (an entry in a stack of data maps) and
// passes the data to the device;
void __tgt_target_data_begin(int32_t device_id, int32_t arg_num,
void **args_base, void **args, int64_t *arg_sizes,
int32_t *arg_types);
void __tgt_target_data_begin_nowait(int32_t device_id, int32_t arg_num,
void **args_base, void **args,
int64_t *arg_sizes, int32_t *arg_types,
int32_t depNum, void *depList,
int32_t noAliasDepNum,
void *noAliasDepList);
// passes data from the target, release target memory and destroys the
// host-target mapping (top entry from the stack of data maps) created by
// the last __tgt_target_data_begin
void __tgt_target_data_end(int32_t device_id, int32_t arg_num, void **args_base,
void **args, int64_t *arg_sizes, int32_t *arg_types);
void __tgt_target_data_end_nowait(int32_t device_id, int32_t arg_num,
void **args_base, void **args,
int64_t *arg_sizes, int32_t *arg_types,
int32_t depNum, void *depList,
int32_t noAliasDepNum, void *noAliasDepList);
/// passes data to/from the target
void __tgt_target_data_update(int32_t device_id, int32_t arg_num,
void **args_base, void **args, int64_t *arg_sizes,
int32_t *arg_types);
void __tgt_target_data_update_nowait(int32_t device_id, int32_t arg_num,
void **args_base, void **args,
int64_t *arg_sizes, int32_t *arg_types,
int32_t depNum, void *depList,
int32_t noAliasDepNum,
void *noAliasDepList);
// Performs the same actions as data_begin in case arg_num is non-zero
// and initiates run of offloaded region on target platform; if arg_num
// is non-zero after the region execution is done it also performs the
// same action as data_end above. The following types are used; this
// function returns 0 if it was able to transfer the execution to a
// target and an int different from zero otherwise.
int __tgt_target(int32_t device_id, void *host_ptr, int32_t arg_num,
void **args_base, void **args, int64_t *arg_sizes,
int32_t *arg_types);
int __tgt_target_nowait(int32_t device_id, void *host_ptr, int32_t arg_num,
void **args_base, void **args, int64_t *arg_sizes,
int32_t *arg_types, int32_t depNum, void *depList,
int32_t noAliasDepNum, void *noAliasDepList);
int __tgt_target_teams(int32_t device_id, void *host_ptr, int32_t arg_num,
void **args_base, void **args, int64_t *arg_sizes,
int32_t *arg_types, int32_t num_teams,
int32_t thread_limit);
int __tgt_target_teams_nowait(int32_t device_id, void *host_ptr,
int32_t arg_num, void **args_base, void **args,
int64_t *arg_sizes, int32_t *arg_types,
int32_t num_teams, int32_t thread_limit,
int32_t depNum, void *depList,
int32_t noAliasDepNum, void *noAliasDepList);
void __kmpc_push_target_tripcount(int32_t device_id, uint64_t loop_tripcount);
#ifdef __cplusplus
}
#endif
#ifdef OMPTARGET_DEBUG
#include <stdio.h>
#define DEBUGP(prefix, ...) \
{ \
fprintf(stderr, "%s --> ", prefix); \
fprintf(stderr, __VA_ARGS__); \
}
#ifndef __STDC_FORMAT_MACROS
#define __STDC_FORMAT_MACROS
#endif
#include <inttypes.h>
#define DPxMOD "0x%0*" PRIxPTR
#define DPxPTR(ptr) ((int)(2*sizeof(uintptr_t))), ((uintptr_t) (ptr))
/*
* To printf a pointer in hex with a fixed width of 16 digits and a leading 0x,
* use printf("ptr=" DPxMOD "...\n", DPxPTR(ptr));
*
* DPxMOD expands to:
* "0x%0*" PRIxPTR
* where PRIxPTR expands to an appropriate modifier for the type uintptr_t on a
* specific platform, e.g. "lu" if uintptr_t is typedef'd as unsigned long:
* "0x%0*lu"
*
* Ultimately, the whole statement expands to:
* printf("ptr=0x%0*lu...\n", // the 0* modifier expects an extra argument
* // specifying the width of the output
* (int)(2*sizeof(uintptr_t)), // the extra argument specifying the width
* // 8 digits for 32bit systems
* // 16 digits for 64bit
* (uintptr_t) ptr);
*/
#else
#define DEBUGP(prefix, ...) \
{}
#endif
#ifdef __cplusplus
#define EXTERN extern "C"
#else
#define EXTERN extern
#endif
#endif // _OMPTARGET_H_
+92
View File
@@ -0,0 +1,92 @@
//===-- omptargetplugin.h - Target dependent OpenMP Plugin API --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//
// This file defines an interface between target independent OpenMP offload
// runtime library libomptarget and target dependent plugin.
//
//===----------------------------------------------------------------------===//
#ifndef _OMPTARGETPLUGIN_H_
#define _OMPTARGETPLUGIN_H_
#include <omptarget.h>
#ifdef __cplusplus
extern "C" {
#endif
// Return the number of available devices of the type supported by the
// target RTL.
int32_t __tgt_rtl_number_of_devices(void);
// Return an integer different from zero if the provided device image can be
// supported by the runtime. The functionality is similar to comparing the
// result of __tgt__rtl__load__binary to NULL. However, this is meant to be a
// lightweight query to determine if the RTL is suitable for an image without
// having to load the library, which can be expensive.
int32_t __tgt_rtl_is_valid_binary(__tgt_device_image *Image);
// Initialize the specified device. In case of success return 0; otherwise
// return an error code.
int32_t __tgt_rtl_init_device(int32_t ID);
// Pass an executable image section described by image to the specified
// device and prepare an address table of target entities. In case of error,
// return NULL. Otherwise, return a pointer to the built address table.
// Individual entries in the table may also be NULL, when the corresponding
// offload region is not supported on the target device.
__tgt_target_table *__tgt_rtl_load_binary(int32_t ID,
__tgt_device_image *Image);
// Allocate data on the particular target device, of the specified size.
// HostPtr is a address of the host data the allocated target data
// will be associated with (HostPtr may be NULL if it is not known at
// allocation time, like for example it would be for target data that
// is allocated by omp_target_alloc() API). Return address of the
// allocated data on the target that will be used by libomptarget.so to
// initialize the target data mapping structures. These addresses are
// used to generate a table of target variables to pass to
// __tgt_rtl_run_region(). The __tgt_rtl_data_alloc() returns NULL in
// case an error occurred on the target device.
void *__tgt_rtl_data_alloc(int32_t ID, int64_t Size, void *HostPtr);
// Pass the data content to the target device using the target address.
// In case of success, return zero. Otherwise, return an error code.
int32_t __tgt_rtl_data_submit(int32_t ID, void *TargetPtr, void *HostPtr,
int64_t Size);
// Retrieve the data content from the target device using its address.
// In case of success, return zero. Otherwise, return an error code.
int32_t __tgt_rtl_data_retrieve(int32_t ID, void *HostPtr, void *TargetPtr,
int64_t Size);
// De-allocate the data referenced by target ptr on the device. In case of
// success, return zero. Otherwise, return an error code.
int32_t __tgt_rtl_data_delete(int32_t ID, void *TargetPtr);
// Transfer control to the offloaded entry Entry on the target device.
// Args and Offsets are arrays of NumArgs size of target addresses and
// offsets. An offset should be added to the target address before passing it
// to the outlined function on device side. In case of success, return zero.
// Otherwise, return an error code.
int32_t __tgt_rtl_run_target_region(int32_t ID, void *Entry, void **Args,
ptrdiff_t *Offsets, int32_t NumArgs);
// Similar to __tgt_rtl_run_target_region, but additionally specify the
// number of teams to be created and a number of threads in each team.
int32_t __tgt_rtl_run_target_team_region(int32_t ID, void *Entry, void **Args,
ptrdiff_t *Offsets, int32_t NumArgs,
int32_t NumTeams, int32_t ThreadLimit,
uint64_t loop_tripcount);
#ifdef __cplusplus
}
#endif
#endif // _OMPTARGETPLUGIN_H_
+92
View File
@@ -0,0 +1,92 @@
# CMakeLists.txt file for unit testing OpenMP Library
include(FindPythonInterp)
include(CheckTypeSize)
if(NOT PYTHONINTERP_FOUND)
libomptarget_warning_say("Could not find Python.")
libomptarget_warning_say("The check-libomptarget target will not be available!")
return()
endif()
set(LIBOMPTARGET_TEST_CFLAGS "" CACHE STRING
"Extra compiler flags to send to the test compiler")
if(${LIBOMPTARGET_STANDALONE_BUILD})
# Make sure we can use the console pool for recent cmake and ninja > 1.5
if(CMAKE_VERSION VERSION_LESS 3.1.20141117)
set(cmake_3_2_USES_TERMINAL)
else()
set(cmake_3_2_USES_TERMINAL USES_TERMINAL)
endif()
set(LIBOMPTARGET_TEST_C_COMPILER ${CMAKE_C_COMPILER} CACHE STRING
"C compiler to use for testing OpenMP offloading library")
set(LIBOMPTARGET_TEST_CXX_COMPILER ${CMAKE_CXX_COMPILER} CACHE STRING
"C++ compiler to use for testing OpenMP offloading library")
set(LIBOMPTARGET_TEST_OPENMP_FLAG -fopenmp CACHE STRING
"OpenMP compiler flag to use for testing OpenMP offloading library")
find_program(LIBOMPTARGET_LLVM_LIT_EXECUTABLE
NAMES llvm-lit lit.py lit
PATHS ${OPENMP_LLVM_TOOLS_DIR})
if(NOT LIBOMPTARGET_LLVM_LIT_EXECUTABLE)
libomptarget_say("Cannot find llvm-lit.")
libomptarget_say("Please put llvm-lit in your PATH or set LIBOMPTARGET_LLVM_LIT_EXECUTABLE to its full path or point OPENMP_LLVM_TOOLS_DIR to its directory")
libomptarget_warning_say("The check-libomptarget target will not be available!")
return()
endif()
find_program(LIBOMPTARGET_FILECHECK_EXECUTABLE
NAMES FileCheck
PATHS ${OPENMP_LLVM_TOOLS_DIR})
if(NOT LIBOMPTARGET_FILECHECK_EXECUTABLE)
libomptarget_say("Cannot find FileCheck.")
libomptarget_say("Please put FileCheck in your PATH or set LIBOMPTARGET_FILECHECK_EXECUTABLE to its full path or point OPENMP_LLVM_TOOLS_DIR to its directory")
libomptarget_warning_say("The check-libomptarget target will not be available!")
return()
endif()
# Set lit arguments
# The -j 1 lets the actual tests run with the entire machine.
# We have one test thread that spawns the tests serially. This allows
# Each test to use the entire machine.
set(LIBOMPTARGET_LIT_ARGS_DEFAULT "-sv --show-unsupported --show-xfail -j 1")
if(MSVC OR XCODE)
set(LIBOMPTARGET_LIT_ARGS_DEFAULT "${LIBOMPTARGET_LIT_ARGS_DEFAULT} --no-progress-bar")
endif()
set(LIBOMPTARGET_LIT_ARGS "${LIBOMPTARGET_LIT_ARGS_DEFAULT}" CACHE STRING
"Default options for lit")
separate_arguments(LIBOMPTARGET_LIT_ARGS)
add_custom_target(check-libomptarget
COMMAND ${PYTHON_EXECUTABLE} ${LIBOMPTARGET_LLVM_LIT_EXECUTABLE} ${LIBOMPTARGET_LIT_ARGS} ${CMAKE_CURRENT_BINARY_DIR}
DEPENDS omptarget
COMMENT "Running libomptarget tests"
${cmake_3_2_USES_TERMINAL}
)
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../../runtime/src" CACHE STRING
"Path to folder containing omp.h")
set(LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER "${CMAKE_CURRENT_BINARY_DIR}/../../runtime/src" CACHE STRING
"Path to folder containing libomp.so")
else()
# LLVM source tree build, test just-built clang
if(NOT MSVC)
set(LIBOMPTARGET_TEST_C_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang)
set(LIBOMPTARGET_TEST_CXX_COMPILER ${LLVM_RUNTIME_OUTPUT_INTDIR}/clang++)
set(LIBOMPTARGET_FILECHECK_EXECUTABLE ${LLVM_RUNTIME_OUTPUT_INTDIR}/FileCheck)
else()
libomptarget_warning_say("Not prepared to run tests on Windows systems.")
endif()
set(LIBOMPTARGET_TEST_OPENMP_FLAG -fopenmp=libomp)
# Use add_lit_testsuite() from LLVM CMake. This also depends on OpenMP
# implementation because it uses omp.h.
add_lit_testsuite(check-libomptarget
"Running libomptarget tests"
${CMAKE_CURRENT_BINARY_DIR}
DEPENDS omptarget omp
)
set(LIBOMPTARGET_OPENMP_HEADER_FOLDER "${LIBOMPTARGET_BINARY_DIR}/../runtime/src")
endif()
# Configure the lit.site.cfg.in file
set(AUTO_GEN_COMMENT "## Autogenerated by libomptarget configuration.\n# Do not edit!")
configure_file(lit.site.cfg.in lit.site.cfg @ONLY)
+116
View File
@@ -0,0 +1,116 @@
# -*- Python -*- vim: set ft=python ts=4 sw=4 expandtab tw=79:
# Configuration file for the 'lit' test runner.
import os
import lit.formats
# Tell pylint that we know config and lit_config exist somewhere.
if 'PYLINT_IMPORT' in os.environ:
config = object()
lit_config = object()
def append_dynamic_library_path(name, value, sep):
if name in config.environment:
config.environment[name] = value + sep + config.environment[name]
else:
config.environment[name] = value
# name: The name of this test suite.
config.name = 'libomptarget'
# suffixes: A list of file extensions to treat as test files.
config.suffixes = ['.c', '.cpp', '.cc']
# test_source_root: The root path where tests are located.
config.test_source_root = os.path.dirname(__file__)
# test_exec_root: The root object directory where output is placed
config.test_exec_root = config.libomptarget_obj_root
# test format
config.test_format = lit.formats.ShTest()
# compiler flags
config.test_cflags = config.test_openmp_flag + \
" -I " + config.test_source_root + \
" -I " + config.omp_header_directory + \
" -L " + config.library_dir;
if config.omp_host_rtl_directory:
config.test_cflags = config.test_cflags + " -L " + \
config.omp_host_rtl_directory
config.test_cflags = config.test_cflags + " " + config.test_extra_cflags
# Setup environment to find dynamic library at runtime
if config.operating_system == 'Windows':
append_dynamic_library_path('PATH', config.library_dir, ";")
append_dynamic_library_path('PATH', config.omp_host_rtl_directory, ";")
elif config.operating_system == 'Darwin':
append_dynamic_library_path('DYLD_LIBRARY_PATH', config.library_dir, ":")
append_dynamic_library_path('DYLD_LIBRARY_PATH', \
config.omp_host_rtl_directory, ";")
config.test_cflags += " -Wl,-rpath," + config.library_dir
config.test_cflags += " -Wl,-rpath," + config.omp_host_rtl_directory
else: # Unices
append_dynamic_library_path('LD_LIBRARY_PATH', config.library_dir, ":")
append_dynamic_library_path('LD_LIBRARY_PATH', \
config.omp_host_rtl_directory, ":")
# substitutions
# - for targets that exist in the system create the actual command.
# - for valid targets that do not exist in the system, return false, so that the
# same test can be used for different targets.
# Scan all the valid targets.
for libomptarget_target in config.libomptarget_all_targets:
# Is this target in the current system? If so create a compile, run and test
# command. Otherwise create command that return false.
if libomptarget_target in config.libomptarget_system_targets:
config.substitutions.append(("%libomptarget-compilexx-run-and-check-" + \
libomptarget_target, \
"%libomptarget-compilexx-and-run-" + libomptarget_target + \
" | " + config.libomptarget_filecheck + " %s"))
config.substitutions.append(("%libomptarget-compile-run-and-check-" + \
libomptarget_target, \
"%libomptarget-compile-and-run-" + libomptarget_target + \
" | " + config.libomptarget_filecheck + " %s"))
config.substitutions.append(("%libomptarget-compilexx-and-run-" + \
libomptarget_target, \
"%clangxx-" + libomptarget_target + " %s -o %t-" + \
libomptarget_target + " && %t-" + libomptarget_target))
config.substitutions.append(("%libomptarget-compile-and-run-" + \
libomptarget_target, \
"%clang-" + libomptarget_target + " %s -o %t-" + \
libomptarget_target + " && %t-" + libomptarget_target))
config.substitutions.append(("%clangxx-" + libomptarget_target, \
"%clangxx %cflags -fopenmp-targets=" + libomptarget_target))
config.substitutions.append(("%clang-" + libomptarget_target, \
"%clang %cflags -fopenmp-targets=" + libomptarget_target))
config.substitutions.append(("%fcheck-" + libomptarget_target, \
config.libomptarget_filecheck + " %s"))
else:
config.substitutions.append(("%libomptarget-compile-run-and-check-" + \
libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%libomptarget-compilexx-run-and-check-" + \
libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%libomptarget-compile-and-run-" + \
libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%libomptarget-compilexx-and-run-" + \
libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%clang-" + libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%clangxx-" + libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%fcheck-" + libomptarget_target, \
"echo ignored-command"))
config.substitutions.append(("%clangxx", config.test_cxx_compiler))
config.substitutions.append(("%clang", config.test_c_compiler))
config.substitutions.append(("%openmp_flag", config.test_openmp_flag))
config.substitutions.append(("%cflags", config.test_cflags))
+20
View File
@@ -0,0 +1,20 @@
@AUTO_GEN_COMMENT@
config.test_c_compiler = "@LIBOMPTARGET_TEST_C_COMPILER@"
config.test_cxx_compiler = "@LIBOMPTARGET_TEST_CXX_COMPILER@"
config.test_openmp_flag = "@LIBOMPTARGET_TEST_OPENMP_FLAG@"
# For the moment we still need to pass libomptarget explicitly. Once the driver
# patch, lands, this is not required anymore.
config.test_extra_cflags = "-lomptarget @LIBOMPTARGET_TEST_CFLAGS@"
config.libomptarget_obj_root = "@CMAKE_CURRENT_BINARY_DIR@"
config.library_dir = "@LIBOMPTARGET_LIBRARY_DIR@"
config.omp_header_directory = "@LIBOMPTARGET_OPENMP_HEADER_FOLDER@"
config.omp_host_rtl_directory = "@LIBOMPTARGET_OPENMP_HOST_RTL_FOLDER@"
config.operating_system = "@CMAKE_SYSTEM_NAME@"
config.libomptarget_all_targets = "@LIBOMPTARGET_ALL_TARGETS@".split()
config.libomptarget_system_targets = "@LIBOMPTARGET_SYSTEM_TARGETS@".split()
config.libomptarget_filecheck = "@LIBOMPTARGET_FILECHECK_EXECUTABLE@"
# Let the main config do the real work.
lit_config.load_config(config, "@LIBOMPTARGET_BASE_DIR@/test/lit.cfg")
@@ -0,0 +1,23 @@
// RUN: %libomptarget-compile-run-and-check-aarch64-unknown-linux-gnu
// RUN: %libomptarget-compile-run-and-check-powerpc64-ibm-linux-gnu
// RUN: %libomptarget-compile-run-and-check-powerpc64le-ibm-linux-gnu
// RUN: %libomptarget-compile-run-and-check-x86_64-pc-linux-gnu
#include <stdio.h>
#include <omp.h>
int main(void) {
int isHost = -1;
#pragma omp target map(from: isHost)
{ isHost = omp_is_initial_device(); }
if (isHost < 0) {
printf("Runtime error, isHost=%d\n", isHost);
}
// CHECK: Target region executed on the device
printf("Target region executed on the %s\n", isHost ? "host" : "device");
return isHost;
}
@@ -0,0 +1,23 @@
// RUN: %libomptarget-compilexx-run-and-check-aarch64-unknown-linux-gnu
// RUN: %libomptarget-compilexx-run-and-check-powerpc64-ibm-linux-gnu
// RUN: %libomptarget-compilexx-run-and-check-powerpc64le-ibm-linux-gnu
// RUN: %libomptarget-compilexx-run-and-check-x86_64-pc-linux-gnu
#include <stdio.h>
#include <omp.h>
int main(void) {
int isHost = 0;
#pragma omp target map(from: isHost)
{ isHost = omp_is_initial_device(); }
if (isHost < 0) {
printf("Runtime error, isHost=%d\n", isHost);
}
// CHECK: Target region executed on the device
printf("Target region executed on the %s\n", isHost ? "host" : "device");
return isHost;
}
+224
View File
@@ -0,0 +1,224 @@
#
##//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# MAKEFILE PARAMETERS
#
# root_dir - path to root directory of liboffload
# build_dir - path to build directory
# mpss_dir - path to root directory of mpss
# mpss_version - version of the mpss (e.g., version "3.3.x" would be "33")
# libiomp_host_dir - path to host libiomp directory (unnecessary if compiler_host is icc)
# libiomp_target_dir - path to target libiomp directory (unnecesarry if compiler_target is icc)
# omp_header_dir - path to omp.h (unnecessary if compiler_host and compiler_target are icc)
# os_host - host operating system
# os_target - target operating system
# compiler_host - host compiler
# compiler_target - target compiler
# options_host - additional options for host compiler
# options_target - additional options for target compiler
#
# Directories
root_dir?=.
build_dir?=$(root_dir)/build
build_host_dir=$(build_dir)/host
build_target_dir=$(build_dir)/target
obj_host_dir=$(build_dir)/obj_host
obj_target_dir=$(build_dir)/obj_target
source_dir=$(root_dir)/src
imported_dir=$(source_dir)/imported
# OS
os_host?=linux
os_target?=linux
ifneq ($(os_host)_$(os_target), linux_linux)
$(error "Only linux is supported")
endif
# Compilers
compiler_host?=gcc
compiler_target?=gcc
# MPSS
mpss_version?=30
mpss_dir?=/
mpss_present=$(shell if test -d $(mpss_dir); then echo OK; else echo KO; fi)
ifneq ($(mpss_present), OK)
$(error "Cannot find MPSS directory $(mpss_dir)")
endif
ifeq ($(shell test $(mpss_version) -gt 33; echo $$?), 0)
coi_dir=$(mpss_dir)/sysroots/k1om-mpss-linux/usr
coi_include=$(coi_dir)/include/intel-coi
coi_lib_host=$(mpss_dir)/lib64
coi_lib_device=$(coi_dir)/lib64
else
coi_dir=$(mpss_dir)/opt/intel/mic/coi
coi_include=$(coi_dir)/include
coi_lib_host=$(coi_dir)/host-linux-release/lib
coi_lib_device=$(coi_dir)/device-linux-release/lib
endif
myo_dir=$(mpss_dir)/opt/intel/mic/myo
# Sources
src_liboffload_common=dv_util.cpp liboffload_error.c liboffload_msg.c offload_common.cpp offload_table.cpp offload_trace.cpp offload_util.cpp
src_liboffload_host=$(src_liboffload_common) cean_util.cpp coi/coi_client.cpp compiler_if_host.cpp offload_engine.cpp offload_env.cpp offload_host.cpp offload_omp_host.cpp offload_timer_host.cpp offload_orsl.cpp orsl-lite/lib/orsl-lite.c offload_myo_host.cpp
src_liboffload_host:=$(foreach file,$(src_liboffload_host),$(source_dir)/$(file))
src_liboffload_target=$(src_liboffload_common) coi/coi_server.cpp compiler_if_target.cpp offload_omp_target.cpp offload_target.cpp offload_timer_target.cpp offload_myo_target.cpp
src_liboffload_target:=$(foreach file,$(src_liboffload_target),$(source_dir)/$(file))
src_ofld=ofldbegin.cpp ofldend.cpp
src_ofld:=$(foreach file,$(src_ofld),$(source_dir)/$(file))
headers=$(wildcard $(source_dir)/*.h) $(wildcard $(source_dir)/coi/*.h) $(wildcard $(source_dir)/orsl-lite/include/*.h)
ifneq ($(omp_header_dir), )
headers+=$(imported_dir)/omp.h
endif
# Objects
obj_liboffload_host=$(notdir $(src_liboffload_host))
obj_liboffload_host:=$(obj_liboffload_host:.cpp=.o)
obj_liboffload_host:=$(obj_liboffload_host:.c=.o)
obj_liboffload_host:=$(foreach file,$(obj_liboffload_host),$(obj_host_dir)/$(file))
obj_liboffload_target=$(notdir $(src_liboffload_target))
obj_liboffload_target:=$(obj_liboffload_target:.cpp=.o)
obj_liboffload_target:=$(obj_liboffload_target:.c=.o)
obj_liboffload_target:=$(foreach file,$(obj_liboffload_target),$(obj_target_dir)/$(file))
obj_ofld=$(notdir $(src_ofld))
obj_ofld:=$(obj_ofld:.cpp=.o)
obj_ofld_host=$(foreach file,$(obj_ofld),$(build_host_dir)/$(file))
obj_ofld_target=$(foreach file,$(obj_ofld),$(build_target_dir)/$(file))
# Options
opts_common=-O2 -w -fpic -c -DCOI_LIBRARY_VERSION=2 -DMYO_SUPPORT -DOFFLOAD_DEBUG=1 -DSEP_SUPPORT -DTIMING_SUPPORT -I$(coi_include) -I$(myo_dir)/include -I$(source_dir)
ifneq ($(omp_header_dir), )
opts_common+=-I$(imported_dir)
endif
opts_liboffload=-shared -Wl,-soname,liboffload.so.5 -ldl -lstdc++ -liomp5
opts_liboffload_host=$(opts_liboffload) -L$(coi_lib_host) -lcoi_host -L$(myo_dir)/lib -lmyo-client
ifneq ($(libiomp_host_dir), )
opts_liboffload_host+=-L$(libiomp_host_dir)
endif
opts_liboffload_target=$(opts_liboffload) -L$(coi_lib_device) -lcoi_device -L$(myo_dir)/lib -lmyo-service
ifneq ($(libiomp_target_dir), )
opts_liboffload_target+=-L$(libiomp_target_dir)
endif
options_host?=
opts_host=$(options_host) -DHOST_LIBRARY=1 -DMPSS_VERSION=$(mpss_version)
ifeq ($(os_host), linux)
opts_host+=-DLINUX
endif
options_target?=
opts_target=$(options_target) -DHOST_LIBRARY=0
ifeq ($(os_target), linux)
opts_target+=-DLINUX
endif
ifeq ($(compiler_target), icc)
opts_target+=-mmic
endif
# Make targets
.PHONY: all clean info
all: info $(build_host_dir)/liboffload.so $(build_target_dir)/liboffload.so $(obj_ofld_host) $(obj_ofld_target)
$(build_host_dir)/liboffload.so: $(build_host_dir)/liboffload.so.5 | $(build_host_dir)
ln -f $< $@
$(build_host_dir)/liboffload.so.5: $(obj_liboffload_host) | $(build_host_dir)
$(compiler_host) $(opts_liboffload_host) $(opts_host) $^ -o $@
$(obj_host_dir)/%.o: $(source_dir)/%.c $(headers) | $(obj_host_dir)
$(compiler_host) $(opts_common) $(opts_host) $< -o $@
$(obj_host_dir)/%.o: $(source_dir)/%.cpp $(headers) | $(obj_host_dir)
$(compiler_host) $(opts_common) $(opts_host) $< -o $@
$(obj_host_dir)/%.o: $(source_dir)/coi/%.cpp $(headers) | $(obj_host_dir)
$(compiler_host) $(opts_common) $(opts_host) $< -o $@
$(obj_host_dir)/%.o: $(source_dir)/orsl-lite/lib/%.c $(headers) | $(obj_host_dir)
$(compiler_host) $(opts_common) $(opts_host) $< -o $@
$(build_target_dir)/liboffload.so: $(build_target_dir)/liboffload.so.5 | $(build_target_dir)
ln -f $< $@
$(build_target_dir)/liboffload.so.5: $(obj_liboffload_target) | $(build_target_dir)
$(compiler_target) $(opts_liboffload_target) $(opts_target) $^ -o $@
$(obj_target_dir)/%.o: $(source_dir)/%.c $(headers) | $(obj_target_dir)
$(compiler_target) $(opts_common) $(opts_target) $< -o $@
$(obj_target_dir)/%.o: $(source_dir)/%.cpp $(headers) | $(obj_target_dir)
$(compiler_target) $(opts_common) $(opts_target) $< -o $@
$(obj_target_dir)/%.o: $(source_dir)/coi/%.cpp $(headers) | $(obj_target_dir)
$(compiler_target) $(opts_common) $(opts_target) $< -o $@
$(obj_target_dir)/%.o: $(source_dir)/orsl-lite/lib/%.c $(headers) | $(obj_target_dir)
$(compiler_target) $(opts_common) $(opts_target) $< -o $@
$(build_host_dir)/%.o: $(source_dir)/%.cpp $(headers) | $(build_host_dir)
$(compiler_host) $(opts_common) $(opts_host) $< -o $@
$(build_target_dir)/%.o: $(source_dir)/%.cpp $(headers) | $(build_target_dir)
$(compiler_target) $(opts_common) $(opts_target) $< -o $@
$(imported_dir)/omp.h: $(omp_header_dir)/omp.h | $(imported_dir)
cp $< $@
$(build_host_dir) $(build_target_dir) $(obj_host_dir) $(obj_target_dir): | $(build_dir)
$(shell mkdir -p $@ >/dev/null 2>/dev/null)
@echo "Created $@ directory"
$(build_dir):
$(shell mkdir -p $@ >/dev/null 2>/dev/null)
@echo "Created $@ directory"
$(imported_dir):
$(shell mkdir -p $@ >/dev/null 2>/dev/null)
@echo "Created $@ directory"
clean:
$(shell rm -rf $(build_dir))
@echo "Remove $(build_dir) directory"
info:
@echo "root_dir = $(root_dir)"
@echo "build_dir = $(build_dir)"
@echo "mpss_dir = $(mpss_dir)"
@echo "mpss_version = $(mpss_version)"
@echo "libiomp_host_dir = $(libiomp_host_dir)"
@echo "libiomp_target_dir = $(libiomp_target_dir)"
@echo "omp_header_dir = $(omp_header_dir)"
@echo "os_host = $(os_host)"
@echo "os_target = $(os_target)"
@echo "compiler_host = $(compiler_host)"
@echo "compiler_target = $(compiler_target)"
@echo "options_host = $(options_host)"
@echo "options_target = $(options_target)"
+129
View File
@@ -0,0 +1,129 @@
README for Intel(R) Offload Runtime Library
===========================================
How to Build Documentation
==========================
The main documentation is in Doxygen* format, and this distribution
should come with pre-built PDF documentation in doc/Reference.pdf.
However, an HTML version can be built by executing:
% doxygen doc/doxygen/config
in this directory.
That will produce HTML documentation in the doc/doxygen/generated
directory, which can be accessed by pointing a web browser at the
index.html file there.
If you don't have Doxygen installed, you can download it from
www.doxygen.org.
Software Requirements
=====================
Intel(R) Offload Runtime Library requires additional software:
1) Intel(R) OpenMP* Runtime Library. You can either download the source
code for that (from openmprtl.org or openmp.llvm.org) or simply use the
compiled version distributed with the Intel compilers.
2) Intel(R) COI Runtime Library and Intel(R) MYO Runtime Library. These
libraries are part of Intel(R) Manycore Platform Software Stack (MPSS). You
can download MPSS source code or binaries from
software.intel.com/en-us/articles/intel-manycore-platform-software-stack-mpss.
Binaries include host libraries for Intel(R) 64 Architecture and target
libraries for Intel(R) Many Integrated Core Architecture.
Also you will require all of the libraries that enable the target code to run
on device. If you target the Intel(R) Xeon Phi (TM) coprocessor, these
libraries can be taken from MPSS too.
How to Build the Intel(R) Offload Runtime Library
=================================================
The Makefile at the top-level will attempt to detect what it needs to
build the Intel(R) Offload Runtime Library. To see the default settings,
type:
make info
You can change the Makefile's behavior with the following options:
root_dir: The path to the top-level directory containing the
top-level Makefile. By default, this will take on the
value of the current working directory.
build_dir: The path to the build directory. By default, this will
take on value [root_dir]/build.
mpss_dir: The path to the Intel(R) Manycore Platform Software
Stack install directory. By default, this will take on
the value of operating system's root directory.
libiomp_host_dir: The path to the host Intel(R) OpenMP* Runtime Library.
This option is required when the host compiler is other
than icc.
libiomp_target_dir: The path to the target Intel(R) OpenMP* Runtime
Library. This option is required when the target
compiler is other than icc.
omp_header_dir: The path to the header file <omp.h> of Intel(R) OpenMP*
Runtime Library. This option is required if either host
or target compiler is other than icc.
os_host: Operating system on host. Currently supports only
"linux" which is set by default.
os_target: Operating system on target device. Currently supports
only "linux" which is set by default.
compiler_host: Which compiler to use for the build of the host part.
Defaults to "gcc"*. Also supports "icc" and "clang"*.
You should provide the full path to the compiler or it
should be in the user's path.
compiler_host: Which compiler to use for the build of the target part.
Defaults to "gcc"*. Also supports "icc" and "clang"*.
You should provide the full path to the compiler or it
should be in the user's path.
options_host: Additional options for the host compiler.
options_target: Additional options for the target compiler.
To use any of the options above, simple add <option_name>=<value>. For
example, if you want to build with icc instead of gcc, type:
make compiler_host=icc compiler_target=icc
Supported RTL Build Configurations
==================================
Supported Architectures: Intel(R) 64, and Intel(R) Many Integrated
Core Architecture
---------------------------------------------
| icc/icl | gcc | clang |
--------------|---------------|---------------------------|
| Linux* OS | Yes | Yes(1) | Yes(1) |
| OS X* | No | No | No |
| Windows* OS | No | No | No |
-----------------------------------------------------------
(1) Liboffload requires _rdtsc intrinsic, which may be unsupported by some
versions of compiler. In this case you need to include src/rdtsc.h
manually by using Makefile options options_host and options_target:
make options_host="-include src/rdtsc.h" options_target="-include src/rdtsc.h"
-----------------------------------------------------------------------
Notices
=======
*Other names and brands may be claimed as the property of others.
File diff suppressed because it is too large Load Diff
+2328
View File
File diff suppressed because it is too large Load Diff
+90
View File
@@ -0,0 +1,90 @@
% Latex header for doxygen 1.8.3.1
\documentclass{book}
\usepackage[a4paper,top=2.5cm,bottom=2.5cm,left=2.5cm,right=2.5cm]{geometry}
\usepackage{makeidx}
\usepackage{natbib}
\usepackage{graphicx}
\usepackage{multicol}
\usepackage{float}
\usepackage{listings}
\usepackage{color}
\usepackage{ifthen}
\usepackage[table]{xcolor}
\usepackage{textcomp}
\usepackage{alltt}
\usepackage{ifpdf}
\ifpdf
\usepackage[pdftex,
pagebackref=true,
colorlinks=true,
linkcolor=blue,
unicode
]{hyperref}
\else
\usepackage[ps2pdf,
pagebackref=true,
colorlinks=true,
linkcolor=blue,
unicode
]{hyperref}
\usepackage{pspicture}
\fi
\usepackage[utf8]{inputenc}
\usepackage{mathptmx}
\usepackage[scaled=.90]{helvet}
\usepackage{courier}
\usepackage{sectsty}
\usepackage{amssymb}
\usepackage[titles]{tocloft}
\usepackage{doxygen}
\usepackage{fancyhdr}
\pagestyle{fancy}
\lstset{language=C++,inputencoding=utf8,basicstyle=\footnotesize,breaklines=true,breakatwhitespace=true,tabsize=4,numbers=left }
\makeindex
\setcounter{tocdepth}{3}
\renewcommand{\footrulewidth}{0.4pt}
\renewcommand{\familydefault}{\sfdefault}
\hfuzz=15pt
\setlength{\emergencystretch}{15pt}
\hbadness=750
\tolerance=750
\begin{document}
\hypersetup{pageanchor=false,citecolor=blue}
\begin{titlepage}
\vspace*{7cm}
\begin{center}
{\Large Intel\textsuperscript{\textregistered} Offload Runtime Library }\\
\vspace*{1cm}
{\large Generated by Doxygen $doxygenversion }\\
\vspace*{0.5cm}
{\small $datetime }\\
\end{center}
\end{titlepage}
{\bf FTC Optimization Notice}
Intel's compilers may or may not optimize to the same degree for non-Intel microprocessors for
optimizations that are not unique to Intel microprocessors. These optimizations include SSE2,
SSE3, and SSSE3 instruction sets and other optimizations. Intel does not guarantee the
availability, functionality, or effectiveness of any optimization on microprocessors not
manufactured by Intel.
Microprocessor-dependent optimizations in this product are intended for use with Intel
microprocessors. Certain optimizations not specific to Intel microarchitecture are reserved for
Intel microprocessors. Please refer to the applicable product User and Reference Guides for
more information regarding the specific instruction sets covered by this notice.
Notice revision \#20110804
\vspace*{0.5cm}
{\bf Trademarks}
Intel, Xeon, and Intel Xeon Phi are trademarks of Intel Corporation in the U.S. and/or other countries.
This document is Copyright \textcopyright 2014, Intel Corporation. All rights reserved.
\pagenumbering{roman}
\tableofcontents
\pagenumbering{arabic}
\hypersetup{pageanchor=true,citecolor=blue}
+344
View File
@@ -0,0 +1,344 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "cean_util.h"
#include "offload_common.h"
// 1. allocate element of CeanReadRanges type
// 2. initialized it for reading consequently contiguous ranges
// described by "ap" argument
CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap)
{
CeanReadRanges * res;
// find the max contiguous range
int64_t rank = ap->rank - 1;
int64_t length = ap->dim[rank].size;
for (; rank >= 0; rank--) {
if (ap->dim[rank].stride == 1) {
length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
if (rank > 0 && length != ap->dim[rank - 1].size) {
break;
}
}
else {
break;
}
}
res =(CeanReadRanges *)malloc(sizeof(CeanReadRanges) +
(ap->rank - rank) * sizeof(CeanReadDim));
res->current_number = 0;
res->range_size = length;
res->last_noncont_ind = rank;
// calculate number of contiguous ranges inside noncontiguous dimensions
int count = 1;
bool prev_is_cont = true;
int64_t offset = 0;
for (; rank >= 0; rank--) {
res->Dim[rank].count = count;
res->Dim[rank].size = ap->dim[rank].stride * ap->dim[rank].size;
count *= (prev_is_cont && ap->dim[rank].stride == 1? 1 :
(ap->dim[rank].upper - ap->dim[rank].lower +
ap->dim[rank].stride) / ap->dim[rank].stride);
prev_is_cont = false;
offset +=(ap->dim[rank].lower - ap->dim[rank].lindex) *
ap->dim[rank].size;
}
res->range_max_number = count;
res -> ptr = (void*)ap->base;
res -> init_offset = offset;
return res;
}
// check if ranges described by 1 argument could be transferred into ranges
// described by 2-nd one
bool cean_ranges_match(
CeanReadRanges * read_rng1,
CeanReadRanges * read_rng2
)
{
return ( read_rng1 == NULL || read_rng2 == NULL ||
(read_rng1->range_size % read_rng2->range_size == 0 ||
read_rng2->range_size % read_rng1->range_size == 0));
}
// Set next offset and length and returns true for next range.
// Returns false if the ranges are over.
bool get_next_range(
CeanReadRanges * read_rng,
int64_t *offset
)
{
if (++read_rng->current_number > read_rng->range_max_number) {
read_rng->current_number = 0;
return false;
}
int rank = 0;
int num = read_rng->current_number - 1;
int64_t cur_offset = 0;
int num_loc;
for (; rank <= read_rng->last_noncont_ind; rank++) {
num_loc = num / read_rng->Dim[rank].count;
cur_offset += num_loc * read_rng->Dim[rank].size;
num = num % read_rng->Dim[rank].count;
}
*offset = cur_offset + read_rng->init_offset;
return true;
}
bool is_arr_desc_contiguous(const arr_desc *ap)
{
int64_t rank = ap->rank - 1;
int64_t length = ap->dim[rank].size;
for (; rank >= 0; rank--) {
if (ap->dim[rank].stride > 1 &&
ap->dim[rank].upper - ap->dim[rank].lower != 0) {
return false;
}
else if (length != ap->dim[rank].size) {
for (; rank >= 0; rank--) {
if (ap->dim[rank].upper - ap->dim[rank].lower != 0) {
return false;
}
}
return true;
}
length *= (ap->dim[rank].upper - ap->dim[rank].lower + 1);
}
return true;
}
int64_t cean_get_transf_size(CeanReadRanges * read_rng)
{
return(read_rng->range_max_number * read_rng->range_size);
}
static uint64_t last_left, last_right;
typedef void (*fpp)(const char *spaces, uint64_t low, uint64_t high, int esize);
static void generate_one_range(
const char *spaces,
uint64_t lrange,
uint64_t rrange,
fpp fp,
int esize
)
{
OFFLOAD_TRACE(3,
"%s generate_one_range(lrange=%p, rrange=%p, esize=%d)\n",
spaces, (void*)lrange, (void*)rrange, esize);
if (last_left == -1) {
// First range
last_left = lrange;
}
else {
if (lrange == last_right+1) {
// Extend previous range, don't print
}
else {
(*fp)(spaces, last_left, last_right, esize);
last_left = lrange;
}
}
last_right = rrange;
}
static void generate_mem_ranges_one_rank(
const char *spaces,
uint64_t base,
uint64_t rank,
const struct dim_desc *ddp,
fpp fp,
int esize
)
{
uint64_t lindex = ddp->lindex;
uint64_t lower = ddp->lower;
uint64_t upper = ddp->upper;
uint64_t stride = ddp->stride;
uint64_t size = ddp->size;
OFFLOAD_TRACE(3,
"%s "
"generate_mem_ranges_one_rank(base=%p, rank=%lld, lindex=%lld, "
"lower=%lld, upper=%lld, stride=%lld, size=%lld, esize=%d)\n",
spaces, (void*)base, rank, lindex, lower, upper, stride, size, esize);
if (rank == 1) {
uint64_t lrange, rrange;
if (stride == 1) {
lrange = base + (lower-lindex)*size;
rrange = lrange + (upper-lower+1)*size - 1;
generate_one_range(spaces, lrange, rrange, fp, esize);
}
else {
for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
lrange = base + i*size;
rrange = lrange + size - 1;
generate_one_range(spaces, lrange, rrange, fp, esize);
}
}
}
else {
for (int i=lower-lindex; i<=upper-lindex; i+=stride) {
generate_mem_ranges_one_rank(
spaces, base+i*size, rank-1, ddp+1, fp, esize);
}
}
}
static void generate_mem_ranges(
const char *spaces,
const arr_desc *adp,
bool deref,
fpp fp
)
{
uint64_t esize;
OFFLOAD_TRACE(3,
"%s "
"generate_mem_ranges(adp=%p, deref=%d, fp)\n",
spaces, adp, deref);
last_left = -1;
last_right = -2;
// Element size is derived from last dimension
esize = adp->dim[adp->rank-1].size;
generate_mem_ranges_one_rank(
// For c_cean_var the base addr is the address of the data
// For c_cean_var_ptr the base addr is dereferenced to get to the data
spaces, deref ? *((uint64_t*)(adp->base)) : adp->base,
adp->rank, &adp->dim[0], fp, esize);
(*fp)(spaces, last_left, last_right, esize);
}
// returns offset and length of the data to be transferred
void __arr_data_offset_and_length(
const arr_desc *adp,
int64_t &offset,
int64_t &length
)
{
int64_t rank = adp->rank - 1;
int64_t size = adp->dim[rank].size;
int64_t r_off = 0; // offset from right boundary
// find the rightmost dimension which takes just part of its
// range. We define it if the size of left rank is not equal
// the range's length between upper and lower boungaries
while (rank > 0) {
size *= (adp->dim[rank].upper - adp->dim[rank].lower + 1);
if (size != adp->dim[rank - 1].size) {
break;
}
rank--;
}
offset = (adp->dim[rank].lower - adp->dim[rank].lindex) *
adp->dim[rank].size;
// find gaps both from the left - offset and from the right - r_off
for (rank--; rank >= 0; rank--) {
offset += (adp->dim[rank].lower - adp->dim[rank].lindex) *
adp->dim[rank].size;
r_off += adp->dim[rank].size -
(adp->dim[rank + 1].upper - adp->dim[rank + 1].lindex + 1) *
adp->dim[rank + 1].size;
}
length = (adp->dim[0].upper - adp->dim[0].lindex + 1) *
adp->dim[0].size - offset - r_off;
}
#if OFFLOAD_DEBUG > 0
void print_range(
const char *spaces,
uint64_t low,
uint64_t high,
int esize
)
{
char buffer[1024];
char number[32];
OFFLOAD_TRACE(3, "%s print_range(low=%p, high=%p, esize=%d)\n",
spaces, (void*)low, (void*)high, esize);
if (console_enabled < 4) {
return;
}
OFFLOAD_TRACE(4, "%s values:\n", spaces);
int count = 0;
buffer[0] = '\0';
while (low <= high)
{
switch (esize)
{
case 1:
sprintf(number, "%d ", *((char *)low));
low += 1;
break;
case 2:
sprintf(number, "%d ", *((short *)low));
low += 2;
break;
case 4:
sprintf(number, "%d ", *((int *)low));
low += 4;
break;
default:
sprintf(number, "0x%016x ", *((uint64_t *)low));
low += 8;
break;
}
strcat(buffer, number);
count++;
if (count == 10) {
OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
count = 0;
buffer[0] = '\0';
}
}
if (count != 0) {
OFFLOAD_TRACE(4, "%s %s\n", spaces, buffer);
}
}
void __arr_desc_dump(
const char *spaces,
const char *name,
const arr_desc *adp,
bool deref
)
{
OFFLOAD_TRACE(2, "%s%s CEAN expression %p\n", spaces, name, adp);
if (adp != 0) {
OFFLOAD_TRACE(2, "%s base=%llx, rank=%lld\n",
spaces, adp->base, adp->rank);
for (int i = 0; i < adp->rank; i++) {
OFFLOAD_TRACE(2,
"%s dimension %d: size=%lld, lindex=%lld, "
"lower=%lld, upper=%lld, stride=%lld\n",
spaces, i, adp->dim[i].size, adp->dim[i].lindex,
adp->dim[i].lower, adp->dim[i].upper,
adp->dim[i].stride);
}
// For c_cean_var the base addr is the address of the data
// For c_cean_var_ptr the base addr is dereferenced to get to the data
generate_mem_ranges(spaces, adp, deref, &print_range);
}
}
#endif // OFFLOAD_DEBUG
+101
View File
@@ -0,0 +1,101 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef CEAN_UTIL_H_INCLUDED
#define CEAN_UTIL_H_INCLUDED
#if MPSS_VERSION > 33
#include <source/COIBuffer_source.h>
#endif
#include <stdint.h>
#if MPSS_VERSION <= 33
// CEAN expression representation
struct dim_desc {
int64_t size; // Length of data type
int64_t lindex; // Lower index
int64_t lower; // Lower section bound
int64_t upper; // Upper section bound
int64_t stride; // Stride
};
struct arr_desc {
int64_t base; // Base address
int64_t rank; // Rank of array
dim_desc dim[1];
};
#endif
struct CeanReadDim {
int64_t count; // The number of elements in this dimension
int64_t size; // The number of bytes between successive
// elements in this dimension.
};
struct CeanReadRanges {
void * ptr;
int64_t current_number; // the number of ranges read
int64_t range_max_number; // number of contiguous ranges
int64_t range_size; // size of max contiguous range
int last_noncont_ind; // size of Dim array
int64_t init_offset; // offset of 1-st element from array left bound
CeanReadDim Dim[1];
};
// array descriptor length
#define __arr_desc_length(rank) \
(sizeof(int64_t) + sizeof(dim_desc) * (rank))
// returns offset and length of the data to be transferred
void __arr_data_offset_and_length(const arr_desc *adp,
int64_t &offset,
int64_t &length);
// define if data array described by argument is contiguous one
bool is_arr_desc_contiguous(const arr_desc *ap);
// allocate element of CeanReadRanges type initialized
// to read consequently contiguous ranges described by "ap" argument
CeanReadRanges * init_read_ranges_arr_desc(const arr_desc *ap);
// check if ranges described by 1 argument could be transferred into ranges
// described by 2-nd one
bool cean_ranges_match(
CeanReadRanges * read_rng1,
CeanReadRanges * read_rng2
);
// first argument - returned value by call to init_read_ranges_arr_desc.
// returns true if offset and length of next range is set successfuly.
// returns false if the ranges is over.
bool get_next_range(
CeanReadRanges * read_rng,
int64_t *offset
);
// returns number of transferred bytes
int64_t cean_get_transf_size(CeanReadRanges * read_rng);
#if OFFLOAD_DEBUG > 0
// prints array descriptor contents to stderr
void __arr_desc_dump(
const char *spaces,
const char *name,
const arr_desc *adp,
bool dereference);
#else
#define __arr_desc_dump(
spaces,
name,
adp,
dereference)
#endif // OFFLOAD_DEBUG
#endif // CEAN_UTIL_H_INCLUDED
+350
View File
@@ -0,0 +1,350 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// The COI host interface
#include "coi_client.h"
#include "../offload_common.h"
namespace COI {
#define COI_VERSION1 "COI_1.0"
#define COI_VERSION2 "COI_2.0"
bool is_available;
static void* lib_handle;
// pointers to functions from COI library
COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*);
COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*);
COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*, const void*,
uint64_t, int, const char**, uint8_t,
const char**, uint8_t, const char*,
uint64_t, const char*, const char*,
uint64_t, COIPROCESS*);
COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t, int8_t*, uint32_t*);
COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t, const char**,
COIFUNCTION*);
COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS, const void*, uint64_t,
const char*, const char*,
const char*, uint64_t, uint32_t,
COILIBRARY*);
COIRESULT (*ProcessRegisterLibraries)(uint32_t, const void**, const uint64_t*,
const char**, const uint64_t*);
COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*);
COIRESULT (*PipelineDestroy)(COIPIPELINE);
COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION, uint32_t,
const COIBUFFER*, const COI_ACCESS_FLAGS*,
uint32_t, const COIEVENT*, const void*,
uint16_t, void*, uint16_t, COIEVENT*);
COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*,
uint32_t, const COIPROCESS*, COIBUFFER*);
COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE, uint32_t,
void*, uint32_t, const COIPROCESS*,
COIBUFFER*);
COIRESULT (*BufferDestroy)(COIBUFFER);
COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t,
const COIEVENT*, COIEVENT*, COIMAPINSTANCE*, void**);
COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t, COI_COPY_TYPE,
uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*, COIEVENT*);
COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*);
COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t,
const COIEVENT*, COIEVENT*);
COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t, uint8_t, uint32_t*,
uint32_t*);
uint64_t (*PerfGetCycleFrequency)(void);
bool init(void)
{
#ifndef TARGET_WINNT
const char *lib_name = "libcoi_host.so.0";
#else // TARGET_WINNT
const char *lib_name = "coi_host.dll";
#endif // TARGET_WINNT
OFFLOAD_DEBUG_TRACE(2, "Loading COI library %s ...\n", lib_name);
lib_handle = DL_open(lib_name);
if (lib_handle == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to load the library\n");
return false;
}
EngineGetCount =
(COIRESULT (*)(COI_ISA_TYPE, uint32_t*))
DL_sym(lib_handle, "COIEngineGetCount", COI_VERSION1);
if (EngineGetCount == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEngineGetCount");
fini();
return false;
}
EngineGetHandle =
(COIRESULT (*)(COI_ISA_TYPE, uint32_t, COIENGINE*))
DL_sym(lib_handle, "COIEngineGetHandle", COI_VERSION1);
if (EngineGetHandle == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEngineGetHandle");
fini();
return false;
}
ProcessCreateFromMemory =
(COIRESULT (*)(COIENGINE, const char*, const void*, uint64_t, int,
const char**, uint8_t, const char**, uint8_t,
const char*, uint64_t, const char*, const char*,
uint64_t, COIPROCESS*))
DL_sym(lib_handle, "COIProcessCreateFromMemory", COI_VERSION1);
if (ProcessCreateFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessCreateFromMemory");
fini();
return false;
}
ProcessDestroy =
(COIRESULT (*)(COIPROCESS, int32_t, uint8_t, int8_t*,
uint32_t*))
DL_sym(lib_handle, "COIProcessDestroy", COI_VERSION1);
if (ProcessDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessDestroy");
fini();
return false;
}
ProcessGetFunctionHandles =
(COIRESULT (*)(COIPROCESS, uint32_t, const char**, COIFUNCTION*))
DL_sym(lib_handle, "COIProcessGetFunctionHandles", COI_VERSION1);
if (ProcessGetFunctionHandles == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessGetFunctionHandles");
fini();
return false;
}
ProcessLoadLibraryFromMemory =
(COIRESULT (*)(COIPROCESS, const void*, uint64_t, const char*,
const char*, const char*, uint64_t, uint32_t,
COILIBRARY*))
DL_sym(lib_handle, "COIProcessLoadLibraryFromMemory", COI_VERSION2);
if (ProcessLoadLibraryFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessLoadLibraryFromMemory");
fini();
return false;
}
ProcessRegisterLibraries =
(COIRESULT (*)(uint32_t, const void**, const uint64_t*, const char**,
const uint64_t*))
DL_sym(lib_handle, "COIProcessRegisterLibraries", COI_VERSION1);
if (ProcessRegisterLibraries == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIProcessRegisterLibraries");
fini();
return false;
}
PipelineCreate =
(COIRESULT (*)(COIPROCESS, COI_CPU_MASK, uint32_t, COIPIPELINE*))
DL_sym(lib_handle, "COIPipelineCreate", COI_VERSION1);
if (PipelineCreate == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineCreate");
fini();
return false;
}
PipelineDestroy =
(COIRESULT (*)(COIPIPELINE))
DL_sym(lib_handle, "COIPipelineDestroy", COI_VERSION1);
if (PipelineDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineDestroy");
fini();
return false;
}
PipelineRunFunction =
(COIRESULT (*)(COIPIPELINE, COIFUNCTION, uint32_t, const COIBUFFER*,
const COI_ACCESS_FLAGS*, uint32_t, const COIEVENT*,
const void*, uint16_t, void*, uint16_t, COIEVENT*))
DL_sym(lib_handle, "COIPipelineRunFunction", COI_VERSION1);
if (PipelineRunFunction == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPipelineRunFunction");
fini();
return false;
}
BufferCreate =
(COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, const void*,
uint32_t, const COIPROCESS*, COIBUFFER*))
DL_sym(lib_handle, "COIBufferCreate", COI_VERSION1);
if (BufferCreate == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCreate");
fini();
return false;
}
BufferCreateFromMemory =
(COIRESULT (*)(uint64_t, COI_BUFFER_TYPE, uint32_t, void*,
uint32_t, const COIPROCESS*, COIBUFFER*))
DL_sym(lib_handle, "COIBufferCreateFromMemory", COI_VERSION1);
if (BufferCreateFromMemory == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCreateFromMemory");
fini();
return false;
}
BufferDestroy =
(COIRESULT (*)(COIBUFFER))
DL_sym(lib_handle, "COIBufferDestroy", COI_VERSION1);
if (BufferDestroy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferDestroy");
fini();
return false;
}
BufferMap =
(COIRESULT (*)(COIBUFFER, uint64_t, uint64_t, COI_MAP_TYPE, uint32_t,
const COIEVENT*, COIEVENT*, COIMAPINSTANCE*,
void**))
DL_sym(lib_handle, "COIBufferMap", COI_VERSION1);
if (BufferMap == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferMap");
fini();
return false;
}
BufferUnmap =
(COIRESULT (*)(COIMAPINSTANCE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferUnmap", COI_VERSION1);
if (BufferUnmap == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferUnmap");
fini();
return false;
}
BufferWrite =
(COIRESULT (*)(COIBUFFER, uint64_t, const void*, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferWrite", COI_VERSION1);
if (BufferWrite == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferWrite");
fini();
return false;
}
BufferRead =
(COIRESULT (*)(COIBUFFER, uint64_t, void*, uint64_t,
COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*))
DL_sym(lib_handle, "COIBufferRead", COI_VERSION1);
if (BufferRead == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferRead");
fini();
return false;
}
BufferCopy =
(COIRESULT (*)(COIBUFFER, COIBUFFER, uint64_t, uint64_t, uint64_t,
COI_COPY_TYPE, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferCopy", COI_VERSION1);
if (BufferCopy == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferCopy");
fini();
return false;
}
BufferGetSinkAddress =
(COIRESULT (*)(COIBUFFER, uint64_t*))
DL_sym(lib_handle, "COIBufferGetSinkAddress", COI_VERSION1);
if (BufferGetSinkAddress == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferGetSinkAddress");
fini();
return false;
}
BufferSetState =
(COIRESULT(*)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t, const COIEVENT*,
COIEVENT*))
DL_sym(lib_handle, "COIBufferSetState", COI_VERSION1);
if (BufferSetState == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIBufferSetState");
fini();
return false;
}
EventWait =
(COIRESULT (*)(uint16_t, const COIEVENT*, int32_t, uint8_t,
uint32_t*, uint32_t*))
DL_sym(lib_handle, "COIEventWait", COI_VERSION1);
if (EventWait == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIEventWait");
fini();
return false;
}
PerfGetCycleFrequency =
(uint64_t (*)(void))
DL_sym(lib_handle, "COIPerfGetCycleFrequency", COI_VERSION1);
if (PerfGetCycleFrequency == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in COI library\n",
"COIPerfGetCycleFrequency");
fini();
return false;
}
is_available = true;
return true;
}
void fini(void)
{
is_available = false;
if (lib_handle != 0) {
#ifndef TARGET_WINNT
DL_close(lib_handle);
#endif // TARGET_WINNT
lib_handle = 0;
}
}
} // namespace COI
+118
View File
@@ -0,0 +1,118 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// The interface between offload library and the COI API on the host
#ifndef COI_CLIENT_H_INCLUDED
#define COI_CLIENT_H_INCLUDED
#include <common/COIPerf_common.h>
#include <source/COIEngine_source.h>
#include <source/COIProcess_source.h>
#include <source/COIPipeline_source.h>
#include <source/COIBuffer_source.h>
#include <source/COIEvent_source.h>
#include <string.h>
#include "../liboffload_error_codes.h"
#include "../offload_util.h"
#define MIC_ENGINES_MAX 128
#if MIC_ENGINES_MAX < COI_MAX_ISA_MIC_DEVICES
#error MIC_ENGINES_MAX need to be increased
#endif
// COI library interface
namespace COI {
extern bool init(void);
extern void fini(void);
extern bool is_available;
// pointers to functions from COI library
extern COIRESULT (*EngineGetCount)(COI_ISA_TYPE, uint32_t*);
extern COIRESULT (*EngineGetHandle)(COI_ISA_TYPE, uint32_t, COIENGINE*);
extern COIRESULT (*ProcessCreateFromMemory)(COIENGINE, const char*,
const void*, uint64_t, int,
const char**, uint8_t,
const char**, uint8_t,
const char*, uint64_t,
const char*,
const char*, uint64_t,
COIPROCESS*);
extern COIRESULT (*ProcessDestroy)(COIPROCESS, int32_t, uint8_t,
int8_t*, uint32_t*);
extern COIRESULT (*ProcessGetFunctionHandles)(COIPROCESS, uint32_t,
const char**,
COIFUNCTION*);
extern COIRESULT (*ProcessLoadLibraryFromMemory)(COIPROCESS,
const void*,
uint64_t,
const char*,
const char*,
const char*,
uint64_t,
uint32_t,
COILIBRARY*);
extern COIRESULT (*ProcessRegisterLibraries)(uint32_t,
const void**,
const uint64_t*,
const char**,
const uint64_t*);
extern COIRESULT (*PipelineCreate)(COIPROCESS, COI_CPU_MASK, uint32_t,
COIPIPELINE*);
extern COIRESULT (*PipelineDestroy)(COIPIPELINE);
extern COIRESULT (*PipelineRunFunction)(COIPIPELINE, COIFUNCTION,
uint32_t, const COIBUFFER*,
const COI_ACCESS_FLAGS*,
uint32_t, const COIEVENT*,
const void*, uint16_t, void*,
uint16_t, COIEVENT*);
extern COIRESULT (*BufferCreate)(uint64_t, COI_BUFFER_TYPE, uint32_t,
const void*, uint32_t,
const COIPROCESS*, COIBUFFER*);
extern COIRESULT (*BufferCreateFromMemory)(uint64_t, COI_BUFFER_TYPE,
uint32_t, void*,
uint32_t, const COIPROCESS*,
COIBUFFER*);
extern COIRESULT (*BufferDestroy)(COIBUFFER);
extern COIRESULT (*BufferMap)(COIBUFFER, uint64_t, uint64_t,
COI_MAP_TYPE, uint32_t, const COIEVENT*,
COIEVENT*, COIMAPINSTANCE*, void**);
extern COIRESULT (*BufferUnmap)(COIMAPINSTANCE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferWrite)(COIBUFFER, uint64_t, const void*,
uint64_t, COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferRead)(COIBUFFER, uint64_t, void*, uint64_t,
COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferCopy)(COIBUFFER, COIBUFFER, uint64_t, uint64_t,
uint64_t, COI_COPY_TYPE, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*BufferGetSinkAddress)(COIBUFFER, uint64_t*);
extern COIRESULT (*BufferSetState)(COIBUFFER, COIPROCESS, COI_BUFFER_STATE,
COI_BUFFER_MOVE_FLAG, uint32_t,
const COIEVENT*, COIEVENT*);
extern COIRESULT (*EventWait)(uint16_t, const COIEVENT*, int32_t,
uint8_t, uint32_t*, uint32_t*);
extern uint64_t (*PerfGetCycleFrequency)(void);
} // namespace COI
#endif // COI_CLIENT_H_INCLUDED
+130
View File
@@ -0,0 +1,130 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// The COI interface on the target
#include "coi_server.h"
#include "../offload_target.h"
#include "../offload_timer.h"
#ifdef MYO_SUPPORT
#include "../offload_myo_target.h" // for __offload_myoLibInit/Fini
#endif // MYO_SUPPORT
COINATIVELIBEXPORT
void server_compute(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
OffloadDescriptor::offload(buffer_count, buffers,
misc_data, misc_data_len,
return_data, return_data_len);
}
COINATIVELIBEXPORT
void server_init(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
struct init_data {
int device_index;
int devices_total;
int console_level;
int offload_report_level;
} *data = (struct init_data*) misc_data;
// set device index and number of total devices
mic_index = data->device_index;
mic_engines_total = data->devices_total;
// initialize trace level
console_enabled = data->console_level;
offload_report_level = data->offload_report_level;
// return back the process id
*((pid_t*) return_data) = getpid();
}
COINATIVELIBEXPORT
void server_var_table_size(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
struct Params {
int64_t nelems;
int64_t length;
} *params;
params = static_cast<Params*>(return_data);
params->length = __offload_vars.table_size(params->nelems);
}
COINATIVELIBEXPORT
void server_var_table_copy(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_vars.table_copy(buffers[0], *static_cast<int64_t*>(misc_data));
}
#ifdef MYO_SUPPORT
// temporary workaround for blocking behavior of myoiLibInit/Fini calls
COINATIVELIBEXPORT
void server_myoinit(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_myoLibInit();
}
COINATIVELIBEXPORT
void server_myofini(
uint32_t buffer_count,
void** buffers,
uint64_t* buffers_len,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
__offload_myoLibFini();
}
#endif // MYO_SUPPORT
+74
View File
@@ -0,0 +1,74 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
//The interface between offload library and the COI API on the target.
#ifndef COI_SERVER_H_INCLUDED
#define COI_SERVER_H_INCLUDED
#include <common/COIEngine_common.h>
#include <common/COIPerf_common.h>
#include <sink/COIProcess_sink.h>
#include <sink/COIPipeline_sink.h>
#include <sink/COIBuffer_sink.h>
#include <list>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "../liboffload_error_codes.h"
// wrappers for COI API
#define PipelineStartExecutingRunFunctions() \
{ \
COIRESULT res = COIPipelineStartExecutingRunFunctions(); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_pipeline_start_run_funcs, mic_index, res); \
exit(1); \
} \
}
#define ProcessWaitForShutdown() \
{ \
COIRESULT res = COIProcessWaitForShutdown(); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_process_wait_shutdown, mic_index, res); \
exit(1); \
} \
}
#define BufferAddRef(buf) \
{ \
COIRESULT res = COIBufferAddRef(buf); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_buf_add_ref, mic_index, res); \
exit(1); \
} \
}
#define BufferReleaseRef(buf) \
{ \
COIRESULT res = COIBufferReleaseRef(buf); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_buf_release_ref, mic_index, res); \
exit(1); \
} \
}
#define EngineGetIndex(index) \
{ \
COI_ISA_TYPE isa_type; \
COIRESULT res = COIEngineGetIndex(&isa_type, index); \
if (res != COI_SUCCESS) { \
LIBOFFLOAD_ERROR(c_get_engine_index, mic_index, res); \
exit(1); \
} \
}
#endif // COI_SERVER_H_INCLUDED
+323
View File
@@ -0,0 +1,323 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "compiler_if_host.h"
#include <malloc.h>
#ifndef TARGET_WINNT
#include <alloca.h>
#endif // TARGET_WINNT
// Global counter on host.
// This variable is used if P2OPT_offload_do_data_persistence == 2.
// The variable used to identify offload constructs contained in one procedure.
// Increment of OFFLOAD_CALL_COUNT is inserted at entries of HOST routines with
// offload constructs.
static int offload_call_count = 0;
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE(
TARGET_TYPE target_type,
int target_number,
int is_optional,
_Offload_status* status,
const char* file,
uint64_t line
)
{
bool retval;
OFFLOAD ofld;
// initialize status
if (status != 0) {
status->result = OFFLOAD_UNAVAILABLE;
status->device_number = -1;
status->data_sent = 0;
status->data_received = 0;
}
// make sure libray is initialized
retval = __offload_init_library();
// OFFLOAD_TIMER_INIT must follow call to __offload_init_library
OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);
OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
// initialize all devices is init_type is on_offload_all
if (retval && __offload_init_type == c_init_on_offload_all) {
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init();
}
}
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);
if (target_type == TARGET_HOST) {
// Host always available
retval = true;
}
else if (target_type == TARGET_MIC) {
if (target_number >= -1) {
if (retval) {
if (target_number >= 0) {
// User provided the device number
target_number = target_number % mic_engines_total;
}
else {
// use device 0
target_number = 0;
}
// reserve device in ORSL
if (is_optional) {
if (!ORSL::try_reserve(target_number)) {
target_number = -1;
}
}
else {
if (!ORSL::reserve(target_number)) {
target_number = -1;
}
}
// initialize device
if (target_number >= 0 &&
__offload_init_type == c_init_on_offload) {
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
mic_engines[target_number].init();
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
}
}
else {
// fallback to CPU
target_number = -1;
}
if (target_number < 0 || !retval) {
if (!is_optional && status == 0) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}
retval = false;
}
}
else {
LIBOFFLOAD_ERROR(c_invalid_device_number);
exit(1);
}
}
if (retval) {
ofld = new OffloadDescriptor(target_number, status,
!is_optional, false, timer_data);
OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);
Offload_Report_Prolog(timer_data);
OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
"Starting offload: target_type = %d, "
"number = %d, is_optional = %d\n",
target_type, target_number, is_optional);
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
}
else {
ofld = NULL;
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_total_offload);
offload_report_free_data(timer_data);
}
return ofld;
}
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1(
const int* device_num,
const char* file,
uint64_t line
)
{
int target_number;
// make sure libray is initialized and at least one device is available
if (!__offload_init_library()) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}
// OFFLOAD_TIMER_INIT must follow call to __offload_init_library
OffloadHostTimerData * timer_data = OFFLOAD_TIMER_INIT(file, line);
OFFLOAD_TIMER_START(timer_data, c_offload_host_total_offload);
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
if (__offload_init_type == c_init_on_offload_all) {
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init();
}
}
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
OFFLOAD_TIMER_START(timer_data, c_offload_host_target_acquire);
// use default device number if it is not provided
if (device_num != 0) {
target_number = *device_num;
}
else {
target_number = __omp_device_num;
}
// device number should be a non-negative integer value
if (target_number < 0) {
LIBOFFLOAD_ERROR(c_omp_invalid_device_num);
exit(1);
}
// should we do this for OpenMP?
target_number %= mic_engines_total;
// reserve device in ORSL
if (!ORSL::reserve(target_number)) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}
// initialize device(s)
OFFLOAD_TIMER_START(timer_data, c_offload_host_initialize);
if (__offload_init_type == c_init_on_offload) {
mic_engines[target_number].init();
}
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_initialize);
OFFLOAD ofld =
new OffloadDescriptor(target_number, 0, true, true, timer_data);
OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, target_number);
Offload_Report_Prolog(timer_data);
OFFLOAD_DEBUG_TRACE_1(2, timer_data->offload_number, c_offload_start,
"Starting OpenMP offload, device = %d\n",
target_number);
OFFLOAD_TIMER_STOP(timer_data, c_offload_host_target_acquire);
return ofld;
}
int offload_offload_wrap(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void **signal,
int entry_id,
const void *stack_addr
)
{
bool ret = ofld->offload(name, is_empty, vars, vars2, num_vars,
waits, num_waits, signal, entry_id, stack_addr);
if (!ret || signal == 0) {
delete ofld;
}
return ret;
}
extern "C" int OFFLOAD_OFFLOAD1(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void **signal
)
{
return offload_offload_wrap(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits, waits,
signal, NULL, NULL);
}
extern "C" int OFFLOAD_OFFLOAD2(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal,
int entry_id,
const void *stack_addr
)
{
return offload_offload_wrap(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits, waits,
signal, entry_id, stack_addr);
}
extern "C" int OFFLOAD_OFFLOAD(
OFFLOAD ofld,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void **waits,
const void *signal,
int entry_id,
const void *stack_addr
)
{
// signal is passed by reference now
const void **signal_new = (signal != 0) ? &signal : 0;
const void **waits_new = 0;
int num_waits_new = 0;
// remove NULL values from the list of signals to wait for
if (num_waits > 0) {
waits_new = (const void**) alloca(sizeof(void*) * num_waits);
for (int i = 0; i < num_waits; i++) {
if (waits[i] != 0) {
waits_new[num_waits_new++] = waits[i];
}
}
}
return OFFLOAD_OFFLOAD1(ofld, name, is_empty,
num_vars, vars, vars2,
num_waits_new, waits_new,
signal_new);
}
extern "C" int OFFLOAD_CALL_COUNT()
{
offload_call_count++;
return offload_call_count;
}
+133
View File
@@ -0,0 +1,133 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*! \file
\brief The interface between compiler-generated host code and runtime library
*/
#ifndef COMPILER_IF_HOST_H_INCLUDED
#define COMPILER_IF_HOST_H_INCLUDED
#include "offload_host.h"
#define OFFLOAD_TARGET_ACQUIRE OFFLOAD_PREFIX(target_acquire)
#define OFFLOAD_TARGET_ACQUIRE1 OFFLOAD_PREFIX(target_acquire1)
#define OFFLOAD_OFFLOAD OFFLOAD_PREFIX(offload)
#define OFFLOAD_OFFLOAD1 OFFLOAD_PREFIX(offload1)
#define OFFLOAD_OFFLOAD2 OFFLOAD_PREFIX(offload2)
#define OFFLOAD_CALL_COUNT OFFLOAD_PREFIX(offload_call_count)
/*! \fn OFFLOAD_TARGET_ACQUIRE
\brief Attempt to acquire the target.
\param target_type The type of target.
\param target_number The device number.
\param is_optional Whether CPU fall-back is allowed.
\param status Address of variable to hold offload status.
\param file Filename in which this offload occurred.
\param line Line number in the file where this offload occurred.
*/
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE(
TARGET_TYPE target_type,
int target_number,
int is_optional,
_Offload_status* status,
const char* file,
uint64_t line
);
/*! \fn OFFLOAD_TARGET_ACQUIRE1
\brief Acquire the target for offload (OpenMP).
\param device_number Device number or null if not specified.
\param file Filename in which this offload occurred
\param line Line number in the file where this offload occurred.
*/
extern "C" OFFLOAD OFFLOAD_TARGET_ACQUIRE1(
const int* device_number,
const char* file,
uint64_t line
);
/*! \fn OFFLOAD_OFFLOAD1
\brief Run function on target using interface for old data persistence.
\param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
\param name Name of offload entry point.
\param is_empty If no code to execute (e.g. offload_transfer)
\param num_vars Number of variable descriptors.
\param vars Pointer to VarDesc array.
\param vars2 Pointer to VarDesc2 array.
\param num_waits Number of "wait" values.
\param waits Pointer to array of wait values.
\param signal Pointer to signal value or NULL.
*/
extern "C" int OFFLOAD_OFFLOAD1(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal
);
/*! \fn OFFLOAD_OFFLOAD2
\brief Run function on target using interface for new data persistence.
\param o Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
\param name Name of offload entry point.
\param is_empty If no code to execute (e.g. offload_transfer)
\param num_vars Number of variable descriptors.
\param vars Pointer to VarDesc array.
\param vars2 Pointer to VarDesc2 array.
\param num_waits Number of "wait" values.
\param waits Pointer to array of wait values.
\param signal Pointer to signal value or NULL.
\param entry_id A signature for the function doing the offload.
\param stack_addr The stack frame address of the function doing offload.
*/
extern "C" int OFFLOAD_OFFLOAD2(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void** signal,
int entry_id,
const void *stack_addr
);
// Run function on target (obsolete).
// @param o OFFLOAD object
// @param name function name
extern "C" int OFFLOAD_OFFLOAD(
OFFLOAD o,
const char *name,
int is_empty,
int num_vars,
VarDesc *vars,
VarDesc2 *vars2,
int num_waits,
const void** waits,
const void* signal,
int entry_id = 0,
const void *stack_addr = NULL
);
// Global counter on host.
// This variable is used if P2OPT_offload_do_data_persistence == 2.
// The variable used to identify offload constructs contained in one procedure.
// Call to OFFLOAD_CALL_COUNT() is inserted at HOST on entry of the routine.
extern "C" int OFFLOAD_CALL_COUNT();
#endif // COMPILER_IF_HOST_H_INCLUDED
+44
View File
@@ -0,0 +1,44 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "compiler_if_target.h"
extern "C" void OFFLOAD_TARGET_ENTER(
OFFLOAD ofld,
int vars_total,
VarDesc *vars,
VarDesc2 *vars2
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p, %d, %p, %p)\n", __func__, ofld,
vars_total, vars, vars2);
ofld->merge_var_descs(vars, vars2, vars_total);
ofld->scatter_copyin_data();
}
extern "C" void OFFLOAD_TARGET_LEAVE(
OFFLOAD ofld
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ofld);
ofld->gather_copyout_data();
}
extern "C" void OFFLOAD_TARGET_MAIN(void)
{
// initialize target part
__offload_target_init();
// pass control to COI
PipelineStartExecutingRunFunctions();
ProcessWaitForShutdown();
OFFLOAD_DEBUG_TRACE(2, "Exiting main...\n");
}
+50
View File
@@ -0,0 +1,50 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*! \file
\brief The interface between compiler-generated target code and runtime library
*/
#ifndef COMPILER_IF_TARGET_H_INCLUDED
#define COMPILER_IF_TARGET_H_INCLUDED
#include "offload_target.h"
#define OFFLOAD_TARGET_ENTER OFFLOAD_PREFIX(target_enter)
#define OFFLOAD_TARGET_LEAVE OFFLOAD_PREFIX(target_leave)
#define OFFLOAD_TARGET_MAIN OFFLOAD_PREFIX(target_main)
/*! \fn OFFLOAD_TARGET_ENTER
\brief Fill in variable addresses using VarDesc array.
\brief Then call back the runtime library to fetch data.
\param ofld Offload descriptor created by runtime.
\param var_desc_num Number of variable descriptors.
\param var_desc Pointer to VarDesc array.
\param var_desc2 Pointer to VarDesc2 array.
*/
extern "C" void OFFLOAD_TARGET_ENTER(
OFFLOAD ofld,
int var_desc_num,
VarDesc *var_desc,
VarDesc2 *var_desc2
);
/*! \fn OFFLOAD_TARGET_LEAVE
\brief Call back the runtime library to gather outputs using VarDesc array.
\param ofld Offload descriptor created by OFFLOAD_TARGET_ACQUIRE.
*/
extern "C" void OFFLOAD_TARGET_LEAVE(
OFFLOAD ofld
);
// Entry point for the target application.
extern "C" void OFFLOAD_TARGET_MAIN(void);
#endif // COMPILER_IF_TARGET_H_INCLUDED
+131
View File
@@ -0,0 +1,131 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_common.h"
bool __dv_is_contiguous(const ArrDesc *dvp)
{
if (dvp->Flags & ArrDescFlagsContiguous) {
return true;
}
if (dvp->Rank != 0) {
if (dvp->Dim[0].Mult != dvp->Len) {
return false;
}
for (int i = 1; i < dvp->Rank; i++) {
if (dvp->Dim[i].Mult !=
dvp->Dim[i-1].Extent * dvp->Dim[i-1].Mult) {
return false;
}
}
}
return true;
}
bool __dv_is_allocated(const ArrDesc *dvp)
{
return (dvp->Flags & ArrDescFlagsDefined);
}
uint64_t __dv_data_length(const ArrDesc *dvp)
{
uint64_t size;
if (dvp->Rank == 0) {
size = dvp->Len;
return size;
}
size = dvp->Len;
for (int i = 0; i < dvp->Rank; ++i) {
size += (dvp->Dim[i].Extent-1) * dvp->Dim[i].Mult;
}
return size;
}
uint64_t __dv_data_length(const ArrDesc *dvp, int64_t count)
{
if (dvp->Rank == 0) {
return count;
}
return count * dvp->Dim[0].Mult;
}
// Create CeanReadRanges data for reading contiguous ranges of
// noncontiguous array defined by the argument
CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp)
{
int64_t len;
int count;
int rank = dvp->Rank;
CeanReadRanges *res = NULL;
if (rank != 0) {
int i = 0;
len = dvp->Len;
if (dvp->Dim[0].Mult == len) {
for (i = 1; i < rank; i++) {
len *= dvp->Dim[i-1].Extent;
if (dvp->Dim[i].Mult != len) {
break;
}
}
}
res = (CeanReadRanges *)malloc(
sizeof(CeanReadRanges) + (rank - i) * sizeof(CeanReadDim));
res -> last_noncont_ind = rank - i - 1;
count = 1;
for (; i < rank; i++) {
res->Dim[rank - i - 1].count = count;
res->Dim[rank - i - 1].size = dvp->Dim[i].Mult;
count *= dvp->Dim[i].Extent;
}
res -> range_max_number = count;
res -> range_size = len;
res -> ptr = (void*)dvp->Base;
res -> current_number = 0;
res -> init_offset = 0;
}
return res;
}
#if OFFLOAD_DEBUG > 0
void __dv_desc_dump(const char *name, const ArrDesc *dvp)
{
OFFLOAD_TRACE(3, "%s DV %p\n", name, dvp);
if (dvp != 0) {
OFFLOAD_TRACE(3,
" dv->Base = 0x%lx\n"
" dv->Len = 0x%lx\n"
" dv->Offset = 0x%lx\n"
" dv->Flags = 0x%lx\n"
" dv->Rank = 0x%lx\n"
" dv->Resrvd = 0x%lx\n",
dvp->Base,
dvp->Len,
dvp->Offset,
dvp->Flags,
dvp->Rank,
dvp->Reserved);
for (int i = 0 ; i < dvp->Rank; i++) {
OFFLOAD_TRACE(3,
" (%d) Extent=%ld, Multiplier=%ld, LowerBound=%ld\n",
i,
dvp->Dim[i].Extent,
dvp->Dim[i].Mult,
dvp->Dim[i].LowerBound);
}
}
}
#endif // OFFLOAD_DEBUG > 0
+63
View File
@@ -0,0 +1,63 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef DV_UTIL_H_INCLUDED
#define DV_UTIL_H_INCLUDED
#include <stdint.h>
// Dope vector declarations
#define ArrDescMaxArrayRank 31
// Dope vector flags
#define ArrDescFlagsDefined 1
#define ArrDescFlagsNodealloc 2
#define ArrDescFlagsContiguous 4
typedef int64_t dv_size;
typedef struct DimDesc {
dv_size Extent; // Number of elements in this dimension
dv_size Mult; // Multiplier for this dimension.
// The number of bytes between successive
// elements in this dimension.
dv_size LowerBound; // LowerBound of this dimension
} DimDesc ;
typedef struct ArrDesc {
dv_size Base; // Base address
dv_size Len; // Length of data type, used only for
// character strings.
dv_size Offset;
dv_size Flags; // Flags
dv_size Rank; // Rank of pointer
dv_size Reserved; // reserved for openmp requests
DimDesc Dim[ArrDescMaxArrayRank];
} ArrDesc ;
typedef ArrDesc* pArrDesc;
bool __dv_is_contiguous(const ArrDesc *dvp);
bool __dv_is_allocated(const ArrDesc *dvp);
uint64_t __dv_data_length(const ArrDesc *dvp);
uint64_t __dv_data_length(const ArrDesc *dvp, int64_t nelems);
CeanReadRanges * init_read_ranges_dv(const ArrDesc *dvp);
#if OFFLOAD_DEBUG > 0
void __dv_desc_dump(const char *name, const ArrDesc *dvp);
#else // OFFLOAD_DEBUG
#define __dv_desc_dump(name, dvp)
#endif // OFFLOAD_DEBUG
#endif // DV_UTIL_H_INCLUDED
+452
View File
@@ -0,0 +1,452 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
#include <stdarg.h>
#ifndef va_copy
#define va_copy(dst, src) ((dst) = (src))
#endif
#include "liboffload_msg.h"
#include "liboffload_error_codes.h"
/***********************************************/
/* error-handling function, liboffload_error_support */
/***********************************************/
void __liboffload_error_support(error_types input_tag, ...)
{
va_list args;
va_start(args, input_tag);
switch (input_tag) {
case c_device_is_not_available:
write_message(stderr, msg_c_device_is_not_available, args);
break;
case c_invalid_device_number:
write_message(stderr, msg_c_invalid_device_number, args);
break;
case c_send_func_ptr:
write_message(stderr, msg_c_send_func_ptr, args);
break;
case c_receive_func_ptr:
write_message(stderr, msg_c_receive_func_ptr, args);
break;
case c_offload_malloc:
write_message(stderr, msg_c_offload_malloc, args);
break;
case c_offload1:
write_message(stderr, msg_c_offload1, args);
break;
case c_unknown_var_type:
write_message(stderr, c_unknown_var_type, args);
break;
case c_invalid_env_var_value:
write_message(stderr, msg_c_invalid_env_var_value, args);
break;
case c_invalid_env_var_int_value:
write_message(stderr, msg_c_invalid_env_var_int_value, args);
break;
case c_invalid_env_report_value:
write_message(stderr, msg_c_invalid_env_report_value, args);
break;
case c_offload_signaled1:
write_message(stderr, msg_c_offload_signaled1, args);
break;
case c_offload_signaled2:
write_message(stderr, msg_c_offload_signaled2, args);
break;
case c_myowrapper_checkresult:
write_message(stderr, msg_c_myowrapper_checkresult, args);
break;
case c_myotarget_checkresult:
write_message(stderr, msg_c_myotarget_checkresult, args);
break;
case c_offload_descriptor_offload:
write_message(stderr, msg_c_offload_descriptor_offload, args);
break;
case c_merge_var_descs1:
write_message(stderr, msg_c_merge_var_descs1, args);
break;
case c_merge_var_descs2:
write_message(stderr, msg_c_merge_var_descs2, args);
break;
case c_mic_parse_env_var_list1:
write_message(stderr, msg_c_mic_parse_env_var_list1, args);
break;
case c_mic_parse_env_var_list2:
write_message(stderr, msg_c_mic_parse_env_var_list2, args);
break;
case c_mic_process_exit_ret:
write_message(stderr, msg_c_mic_process_exit_ret, args);
break;
case c_mic_process_exit_sig:
write_message(stderr, msg_c_mic_process_exit_sig, args);
break;
case c_mic_process_exit:
write_message(stderr, msg_c_mic_process_exit, args);
break;
case c_mic_init3:
write_message(stderr, msg_c_mic_init3, args);
break;
case c_mic_init4:
write_message(stderr, msg_c_mic_init4, args);
break;
case c_mic_init5:
write_message(stderr, msg_c_mic_init5, args);
break;
case c_mic_init6:
write_message(stderr, msg_c_mic_init6, args);
break;
case c_no_static_var_data:
write_message(stderr, msg_c_no_static_var_data, args);
break;
case c_no_ptr_data:
write_message(stderr, msg_c_no_ptr_data, args);
break;
case c_get_engine_handle:
write_message(stderr, msg_c_get_engine_handle, args);
break;
case c_get_engine_index:
write_message(stderr, msg_c_get_engine_index, args);
break;
case c_process_create:
write_message(stderr, msg_c_process_create, args);
break;
case c_process_wait_shutdown:
write_message(stderr, msg_c_process_wait_shutdown, args);
break;
case c_process_proxy_flush:
write_message(stderr, msg_c_process_proxy_flush, args);
break;
case c_process_get_func_handles:
write_message(stderr, msg_c_process_get_func_handles, args);
break;
case c_load_library:
write_message(stderr, msg_c_load_library, args);
break;
case c_coipipe_max_number:
write_message(stderr, msg_c_coi_pipeline_max_number, args);
break;
case c_pipeline_create:
write_message(stderr, msg_c_pipeline_create, args);
break;
case c_pipeline_run_func:
write_message(stderr, msg_c_pipeline_run_func, args);
break;
case c_pipeline_start_run_funcs:
write_message(stderr, msg_c_pipeline_start_run_funcs, args);
break;
case c_buf_create:
write_message(stderr, msg_c_buf_create, args);
break;
case c_buf_create_out_of_mem:
write_message(stderr, msg_c_buf_create_out_of_mem, args);
break;
case c_buf_create_from_mem:
write_message(stderr, msg_c_buf_create_from_mem, args);
break;
case c_buf_destroy:
write_message(stderr, msg_c_buf_destroy, args);
break;
case c_buf_map:
write_message(stderr, msg_c_buf_map, args);
break;
case c_buf_unmap:
write_message(stderr, msg_c_buf_unmap, args);
break;
case c_buf_read:
write_message(stderr, msg_c_buf_read, args);
break;
case c_buf_write:
write_message(stderr, msg_c_buf_write, args);
break;
case c_buf_copy:
write_message(stderr, msg_c_buf_copy, args);
break;
case c_buf_get_address:
write_message(stderr, msg_c_buf_get_address, args);
break;
case c_buf_add_ref:
write_message(stderr, msg_c_buf_add_ref, args);
break;
case c_buf_release_ref:
write_message(stderr, msg_c_buf_release_ref, args);
break;
case c_buf_set_state:
write_message(stderr, msg_c_buf_set_state, args);
break;
case c_event_wait:
write_message(stderr, msg_c_event_wait, args);
break;
case c_zero_or_neg_ptr_len:
write_message(stderr, msg_c_zero_or_neg_ptr_len, args);
break;
case c_zero_or_neg_transfer_size:
write_message(stderr, msg_c_zero_or_neg_transfer_size, args);
break;
case c_bad_ptr_mem_range:
write_message(stderr, msg_c_bad_ptr_mem_range, args);
break;
case c_different_src_and_dstn_sizes:
write_message(stderr, msg_c_different_src_and_dstn_sizes, args);
break;
case c_ranges_dont_match:
write_message(stderr, msg_c_ranges_dont_match, args);
break;
case c_destination_is_over:
write_message(stderr, msg_c_destination_is_over, args);
break;
case c_slice_of_noncont_array:
write_message(stderr, msg_c_slice_of_noncont_array, args);
break;
case c_non_contiguous_dope_vector:
write_message(stderr, msg_c_non_contiguous_dope_vector, args);
break;
case c_pointer_array_mismatch:
write_message(stderr, msg_c_pointer_array_mismatch, args);
break;
case c_omp_invalid_device_num_env:
write_message(stderr, msg_c_omp_invalid_device_num_env, args);
break;
case c_omp_invalid_device_num:
write_message(stderr, msg_c_omp_invalid_device_num, args);
break;
case c_unknown_binary_type:
write_message(stderr, msg_c_unknown_binary_type, args);
break;
case c_multiple_target_exes:
write_message(stderr, msg_c_multiple_target_exes, args);
break;
case c_no_target_exe:
write_message(stderr, msg_c_no_target_exe, args);
break;
case c_report_unknown_timer_node:
write_message(stderr, msg_c_report_unknown_timer_node, args);
break;
case c_report_unknown_trace_node:
write_message(stderr, msg_c_report_unknown_trace_node, args);
break;
}
va_end(args);
}
char const * report_get_message_str(error_types input_tag)
{
switch (input_tag) {
case c_report_title:
return (offload_get_message_str(msg_c_report_title));
case c_report_from_file:
return (offload_get_message_str(msg_c_report_from_file));
case c_report_offload:
return (offload_get_message_str(msg_c_report_offload));
case c_report_mic:
return (offload_get_message_str(msg_c_report_mic));
case c_report_file:
return (offload_get_message_str(msg_c_report_file));
case c_report_line:
return (offload_get_message_str(msg_c_report_line));
case c_report_host:
return (offload_get_message_str(msg_c_report_host));
case c_report_tag:
return (offload_get_message_str(msg_c_report_tag));
case c_report_cpu_time:
return (offload_get_message_str(msg_c_report_cpu_time));
case c_report_seconds:
return (offload_get_message_str(msg_c_report_seconds));
case c_report_cpu_to_mic_data:
return (offload_get_message_str(msg_c_report_cpu_to_mic_data));
case c_report_bytes:
return (offload_get_message_str(msg_c_report_bytes));
case c_report_mic_time:
return (offload_get_message_str(msg_c_report_mic_time));
case c_report_mic_to_cpu_data:
return (offload_get_message_str(msg_c_report_mic_to_cpu_data));
case c_report_compute:
return (offload_get_message_str(msg_c_report_compute));
case c_report_copyin_data:
return (offload_get_message_str(msg_c_report_copyin_data));
case c_report_copyout_data:
return (offload_get_message_str(msg_c_report_copyout_data));
case c_report_create_buf_host:
return (offload_get_message_str(c_report_create_buf_host));
case c_report_create_buf_mic:
return (offload_get_message_str(msg_c_report_create_buf_mic));
case c_report_destroy:
return (offload_get_message_str(msg_c_report_destroy));
case c_report_gather_copyin_data:
return (offload_get_message_str(msg_c_report_gather_copyin_data));
case c_report_gather_copyout_data:
return (offload_get_message_str(msg_c_report_gather_copyout_data));
case c_report_state_signal:
return (offload_get_message_str(msg_c_report_state_signal));
case c_report_signal:
return (offload_get_message_str(msg_c_report_signal));
case c_report_wait:
return (offload_get_message_str(msg_c_report_wait));
case c_report_init:
return (offload_get_message_str(msg_c_report_init));
case c_report_init_func:
return (offload_get_message_str(msg_c_report_init_func));
case c_report_logical_card:
return (offload_get_message_str(msg_c_report_logical_card));
case c_report_mic_myo_fptr:
return (offload_get_message_str(msg_c_report_mic_myo_fptr));
case c_report_mic_myo_shared:
return (offload_get_message_str(msg_c_report_mic_myo_shared));
case c_report_myoacquire:
return (offload_get_message_str(msg_c_report_myoacquire));
case c_report_myofini:
return (offload_get_message_str(msg_c_report_myofini));
case c_report_myoinit:
return (offload_get_message_str(msg_c_report_myoinit));
case c_report_myoregister:
return (offload_get_message_str(msg_c_report_myoregister));
case c_report_myorelease:
return (offload_get_message_str(msg_c_report_myorelease));
case c_report_myosharedalignedfree:
return (
offload_get_message_str(msg_c_report_myosharedalignedfree));
case c_report_myosharedalignedmalloc:
return (
offload_get_message_str(msg_c_report_myosharedalignedmalloc));
case c_report_myosharedfree:
return (offload_get_message_str(msg_c_report_myosharedfree));
case c_report_myosharedmalloc:
return (offload_get_message_str(msg_c_report_myosharedmalloc));
case c_report_physical_card:
return (offload_get_message_str(msg_c_report_physical_card));
case c_report_receive_pointer_data:
return (
offload_get_message_str(msg_c_report_receive_pointer_data));
case c_report_received_pointer_data:
return (
offload_get_message_str(msg_c_report_received_pointer_data));
case c_report_register:
return (offload_get_message_str(msg_c_report_register));
case c_report_scatter_copyin_data:
return (offload_get_message_str(msg_c_report_scatter_copyin_data));
case c_report_scatter_copyout_data:
return (
offload_get_message_str(msg_c_report_scatter_copyout_data));
case c_report_send_pointer_data:
return (offload_get_message_str(msg_c_report_send_pointer_data));
case c_report_sent_pointer_data:
return (offload_get_message_str(msg_c_report_sent_pointer_data));
case c_report_start:
return (offload_get_message_str(msg_c_report_start));
case c_report_start_target_func:
return (offload_get_message_str(msg_c_report_start_target_func));
case c_report_state:
return (offload_get_message_str(msg_c_report_state));
case c_report_unregister:
return (offload_get_message_str(msg_c_report_unregister));
case c_report_var:
return (offload_get_message_str(msg_c_report_var));
default:
LIBOFFLOAD_ERROR(c_report_unknown_trace_node);
abort();
}
}
char const * report_get_host_stage_str(int i)
{
switch (i) {
case c_offload_host_total_offload:
return (
offload_get_message_str(msg_c_report_host_total_offload_time));
case c_offload_host_initialize:
return (offload_get_message_str(msg_c_report_host_initialize));
case c_offload_host_target_acquire:
return (
offload_get_message_str(msg_c_report_host_target_acquire));
case c_offload_host_wait_deps:
return (offload_get_message_str(msg_c_report_host_wait_deps));
case c_offload_host_setup_buffers:
return (offload_get_message_str(msg_c_report_host_setup_buffers));
case c_offload_host_alloc_buffers:
return (offload_get_message_str(msg_c_report_host_alloc_buffers));
case c_offload_host_setup_misc_data:
return (
offload_get_message_str(msg_c_report_host_setup_misc_data));
case c_offload_host_alloc_data_buffer:
return (
offload_get_message_str(msg_c_report_host_alloc_data_buffer));
case c_offload_host_send_pointers:
return (offload_get_message_str(msg_c_report_host_send_pointers));
case c_offload_host_gather_inputs:
return (offload_get_message_str(msg_c_report_host_gather_inputs));
case c_offload_host_map_in_data_buffer:
return (
offload_get_message_str(msg_c_report_host_map_in_data_buffer));
case c_offload_host_unmap_in_data_buffer:
return (offload_get_message_str(
msg_c_report_host_unmap_in_data_buffer));
case c_offload_host_start_compute:
return (offload_get_message_str(msg_c_report_host_start_compute));
case c_offload_host_wait_compute:
return (offload_get_message_str(msg_c_report_host_wait_compute));
case c_offload_host_start_buffers_reads:
return (offload_get_message_str(
msg_c_report_host_start_buffers_reads));
case c_offload_host_scatter_outputs:
return (
offload_get_message_str(msg_c_report_host_scatter_outputs));
case c_offload_host_map_out_data_buffer:
return (offload_get_message_str(
msg_c_report_host_map_out_data_buffer));
case c_offload_host_unmap_out_data_buffer:
return (offload_get_message_str(
msg_c_report_host_unmap_out_data_buffer));
case c_offload_host_wait_buffers_reads:
return (
offload_get_message_str(msg_c_report_host_wait_buffers_reads));
case c_offload_host_destroy_buffers:
return (
offload_get_message_str(msg_c_report_host_destroy_buffers));
default:
LIBOFFLOAD_ERROR(c_report_unknown_timer_node);
abort();
}
}
char const * report_get_target_stage_str(int i)
{
switch (i) {
case c_offload_target_total_time:
return (offload_get_message_str(msg_c_report_target_total_time));
case c_offload_target_descriptor_setup:
return (
offload_get_message_str(msg_c_report_target_descriptor_setup));
case c_offload_target_func_lookup:
return (offload_get_message_str(msg_c_report_target_func_lookup));
case c_offload_target_func_time:
return (offload_get_message_str(msg_c_report_target_func_time));
case c_offload_target_scatter_inputs:
return (
offload_get_message_str(msg_c_report_target_scatter_inputs));
case c_offload_target_add_buffer_refs:
return (
offload_get_message_str(msg_c_report_target_add_buffer_refs));
case c_offload_target_compute:
return (offload_get_message_str(msg_c_report_target_compute));
case c_offload_target_gather_outputs:
return (offload_get_message_str
(msg_c_report_target_gather_outputs));
case c_offload_target_release_buffer_refs:
return (offload_get_message_str(
msg_c_report_target_release_buffer_refs));
default:
LIBOFFLOAD_ERROR(c_report_unknown_timer_node);
abort();
}
}
+276
View File
@@ -0,0 +1,276 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#if !defined(LIBOFFLOAD_ERROR_CODES_H)
#define LIBOFFLOAD_ERROR_CODES_H
#include <stdarg.h>
#include <stdlib.h>
#include <stdio.h>
typedef enum
{
c_device_is_not_available = 0,
c_invalid_device_number,
c_offload1,
c_unknown_var_type,
c_send_func_ptr,
c_receive_func_ptr,
c_offload_malloc,
c_invalid_env_var_value,
c_invalid_env_var_int_value,
c_invalid_env_report_value,
c_offload_signaled1,
c_offload_signaled2,
c_myotarget_checkresult,
c_myowrapper_checkresult,
c_offload_descriptor_offload,
c_merge_var_descs1,
c_merge_var_descs2,
c_mic_parse_env_var_list1,
c_mic_parse_env_var_list2,
c_mic_process_exit_ret,
c_mic_process_exit_sig,
c_mic_process_exit,
c_mic_init3,
c_mic_init4,
c_mic_init5,
c_mic_init6,
c_no_static_var_data,
c_no_ptr_data,
c_get_engine_handle,
c_get_engine_index,
c_process_create,
c_process_get_func_handles,
c_process_wait_shutdown,
c_process_proxy_flush,
c_load_library,
c_pipeline_create,
c_pipeline_run_func,
c_pipeline_start_run_funcs,
c_buf_create,
c_buf_create_out_of_mem,
c_buf_create_from_mem,
c_buf_destroy,
c_buf_map,
c_buf_unmap,
c_buf_read,
c_buf_write,
c_buf_copy,
c_buf_get_address,
c_buf_add_ref,
c_buf_release_ref,
c_buf_set_state,
c_event_wait,
c_zero_or_neg_ptr_len,
c_zero_or_neg_transfer_size,
c_bad_ptr_mem_range,
c_different_src_and_dstn_sizes,
c_ranges_dont_match,
c_destination_is_over,
c_slice_of_noncont_array,
c_non_contiguous_dope_vector,
c_pointer_array_mismatch,
c_omp_invalid_device_num_env,
c_omp_invalid_device_num,
c_unknown_binary_type,
c_multiple_target_exes,
c_no_target_exe,
c_report_host,
c_report_target,
c_report_title,
c_report_from_file,
c_report_file,
c_report_line,
c_report_tag,
c_report_seconds,
c_report_bytes,
c_report_mic,
c_report_cpu_time,
c_report_cpu_to_mic_data,
c_report_mic_time,
c_report_mic_to_cpu_data,
c_report_unknown_timer_node,
c_report_unknown_trace_node,
c_report_offload,
c_report_w_tag,
c_report_state,
c_report_start,
c_report_init,
c_report_logical_card,
c_report_physical_card,
c_report_register,
c_report_init_func,
c_report_create_buf_host,
c_report_create_buf_mic,
c_report_send_pointer_data,
c_report_sent_pointer_data,
c_report_gather_copyin_data,
c_report_copyin_data,
c_report_state_signal,
c_report_signal,
c_report_wait,
c_report_compute,
c_report_receive_pointer_data,
c_report_received_pointer_data,
c_report_start_target_func,
c_report_var,
c_report_scatter_copyin_data,
c_report_gather_copyout_data,
c_report_scatter_copyout_data,
c_report_copyout_data,
c_report_unregister,
c_report_destroy,
c_report_myoinit,
c_report_myoregister,
c_report_myofini,
c_report_mic_myo_shared,
c_report_mic_myo_fptr,
c_report_myosharedmalloc,
c_report_myosharedfree,
c_report_myosharedalignedmalloc,
c_report_myosharedalignedfree,
c_report_myoacquire,
c_report_myorelease,
c_coipipe_max_number
} error_types;
enum OffloadHostPhase {
// Total time on host for entire offload
c_offload_host_total_offload = 0,
// Time to load target binary
c_offload_host_initialize,
// Time to acquire lrb availability dynamically
c_offload_host_target_acquire,
// Time to wait for dependencies
c_offload_host_wait_deps,
// Time to allocate pointer buffers, initiate writes for pointers
// and calculate size of copyin/copyout buffer
c_offload_host_setup_buffers,
// Time to allocate pointer buffers
c_offload_host_alloc_buffers,
// Time to initialize misc data
c_offload_host_setup_misc_data,
// Time to allocate copyin/copyout buffer
c_offload_host_alloc_data_buffer,
// Time to initiate writes from host pointers to buffers
c_offload_host_send_pointers,
// Time to Gather IN data of offload into buffer
c_offload_host_gather_inputs,
// Time to map buffer
c_offload_host_map_in_data_buffer,
// Time to unmap buffer
c_offload_host_unmap_in_data_buffer,
// Time to start remote function call that does computation on lrb
c_offload_host_start_compute,
// Time to wait for compute to finish
c_offload_host_wait_compute,
// Time to initiate reads from pointer buffers
c_offload_host_start_buffers_reads,
// Time to update host variabels with OUT data from buffer
c_offload_host_scatter_outputs,
// Time to map buffer
c_offload_host_map_out_data_buffer,
// Time to unmap buffer
c_offload_host_unmap_out_data_buffer,
// Time to wait reads from buffers to finish
c_offload_host_wait_buffers_reads,
// Time to destroy buffers that are no longer needed
c_offload_host_destroy_buffers,
// LAST TIME MONITOR
c_offload_host_max_phase
};
enum OffloadTargetPhase {
// Total time spent on the target
c_offload_target_total_time = 0,
// Time to initialize offload descriptor
c_offload_target_descriptor_setup,
// Time to find target entry point in lookup table
c_offload_target_func_lookup,
// Total time spend executing offload entry
c_offload_target_func_time,
// Time to initialize target variables with IN values from buffer
c_offload_target_scatter_inputs,
// Time to add buffer reference for pointer buffers
c_offload_target_add_buffer_refs,
// Total time on lrb for computation
c_offload_target_compute,
// On lrb, time to copy OUT into buffer
c_offload_target_gather_outputs,
// Time to release buffer references
c_offload_target_release_buffer_refs,
// LAST TIME MONITOR
c_offload_target_max_phase
};
#ifdef __cplusplus
extern "C" {
#endif
void __liboffload_error_support(error_types input_tag, ...);
void __liboffload_report_support(error_types input_tag, ...);
char const *offload_get_message_str(int msgCode);
char const * report_get_message_str(error_types input_tag);
char const * report_get_host_stage_str(int i);
char const * report_get_target_stage_str(int i);
#ifdef __cplusplus
}
#endif
#define test_msg_cat(nm, msg) \
fprintf(stderr, "\t TEST for %s \n \t", nm); \
__liboffload_error_support(msg);
#define test_msg_cat1(nm, msg, ...) \
fprintf(stderr, "\t TEST for %s \n \t", nm); \
__liboffload_error_support(msg, __VA_ARGS__);
void write_message(FILE * file, int msgCode, va_list args_p);
#define LIBOFFLOAD_ERROR __liboffload_error_support
#ifdef TARGET_WINNT
#define LIBOFFLOAD_ABORT \
_set_abort_behavior(0, _WRITE_ABORT_MSG); \
abort()
#else
#define LIBOFFLOAD_ABORT \
abort()
#endif
#endif // !defined(LIBOFFLOAD_ERROR_CODES_H)
+35
View File
@@ -0,0 +1,35 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <stdio.h>
// ===========================================================================
// Bring in the static string table and the enumerations for indexing into
// it.
// ===========================================================================
#include "liboffload_msg.h"
# define DYNART_STDERR_PUTS(__message_text__) fputs((__message_text__),stderr)
// ===========================================================================
// Now the code for accessing the message catalogs
// ===========================================================================
void write_message(FILE * file, int msgCode) {
fputs(MESSAGE_TABLE_NAME[ msgCode ], file);
fflush(file);
}
char const *offload_get_message_str(int msgCode) {
return MESSAGE_TABLE_NAME[ msgCode ];
}
+326
View File
@@ -0,0 +1,326 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// file: liboffload_msg.h
enum {
__dummy__ = 0,
msg_c_device_is_not_available,
msg_c_invalid_device_number,
msg_c_send_func_ptr,
msg_c_receive_func_ptr,
msg_c_offload_malloc,
msg_c_offload1,
msg_c_unknown_var_type,
msg_c_invalid_env_var_value,
msg_c_invalid_env_var_int_value,
msg_c_invalid_env_report_value,
msg_c_offload_signaled1,
msg_c_offload_signaled2,
msg_c_myowrapper_checkresult,
msg_c_myotarget_checkresult,
msg_c_offload_descriptor_offload,
msg_c_merge_var_descs1,
msg_c_merge_var_descs2,
msg_c_mic_parse_env_var_list1,
msg_c_mic_parse_env_var_list2,
msg_c_mic_process_exit_ret,
msg_c_mic_process_exit_sig,
msg_c_mic_process_exit,
msg_c_mic_init3,
msg_c_mic_init4,
msg_c_mic_init5,
msg_c_mic_init6,
msg_c_no_static_var_data,
msg_c_no_ptr_data,
msg_c_get_engine_handle,
msg_c_get_engine_index,
msg_c_process_create,
msg_c_process_get_func_handles,
msg_c_process_wait_shutdown,
msg_c_process_proxy_flush,
msg_c_load_library,
msg_c_pipeline_create,
msg_c_pipeline_run_func,
msg_c_pipeline_start_run_funcs,
msg_c_buf_create,
msg_c_buf_create_out_of_mem,
msg_c_buf_create_from_mem,
msg_c_buf_destroy,
msg_c_buf_map,
msg_c_buf_unmap,
msg_c_buf_read,
msg_c_buf_write,
msg_c_buf_copy,
msg_c_buf_get_address,
msg_c_buf_add_ref,
msg_c_buf_release_ref,
msg_c_buf_set_state,
msg_c_event_wait,
msg_c_zero_or_neg_ptr_len,
msg_c_zero_or_neg_transfer_size,
msg_c_bad_ptr_mem_range,
msg_c_different_src_and_dstn_sizes,
msg_c_non_contiguous_dope_vector,
msg_c_omp_invalid_device_num_env,
msg_c_omp_invalid_device_num,
msg_c_unknown_binary_type,
msg_c_multiple_target_exes,
msg_c_no_target_exe,
msg_c_report_unknown_timer_node,
msg_c_report_unknown_trace_node,
msg_c_report_host,
msg_c_report_mic,
msg_c_report_title,
msg_c_report_seconds,
msg_c_report_bytes,
msg_c_report_cpu_time,
msg_c_report_mic_time,
msg_c_report_tag,
msg_c_report_from_file,
msg_c_report_file,
msg_c_report_line,
msg_c_report_cpu_to_mic_data,
msg_c_report_mic_to_cpu_data,
msg_c_report_offload,
msg_c_report_w_tag,
msg_c_report_state,
msg_c_report_start,
msg_c_report_init,
msg_c_report_logical_card,
msg_c_report_physical_card,
msg_c_report_register,
msg_c_report_init_func,
msg_c_report_create_buf_host,
msg_c_report_create_buf_mic,
msg_c_report_send_pointer_data,
msg_c_report_sent_pointer_data,
msg_c_report_gather_copyin_data,
msg_c_report_copyin_data,
msg_c_report_state_signal,
msg_c_report_signal,
msg_c_report_wait,
msg_c_report_compute,
msg_c_report_receive_pointer_data,
msg_c_report_received_pointer_data,
msg_c_report_start_target_func,
msg_c_report_var,
msg_c_report_scatter_copyin_data,
msg_c_report_gather_copyout_data,
msg_c_report_scatter_copyout_data,
msg_c_report_copyout_data,
msg_c_report_unregister,
msg_c_report_destroy,
msg_c_report_myoinit,
msg_c_report_myoregister,
msg_c_report_myofini,
msg_c_report_mic_myo_shared,
msg_c_report_mic_myo_fptr,
msg_c_report_myosharedmalloc,
msg_c_report_myosharedfree,
msg_c_report_myosharedalignedmalloc,
msg_c_report_myosharedalignedfree,
msg_c_report_myoacquire,
msg_c_report_myorelease,
msg_c_report_host_total_offload_time,
msg_c_report_host_initialize,
msg_c_report_host_target_acquire,
msg_c_report_host_wait_deps,
msg_c_report_host_setup_buffers,
msg_c_report_host_alloc_buffers,
msg_c_report_host_setup_misc_data,
msg_c_report_host_alloc_data_buffer,
msg_c_report_host_send_pointers,
msg_c_report_host_gather_inputs,
msg_c_report_host_map_in_data_buffer,
msg_c_report_host_unmap_in_data_buffer,
msg_c_report_host_start_compute,
msg_c_report_host_wait_compute,
msg_c_report_host_start_buffers_reads,
msg_c_report_host_scatter_outputs,
msg_c_report_host_map_out_data_buffer,
msg_c_report_host_unmap_out_data_buffer,
msg_c_report_host_wait_buffers_reads,
msg_c_report_host_destroy_buffers,
msg_c_report_target_total_time,
msg_c_report_target_descriptor_setup,
msg_c_report_target_func_lookup,
msg_c_report_target_func_time,
msg_c_report_target_scatter_inputs,
msg_c_report_target_add_buffer_refs,
msg_c_report_target_compute,
msg_c_report_target_gather_outputs,
msg_c_report_target_release_buffer_refs,
msg_c_coi_pipeline_max_number,
msg_c_ranges_dont_match,
msg_c_destination_is_over,
msg_c_slice_of_noncont_array,
msg_c_pointer_array_mismatch,
lastMsg = 152,
firstMsg = 1
};
#if !defined(MESSAGE_TABLE_NAME)
# define MESSAGE_TABLE_NAME __liboffload_message_table
#endif
static char const * MESSAGE_TABLE_NAME[] = {
/* 0 __dummy__ */ "Un-used message",
/* 1 msg_c_device_is_not_available */ "offload error: cannot offload to MIC - device is not available",
/* 2 msg_c_invalid_device_number */ "offload error: expected a number greater than or equal to -1",
/* 3 msg_c_send_func_ptr */ "offload error: cannot find function name for address %p",
/* 4 msg_c_receive_func_ptr */ "offload error: cannot find address of function %s",
/* 5 msg_c_offload_malloc */ "offload error: memory allocation failed (requested=%lld bytes, align %lld)",
/* 6 msg_c_offload1 */ "offload error: device %d does not have a pending signal for wait(%p)",
/* 7 msg_c_unknown_var_type */ "offload error: unknown variable type %d",
/* 8 msg_c_invalid_env_var_value */ "offload warning: ignoring invalid value specified for %s",
/* 9 msg_c_invalid_env_var_int_value */ "offload warning: specify an integer value for %s",
/* 10 msg_c_invalid_env_report_value */ "offload warning: ignoring %s setting; use a value in range 1-3",
/* 11 msg_c_offload_signaled1 */ "offload error: invalid device number %d specified in _Offload_signaled",
/* 12 msg_c_offload_signaled2 */ "offload error: invalid signal %p specified for _Offload_signaled",
/* 13 msg_c_myowrapper_checkresult */ "offload error: %s failed with error %d",
/* 14 msg_c_myotarget_checkresult */ "offload error: %s failed with error %d",
/* 15 msg_c_offload_descriptor_offload */ "offload error: cannot find offload entry %s",
/* 16 msg_c_merge_var_descs1 */ "offload error: unexpected number of variable descriptors",
/* 17 msg_c_merge_var_descs2 */ "offload error: unexpected variable type",
/* 18 msg_c_mic_parse_env_var_list1 */ "offload_error: MIC environment variable must begin with an alpabetic character",
/* 19 msg_c_mic_parse_env_var_list2 */ "offload_error: MIC environment variable value must be specified with =",
/* 20 msg_c_mic_process_exit_ret */ "offload error: process on the device %d unexpectedly exited with code %d",
/* 21 msg_c_mic_process_exit_sig */ "offload error: process on the device %d was terminated by signal %d (%s)",
/* 22 msg_c_mic_process_exit */ "offload error: process on the device %d was unexpectedly terminated",
/* 23 msg_c_mic_init3 */ "offload warning: ignoring MIC_STACKSIZE setting; use a value >= 16K and a multiple of 4K",
/* 24 msg_c_mic_init4 */ "offload error: thread key create failed with error %d",
/* 25 msg_c_mic_init5 */ "offload warning: specify OFFLOAD_DEVICES as comma-separated physical device numbers or 'none'",
/* 26 msg_c_mic_init6 */ "offload warning: OFFLOAD_DEVICES device number %d does not correspond to a physical device",
/* 27 msg_c_no_static_var_data */ "offload error: cannot find data associated with statically allocated variable %p",
/* 28 msg_c_no_ptr_data */ "offload error: cannot find data associated with pointer variable %p",
/* 29 msg_c_get_engine_handle */ "offload error: cannot get device %d handle (error code %d)",
/* 30 msg_c_get_engine_index */ "offload error: cannot get physical index for logical device %d (error code %d)",
/* 31 msg_c_process_create */ "offload error: cannot start process on the device %d (error code %d)",
/* 32 msg_c_process_get_func_handles */ "offload error: cannot get function handles on the device %d (error code %d)",
/* 33 msg_c_process_wait_shutdown */ "offload error: wait for process shutdown failed on device %d (error code %d)",
/* 34 msg_c_process_proxy_flush */ "offload error: cannot flush process output on device %d (error code %d)",
/* 35 msg_c_load_library */ "offload error: cannot load library to the device %d (error code %d)",
/* 36 msg_c_pipeline_create */ "offload error: cannot create pipeline on the device %d (error code %d)",
/* 37 msg_c_pipeline_run_func */ "offload error: cannot execute function on the device %d (error code %d)",
/* 38 msg_c_pipeline_start_run_funcs */ "offload error: cannot start executing pipeline function on the device %d (error code %d)",
/* 39 msg_c_buf_create */ "offload error: cannot create buffer on device %d (error code %d)",
/* 40 msg_c_buf_create_out_of_mem */ "offload error: cannot create buffer on device %d, out of memory",
/* 41 msg_c_buf_create_from_mem */ "offload error: cannot create buffer from memory on device %d (error code %d)",
/* 42 msg_c_buf_destroy */ "offload error: buffer destroy failed (error code %d)",
/* 43 msg_c_buf_map */ "offload error: buffer map failed (error code %d)",
/* 44 msg_c_buf_unmap */ "offload error: buffer unmap failed (error code %d)",
/* 45 msg_c_buf_read */ "offload error: buffer read failed (error code %d)",
/* 46 msg_c_buf_write */ "offload error: buffer write failed (error code %d)",
/* 47 msg_c_buf_copy */ "offload error: buffer copy failed (error code %d)",
/* 48 msg_c_buf_get_address */ "offload error: cannot get buffer address on device %d (error code %d)",
/* 49 msg_c_buf_add_ref */ "offload error: cannot reuse buffer memory on device %d (error code %d)",
/* 50 msg_c_buf_release_ref */ "offload error: cannot release buffer memory on device %d (error code %d)",
/* 51 msg_c_buf_set_state */ "offload error: buffer set state failed (error code %d)",
/* 52 msg_c_event_wait */ "offload error: wait for event to become signaled failed (error code %d)",
/* 53 msg_c_zero_or_neg_ptr_len */ "offload error: memory allocation of negative length is not supported",
/* 54 msg_c_zero_or_neg_transfer_size */ "offload error: data transfer of zero or negative size is not supported",
/* 55 msg_c_bad_ptr_mem_range */ "offload error: address range partially overlaps with existing allocation",
/* 56 msg_c_different_src_and_dstn_sizes */ "offload error: size of the source %d differs from size of the destination %d",
/* 57 msg_c_non_contiguous_dope_vector */ "offload error: offload data transfer supports only a single contiguous memory range per variable",
/* 58 msg_c_omp_invalid_device_num_env */ "offload warning: ignoring %s setting; use a non-negative integer value",
/* 59 msg_c_omp_invalid_device_num */ "offload error: device number should be a non-negative integer value",
/* 60 msg_c_unknown_binary_type */ "offload error: unexpected embedded target binary type, expected either an executable or shared library",
/* 61 msg_c_multiple_target_exes */ "offload error: more that one target executable found",
/* 62 msg_c_no_target_exe */ "offload error: target executable is not available",
/* 63 msg_c_report_unknown_timer_node */ "offload error: unknown timer node",
/* 64 msg_c_report_unknown_trace_node */ "offload error: unknown trace node",
/* 65 msg_c_report_host */ "HOST",
/* 66 msg_c_report_mic */ "MIC",
/* 67 msg_c_report_title */ "timer data (sec)",
/* 68 msg_c_report_seconds */ "(seconds)",
/* 69 msg_c_report_bytes */ "(bytes)",
/* 70 msg_c_report_cpu_time */ "CPU Time",
/* 71 msg_c_report_mic_time */ "MIC Time",
/* 72 msg_c_report_tag */ "Tag",
/* 73 msg_c_report_from_file */ "Offload from file",
/* 74 msg_c_report_file */ "File",
/* 75 msg_c_report_line */ "Line",
/* 76 msg_c_report_cpu_to_mic_data */ "CPU->MIC Data",
/* 77 msg_c_report_mic_to_cpu_data */ "MIC->CPU Data",
/* 78 msg_c_report_offload */ "Offload",
/* 79 msg_c_report_w_tag */ "Tag %d",
/* 80 msg_c_report_state */ "State",
/* 81 msg_c_report_start */ "Start target",
/* 82 msg_c_report_init */ "Initialize",
/* 83 msg_c_report_logical_card */ "logical card",
/* 84 msg_c_report_physical_card */ "physical card",
/* 85 msg_c_report_register */ "Register static data tables",
/* 86 msg_c_report_init_func */ "Setup target entry",
/* 87 msg_c_report_create_buf_host */ "Create host buffer",
/* 88 msg_c_report_create_buf_mic */ "Create target buffer",
/* 89 msg_c_report_send_pointer_data */ "Send pointer data",
/* 90 msg_c_report_sent_pointer_data */ "Host->target pointer data",
/* 91 msg_c_report_gather_copyin_data */ "Gather copyin data",
/* 92 msg_c_report_copyin_data */ "Host->target copyin data",
/* 93 msg_c_report_state_signal */ "Signal",
/* 94 msg_c_report_signal */ "signal :",
/* 95 msg_c_report_wait */ "waits :",
/* 96 msg_c_report_compute */ "Execute task on target",
/* 97 msg_c_report_receive_pointer_data */ "Receive pointer data",
/* 98 msg_c_report_received_pointer_data */ "Target->host pointer data",
/* 99 msg_c_report_start_target_func */ "Start target entry",
/* 100 msg_c_report_var */ "Var",
/* 101 msg_c_report_scatter_copyin_data */ "Scatter copyin data",
/* 102 msg_c_report_gather_copyout_data */ "Gather copyout data",
/* 103 msg_c_report_scatter_copyout_data */ "Scatter copyout data",
/* 104 msg_c_report_copyout_data */ "Target->host copyout data",
/* 105 msg_c_report_unregister */ "Unregister data tables",
/* 106 msg_c_report_destroy */ "Destroy",
/* 107 msg_c_report_myoinit */ "Initialize MYO",
/* 108 msg_c_report_myoregister */ "Register MYO tables",
/* 109 msg_c_report_myofini */ "Finalize MYO",
/* 110 msg_c_report_mic_myo_shared */ "MIC MYO shared table register",
/* 111 msg_c_report_mic_myo_fptr */ "MIC MYO fptr table register",
/* 112 msg_c_report_myosharedmalloc */ "MYO shared malloc",
/* 113 msg_c_report_myosharedfree */ "MYO shared free",
/* 114 msg_c_report_myosharedalignedmalloc */ "MYO shared aligned malloc",
/* 115 msg_c_report_myosharedalignedfree */ "MYO shared aligned free",
/* 116 msg_c_report_myoacquire */ "MYO acquire",
/* 117 msg_c_report_myorelease */ "MYO release",
/* 118 msg_c_report_host_total_offload_time */ "host: total offload time",
/* 119 msg_c_report_host_initialize */ "host: initialize target",
/* 120 msg_c_report_host_target_acquire */ "host: acquire target",
/* 121 msg_c_report_host_wait_deps */ "host: wait dependencies",
/* 122 msg_c_report_host_setup_buffers */ "host: setup buffers",
/* 123 msg_c_report_host_alloc_buffers */ "host: allocate buffers",
/* 124 msg_c_report_host_setup_misc_data */ "host: setup misc_data",
/* 125 msg_c_report_host_alloc_data_buffer */ "host: allocate buffer",
/* 126 msg_c_report_host_send_pointers */ "host: send pointers",
/* 127 msg_c_report_host_gather_inputs */ "host: gather inputs",
/* 128 msg_c_report_host_map_in_data_buffer */ "host: map IN data buffer",
/* 129 msg_c_report_host_unmap_in_data_buffer */ "host: unmap IN data buffer",
/* 130 msg_c_report_host_start_compute */ "host: initiate compute",
/* 131 msg_c_report_host_wait_compute */ "host: wait compute",
/* 132 msg_c_report_host_start_buffers_reads */ "host: initiate pointer reads",
/* 133 msg_c_report_host_scatter_outputs */ "host: scatter outputs",
/* 134 msg_c_report_host_map_out_data_buffer */ "host: map OUT data buffer",
/* 135 msg_c_report_host_unmap_out_data_buffer */ "host: unmap OUT data buffer",
/* 136 msg_c_report_host_wait_buffers_reads */ "host: wait pointer reads",
/* 137 msg_c_report_host_destroy_buffers */ "host: destroy buffers",
/* 138 msg_c_report_target_total_time */ "target: total time",
/* 139 msg_c_report_target_descriptor_setup */ "target: setup offload descriptor",
/* 140 msg_c_report_target_func_lookup */ "target: entry lookup",
/* 141 msg_c_report_target_func_time */ "target: entry time",
/* 142 msg_c_report_target_scatter_inputs */ "target: scatter inputs",
/* 143 msg_c_report_target_add_buffer_refs */ "target: add buffer reference",
/* 144 msg_c_report_target_compute */ "target: compute",
/* 145 msg_c_report_target_gather_outputs */ "target: gather outputs",
/* 146 msg_c_report_target_release_buffer_refs */ "target: remove buffer reference",
/* 147 msg_c_coi_pipeline_max_number */ "number of host threads doing offload exceeds maximum of %d",
/* 148 msg_c_ranges_dont_match */ "ranges of source and destination don't match together",
/* 149 msg_c_destination_is_over */ "insufficient destination memory to transfer source",
/* 150 msg_c_slice_of_noncont_array */ "a non-contiguous slice may be taken of contiguous arrays only",
/* 151 msg_c_pointer_array_mismatch */ "number of %s elements is less than described by the source",
};
+441
View File
@@ -0,0 +1,441 @@
!
!//===----------------------------------------------------------------------===//
!//
!// The LLVM Compiler Infrastructure
!//
!// This file is dual licensed under the MIT and the University of Illinois Open
!// Source Licenses. See LICENSE.txt for details.
!//
!//===----------------------------------------------------------------------===//
!
! **********************************************************************************
! * This file is intended to support the Intel(r) Many Integrated Core Architecture.
! **********************************************************************************
! free form Fortran source - should be named .f90
! lines are longer than 72 characters
module mic_lib
use, intrinsic :: iso_c_binding
integer, parameter:: target_mic=2
integer, parameter:: default_target_type=target_mic
integer, parameter:: default_target_number=0
enum, bind(C)
enumerator :: OFFLOAD_SUCCESS = 0
enumerator :: OFFLOAD_DISABLED ! offload is disabled
enumerator :: OFFLOAD_UNAVAILABLE ! card is not available
enumerator :: OFFLOAD_OUT_OF_MEMORY ! not enough memory on device
enumerator :: OFFLOAD_PROCESS_DIED ! target process has died
enumerator :: OFFLOAD_ERROR ! unspecified error
end enum
type, bind (C) :: offload_status
integer(kind=c_int) :: result = OFFLOAD_DISABLED
integer(kind=c_int) :: device_number = -1
integer(kind=c_size_t) :: data_sent = 0
integer(kind=c_size_t) :: data_received = 0
end type offload_status
interface
function offload_number_of_devices () &
bind (C, name = "_Offload_number_of_devices")
!dec$ attributes default :: offload_number_of_devices
import :: c_int
integer (kind=c_int) :: offload_number_of_devices
!dec$ attributes offload:mic :: offload_number_of_devices
!dir$ attributes known_intrinsic :: offload_number_of_devices
end function offload_number_of_devices
function offload_signaled(target_number, signal) &
bind (C, name = "_Offload_signaled")
!dec$ attributes default :: offload_signaled
import :: c_int, c_int64_t
integer (kind=c_int) :: offload_signaled
integer (kind=c_int), value :: target_number
integer (kind=c_int64_t), value :: signal
!dec$ attributes offload:mic :: offload_signaled
end function offload_signaled
subroutine offload_report(val) &
bind (C, name = "_Offload_report")
!dec$ attributes default :: offload_report
import :: c_int
integer (kind=c_int), value :: val
!dec$ attributes offload:mic :: offload_report
end subroutine offload_report
function offload_get_device_number() &
bind (C, name = "_Offload_get_device_number")
!dec$ attributes default :: offload_get_device_number
import :: c_int
integer (kind=c_int) :: offload_get_device_number
!dec$ attributes offload:mic :: offload_get_device_number
end function offload_get_device_number
function offload_get_physical_device_number() &
bind (C, name = "_Offload_get_physical_device_number")
!dec$ attributes default :: offload_get_physical_device_number
import :: c_int
integer (kind=c_int) :: offload_get_physical_device_number
!dec$ attributes offload:mic :: offload_get_physical_device_number
end function offload_get_physical_device_number
! OpenMP API wrappers
subroutine omp_set_num_threads_target (target_type, &
target_number, &
num_threads) &
bind (C, name = "omp_set_num_threads_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, num_threads
end subroutine omp_set_num_threads_target
function omp_get_max_threads_target (target_type, &
target_number) &
bind (C, name = "omp_get_max_threads_target")
import :: c_int
integer (kind=c_int) :: omp_get_max_threads_target
integer (kind=c_int), value :: target_type, target_number
end function omp_get_max_threads_target
function omp_get_num_procs_target (target_type, &
target_number) &
bind (C, name = "omp_get_num_procs_target")
import :: c_int
integer (kind=c_int) :: omp_get_num_procs_target
integer (kind=c_int), value :: target_type, target_number
end function omp_get_num_procs_target
subroutine omp_set_dynamic_target (target_type, &
target_number, &
num_threads) &
bind (C, name = "omp_set_dynamic_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, num_threads
end subroutine omp_set_dynamic_target
function omp_get_dynamic_target (target_type, &
target_number) &
bind (C, name = "omp_get_dynamic_target")
import :: c_int
integer (kind=c_int) :: omp_get_dynamic_target
integer (kind=c_int), value :: target_type, target_number
end function omp_get_dynamic_target
subroutine omp_set_nested_target (target_type, &
target_number, &
nested) &
bind (C, name = "omp_set_nested_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, nested
end subroutine omp_set_nested_target
function omp_get_nested_target (target_type, &
target_number) &
bind (C, name = "omp_get_nested_target")
import :: c_int
integer (kind=c_int) :: omp_get_nested_target
integer (kind=c_int), value :: target_type, target_number
end function omp_get_nested_target
subroutine omp_set_schedule_target (target_type, &
target_number, &
kind, &
modifier) &
bind (C, name = "omp_set_schedule_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, kind, modifier
end subroutine omp_set_schedule_target
subroutine omp_get_schedule_target (target_type, &
target_number, &
kind, &
modifier) &
bind (C, name = "omp_get_schedule_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: kind, modifier
end subroutine omp_get_schedule_target
! lock API functions
subroutine omp_init_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_init_lock_target")
import :: c_int, c_intptr_t
!dir$ attributes known_intrinsic :: omp_init_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_init_lock_target
subroutine omp_destroy_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_destroy_lock_target")
import :: c_int, c_intptr_t
!dir$ attributes known_intrinsic :: omp_destroy_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_destroy_lock_target
subroutine omp_set_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_set_lock_target")
import :: c_int, c_intptr_t
!dir$ attributes known_intrinsic :: omp_set_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_set_lock_target
subroutine omp_unset_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_unset_lock_target")
import :: c_int, c_intptr_t
!dir$ attributes known_intrinsic :: omp_unset_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_unset_lock_target
function omp_test_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_test_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: omp_test_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end function omp_test_lock_target
! nested lock API functions
subroutine omp_init_nest_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_init_nest_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_init_nest_lock_target
subroutine omp_destroy_nest_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_destroy_nest_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_destroy_nest_lock_target
subroutine omp_set_nest_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_set_nest_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_set_nest_lock_target
subroutine omp_unset_nest_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_unset_nest_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end subroutine omp_unset_nest_lock_target
function omp_test_nest_lock_target (target_type, &
target_number, &
lock) &
bind (C, name = "omp_test_nest_lock_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: omp_test_nest_lock_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: lock
end function omp_test_nest_lock_target
! kmp API functions
subroutine kmp_set_stacksize_target (target_type, &
target_number, &
size) &
bind (C, name = "kmp_set_stacksize_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, size
end subroutine kmp_set_stacksize_target
function kmp_get_stacksize_target (target_type, &
target_number) &
bind (C, name = "kmp_get_stacksize_target")
import :: c_int
integer (kind=c_int) :: kmp_get_stacksize_target
integer (kind=c_int), value :: target_type, target_number
end function kmp_get_stacksize_target
subroutine kmp_set_stacksize_s_target (target_type, &
target_number, &
size) &
bind (C, name = "kmp_set_stacksize_s_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, size
end subroutine kmp_set_stacksize_s_target
function kmp_get_stacksize_s_target (target_type, &
target_number) &
bind (C, name = "kmp_get_stacksize_s_target")
import :: c_int
integer (kind=c_int) :: kmp_get_stacksize_s_target
integer (kind=c_int), value :: target_type, target_number
end function kmp_get_stacksize_s_target
subroutine kmp_set_blocktime_target (target_type, &
target_number, &
time) &
bind (C, name = "kmp_set_blocktime_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, time
end subroutine kmp_set_blocktime_target
function kmp_get_blocktime_target (target_type, &
target_number) &
bind (C, name = "kmp_get_blocktime_target")
import :: c_int
integer (kind=c_int) :: kmp_get_blocktime_target
integer (kind=c_int), value :: target_type, target_number
end function kmp_get_blocktime_target
subroutine kmp_set_library_serial_target (target_type, &
target_number) &
bind (C, name = "kmp_set_library_serial_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number
end subroutine kmp_set_library_serial_target
subroutine kmp_set_library_turnaround_target (target_type, &
target_number) &
bind (C, name = "kmp_set_library_turnaround_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number
end subroutine kmp_set_library_turnaround_target
subroutine kmp_set_library_throughput_target (target_type, &
target_number) &
bind (C, name = "kmp_set_library_throughput_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number
end subroutine kmp_set_library_throughput_target
subroutine kmp_set_library_target (target_type, &
target_number, &
mode) &
bind (C, name = "kmp_set_library_target")
import :: c_int
integer (kind=c_int), value :: target_type, target_number, mode
end subroutine kmp_set_library_target
function kmp_get_library_target (target_type, &
target_number) &
bind (C, name = "kmp_get_library_target")
import :: c_int
integer (kind=c_int) :: kmp_get_library_target
integer (kind=c_int), value :: target_type, target_number
end function kmp_get_library_target
subroutine kmp_set_defaults_target (target_type, &
target_number, &
defaults) &
bind (C, name = "kmp_set_defaults_target")
import :: c_int, c_char
character (kind=c_char) :: defaults(*)
integer (kind=c_int), value :: target_type, target_number
end subroutine kmp_set_defaults_target
! affinity API functions
subroutine kmp_create_affinity_mask_target (target_type, &
target_number, &
mask) &
bind (C, name = "kmp_create_affinity_mask_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: mask
end subroutine kmp_create_affinity_mask_target
subroutine kmp_destroy_affinity_mask_target (target_type, &
target_number, &
mask) &
bind (C, name = "kmp_destroy_affinity_mask_target")
import :: c_int, c_intptr_t
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: mask
end subroutine kmp_destroy_affinity_mask_target
function kmp_set_affinity_target (target_type, &
target_number, &
mask) &
bind (C, name = "kmp_set_affinity_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: kmp_set_affinity_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: mask
end function kmp_set_affinity_target
function kmp_get_affinity_target (target_type, &
target_number, &
mask) &
bind (C, name = "kmp_get_affinity_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: kmp_get_affinity_target
integer (kind=c_int), value :: target_type, target_number
integer (kind=c_intptr_t), value :: mask
end function kmp_get_affinity_target
function kmp_get_affinity_max_proc_target (target_type, &
target_number) &
bind (C, name = "kmp_get_affinity_max_proc_target")
import :: c_int
integer (kind=c_int) :: kmp_get_affinity_max_proc_target
integer (kind=c_int), value :: target_type, target_number
end function kmp_get_affinity_max_proc_target
function kmp_set_affinity_mask_proc_target (target_type, &
target_number, &
proc, &
mask) &
bind (C, name = "kmp_set_affinity_mask_proc_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: kmp_set_affinity_mask_proc_target
integer (kind=c_int), value :: target_type, target_number, proc
integer (kind=c_intptr_t), value :: mask
end function kmp_set_affinity_mask_proc_target
function kmp_unset_affinity_mask_proc_target (target_type, &
target_number, &
proc, &
mask) &
bind (C, name = "kmp_unset_affinity_mask_proc_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: kmp_unset_affinity_mask_proc_target
integer (kind=c_int), value :: target_type, target_number, proc
integer (kind=c_intptr_t), value :: mask
end function kmp_unset_affinity_mask_proc_target
function kmp_get_affinity_mask_proc_target (target_type, &
target_number, &
proc, &
mask) &
bind (C, name = "kmp_get_affinity_mask_proc_target")
import :: c_int, c_intptr_t
integer (kind=c_int) :: kmp_get_affinity_mask_proc_target
integer (kind=c_int), value :: target_type, target_number, proc
integer (kind=c_intptr_t), value :: mask
end function kmp_get_affinity_mask_proc_target
end interface
end module mic_lib
+474
View File
@@ -0,0 +1,474 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*
* Include file for Offload API.
*/
#ifndef OFFLOAD_H_INCLUDED
#define OFFLOAD_H_INCLUDED
#if defined(LINUX) || defined(FREEBSD)
#include <bits/functexcept.h>
#endif
#include <stddef.h>
#include <omp.h>
#ifdef __cplusplus
extern "C" {
#endif
#define TARGET_ATTRIBUTE __declspec(target(mic))
/*
* The target architecture.
*/
typedef enum TARGET_TYPE {
TARGET_NONE, /* Undefine target */
TARGET_HOST, /* Host used as target */
TARGET_MIC /* MIC target */
} TARGET_TYPE;
/*
* The default target type.
*/
#define DEFAULT_TARGET_TYPE TARGET_MIC
/*
* The default target number.
*/
#define DEFAULT_TARGET_NUMBER 0
/*
* Offload status.
*/
typedef enum {
OFFLOAD_SUCCESS = 0,
OFFLOAD_DISABLED, /* offload is disabled */
OFFLOAD_UNAVAILABLE, /* card is not available */
OFFLOAD_OUT_OF_MEMORY, /* not enough memory on device */
OFFLOAD_PROCESS_DIED, /* target process has died */
OFFLOAD_ERROR /* unspecified error */
} _Offload_result;
typedef struct {
_Offload_result result; /* result, see above */
int device_number; /* device number */
size_t data_sent; /* number of bytes sent to the target */
size_t data_received; /* number of bytes received by host */
} _Offload_status;
#define OFFLOAD_STATUS_INIT(x) \
((x).result = OFFLOAD_DISABLED)
#define OFFLOAD_STATUS_INITIALIZER \
{ OFFLOAD_DISABLED, -1, 0, 0 }
/* Offload runtime interfaces */
extern int _Offload_number_of_devices(void);
extern int _Offload_get_device_number(void);
extern int _Offload_get_physical_device_number(void);
extern void* _Offload_shared_malloc(size_t size);
extern void _Offload_shared_free(void *ptr);
extern void* _Offload_shared_aligned_malloc(size_t size, size_t align);
extern void _Offload_shared_aligned_free(void *ptr);
extern int _Offload_signaled(int index, void *signal);
extern void _Offload_report(int val);
/* OpenMP API */
extern void omp_set_default_device(int num);
extern int omp_get_default_device(void);
extern int omp_get_num_devices(void);
/* OpenMP API wrappers */
/* Set num_threads on target */
extern void omp_set_num_threads_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
);
/* Get max_threads from target */
extern int omp_get_max_threads_target(
TARGET_TYPE target_type,
int target_number
);
/* Get num_procs from target */
extern int omp_get_num_procs_target(
TARGET_TYPE target_type,
int target_number
);
/* Set dynamic on target */
extern void omp_set_dynamic_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
);
/* Get dynamic from target */
extern int omp_get_dynamic_target(
TARGET_TYPE target_type,
int target_number
);
/* Set nested on target */
extern void omp_set_nested_target(
TARGET_TYPE target_type,
int target_number,
int nested
);
/* Get nested from target */
extern int omp_get_nested_target(
TARGET_TYPE target_type,
int target_number
);
extern void omp_set_num_threads_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
);
extern int omp_get_max_threads_target(
TARGET_TYPE target_type,
int target_number
);
extern int omp_get_num_procs_target(
TARGET_TYPE target_type,
int target_number
);
extern void omp_set_dynamic_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
);
extern int omp_get_dynamic_target(
TARGET_TYPE target_type,
int target_number
);
extern void omp_set_nested_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
);
extern int omp_get_nested_target(
TARGET_TYPE target_type,
int target_number
);
extern void omp_set_schedule_target(
TARGET_TYPE target_type,
int target_number,
omp_sched_t kind,
int modifier
);
extern void omp_get_schedule_target(
TARGET_TYPE target_type,
int target_number,
omp_sched_t *kind,
int *modifier
);
/* lock API functions */
typedef struct {
omp_lock_t lock;
} omp_lock_target_t;
extern void omp_init_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
);
extern void omp_destroy_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
);
extern void omp_set_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
);
extern void omp_unset_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
);
extern int omp_test_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
);
/* nested lock API functions */
typedef struct {
omp_nest_lock_t lock;
} omp_nest_lock_target_t;
extern void omp_init_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
);
extern void omp_destroy_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
);
extern void omp_set_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
);
extern void omp_unset_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
);
extern int omp_test_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
);
/* kmp API functions */
extern void kmp_set_stacksize_target(
TARGET_TYPE target_type,
int target_number,
int size
);
extern int kmp_get_stacksize_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_stacksize_s_target(
TARGET_TYPE target_type,
int target_number,
size_t size
);
extern size_t kmp_get_stacksize_s_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_blocktime_target(
TARGET_TYPE target_type,
int target_number,
int time
);
extern int kmp_get_blocktime_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_library_serial_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_library_turnaround_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_library_throughput_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_library_target(
TARGET_TYPE target_type,
int target_number,
int mode
);
extern int kmp_get_library_target(
TARGET_TYPE target_type,
int target_number
);
extern void kmp_set_defaults_target(
TARGET_TYPE target_type,
int target_number,
char const *defaults
);
/* affinity API functions */
typedef struct {
kmp_affinity_mask_t mask;
} kmp_affinity_mask_target_t;
extern void kmp_create_affinity_mask_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
);
extern void kmp_destroy_affinity_mask_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
);
extern int kmp_set_affinity_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
);
extern int kmp_get_affinity_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
);
extern int kmp_get_affinity_max_proc_target(
TARGET_TYPE target_type,
int target_number
);
extern int kmp_set_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
);
extern int kmp_unset_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
);
extern int kmp_get_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
);
#ifdef __cplusplus
} /* extern "C" */
/* Namespace for the shared_allocator. */
namespace __offload {
/* This follows the specification for std::allocator. */
/* Forward declaration of the class template. */
template <typename T>
class shared_allocator;
/* Specialization for shared_allocator<void>. */
template <>
class shared_allocator<void> {
public:
typedef void *pointer;
typedef const void *const_pointer;
typedef void value_type;
template <class U> struct rebind { typedef shared_allocator<U> other; };
};
/* Definition of shared_allocator<T>. */
template <class T>
class shared_allocator {
public:
typedef size_t size_type;
typedef ptrdiff_t difference_type;
typedef T *pointer;
typedef const T *const_pointer;
typedef T &reference;
typedef const T &const_reference;
typedef T value_type;
template <class U> struct rebind { typedef shared_allocator<U> other; };
shared_allocator() throw() { }
shared_allocator(const shared_allocator&) throw() { }
template <class U> shared_allocator(const shared_allocator<U>&) throw() { }
~shared_allocator() throw() { }
pointer address(reference x) const { return &x; }
const_pointer address(const_reference x) const { return &x; }
pointer allocate(
size_type, shared_allocator<void>::const_pointer hint = 0);
void deallocate(pointer p, size_type n);
size_type max_size() const throw() {
return size_type(-1)/sizeof(T);
} /* max_size */
void construct(pointer p, const T& arg) {
::new (p) T(arg);
} /* construct */
void destroy(pointer p) {
p->~T();
} /* destroy */
};
/* Definition for allocate. */
template <class T>
typename shared_allocator<T>::pointer
shared_allocator<T>::allocate(shared_allocator<T>::size_type s,
shared_allocator<void>::const_pointer) {
/* Allocate from shared memory. */
void *ptr = _Offload_shared_malloc(s*sizeof(T));
if (ptr == 0) std::__throw_bad_alloc();
return static_cast<pointer>(ptr);
} /* allocate */
template <class T>
void shared_allocator<T>::deallocate(pointer p,
shared_allocator<T>::size_type) {
/* Free the shared memory. */
_Offload_shared_free(p);
} /* deallocate */
template <typename _T1, typename _T2>
inline bool operator==(const shared_allocator<_T1> &,
const shared_allocator<_T2> &) throw() {
return true;
} /* operator== */
template <typename _T1, typename _T2>
inline bool operator!=(const shared_allocator<_T1> &,
const shared_allocator<_T2> &) throw() {
return false;
} /* operator!= */
} /* __offload */
#endif /* __cplusplus */
#endif /* OFFLOAD_H_INCLUDED */
+170
View File
@@ -0,0 +1,170 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#if defined(LINUX) || defined(FREEBSD)
#include <mm_malloc.h>
#endif
#include "offload_common.h"
// The debug routines
#if OFFLOAD_DEBUG > 0
void __dump_bytes(
int trace_level,
const void *data,
int len
)
{
if (console_enabled > trace_level) {
const uint8_t *arr = (const uint8_t*) data;
char buffer[4096];
char *bufferp;
int count = 0;
bufferp = buffer;
while (len--) {
sprintf(bufferp, "%02x", *arr++);
bufferp += 2;
count++;
if ((count&3) == 0) {
sprintf(bufferp, " ");
bufferp++;
}
if ((count&63) == 0) {
OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer);
bufferp = buffer;
count = 0;
}
}
if (count) {
OFFLOAD_DEBUG_TRACE(trace_level, "%s\n", buffer);
}
}
}
#endif // OFFLOAD_DEBUG
// The Marshaller and associated routines
void Marshaller::send_data(
const void *data,
int64_t length
)
{
OFFLOAD_DEBUG_TRACE(2, "send_data(%p, %lld)\n",
data, length);
memcpy(buffer_ptr, data, (size_t)length);
buffer_ptr += length;
tfr_size += length;
}
void Marshaller::receive_data(
void *data,
int64_t length
)
{
OFFLOAD_DEBUG_TRACE(2, "receive_data(%p, %lld)\n",
data, length);
memcpy(data, buffer_ptr, (size_t)length);
buffer_ptr += length;
tfr_size += length;
}
// Send function pointer
void Marshaller::send_func_ptr(
const void* data
)
{
const char* name;
size_t length;
if (data != 0) {
name = __offload_funcs.find_name(data);
if (name == 0) {
#if OFFLOAD_DEBUG > 0
if (console_enabled > 2) {
__offload_funcs.dump();
}
#endif // OFFLOAD_DEBUG > 0
LIBOFFLOAD_ERROR(c_send_func_ptr, data);
exit(1);
}
length = strlen(name) + 1;
}
else {
name = "";
length = 1;
}
memcpy(buffer_ptr, name, length);
buffer_ptr += length;
tfr_size += length;
}
// Receive function pointer
void Marshaller::receive_func_ptr(
const void** data
)
{
const char* name;
size_t length;
name = (const char*) buffer_ptr;
if (name[0] != '\0') {
*data = __offload_funcs.find_addr(name);
if (*data == 0) {
#if OFFLOAD_DEBUG > 0
if (console_enabled > 2) {
__offload_funcs.dump();
}
#endif // OFFLOAD_DEBUG > 0
LIBOFFLOAD_ERROR(c_receive_func_ptr, name);
exit(1);
}
length = strlen(name) + 1;
}
else {
*data = 0;
length = 1;
}
buffer_ptr += length;
tfr_size += length;
}
// End of the Marshaller and associated routines
extern void *OFFLOAD_MALLOC(
size_t size,
size_t align
)
{
void *ptr;
int err;
OFFLOAD_DEBUG_TRACE(2, "%s(%lld, %lld)\n", __func__, size, align);
if (align < sizeof(void*)) {
align = sizeof(void*);
}
ptr = _mm_malloc(size, align);
if (ptr == NULL) {
LIBOFFLOAD_ERROR(c_offload_malloc, size, align);
exit(1);
}
OFFLOAD_DEBUG_TRACE(2, "%s returned %p\n", __func__, ptr);
return ptr;
}
+444
View File
@@ -0,0 +1,444 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*! \file
\brief The parts of the runtime library common to host and target
*/
#ifndef OFFLOAD_COMMON_H_INCLUDED
#define OFFLOAD_COMMON_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <memory.h>
#include "offload.h"
#include "offload_table.h"
#include "offload_trace.h"
#include "offload_timer.h"
#include "offload_util.h"
#include "cean_util.h"
#include "dv_util.h"
#include "liboffload_error_codes.h"
#include <stdarg.h>
// The debug routines
// Host console and file logging
extern int console_enabled;
extern int offload_report_level;
#define OFFLOAD_DO_TRACE (offload_report_level == 3)
extern const char *prefix;
extern int offload_number;
#if !HOST_LIBRARY
extern int mic_index;
#endif
#if HOST_LIBRARY
void Offload_Report_Prolog(OffloadHostTimerData* timer_data);
void Offload_Report_Epilog(OffloadHostTimerData* timer_data);
void offload_report_free_data(OffloadHostTimerData * timer_data);
void Offload_Timer_Print(void);
#ifndef TARGET_WINNT
#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
__sync_add_and_fetch(&offload_number, 1)
#else
#define OFFLOAD_DEBUG_INCR_OFLD_NUM() \
_InterlockedIncrement(reinterpret_cast<long*>(&offload_number))
#endif
#define OFFLOAD_DEBUG_PRINT_TAG_PREFIX() \
printf("%s: ", prefix);
#define OFFLOAD_DEBUG_PRINT_PREFIX() \
printf("%s: ", prefix);
#else
#define OFFLOAD_DEBUG_PRINT_PREFIX() \
printf("%s%d: ", prefix, mic_index);
#endif // HOST_LIBRARY
#define OFFLOAD_TRACE(trace_level, ...) \
if (console_enabled >= trace_level) { \
OFFLOAD_DEBUG_PRINT_PREFIX(); \
printf(__VA_ARGS__); \
fflush(NULL); \
}
#if OFFLOAD_DEBUG > 0
#define OFFLOAD_DEBUG_TRACE(level, ...) \
OFFLOAD_TRACE(level, __VA_ARGS__)
#define OFFLOAD_REPORT(level, offload_number, stage, ...) \
if (OFFLOAD_DO_TRACE) { \
offload_stage_print(stage, offload_number, __VA_ARGS__); \
fflush(NULL); \
}
#define OFFLOAD_DEBUG_TRACE_1(level, offload_number, stage, ...) \
if (OFFLOAD_DO_TRACE) { \
offload_stage_print(stage, offload_number, __VA_ARGS__); \
fflush(NULL); \
} \
if (!OFFLOAD_DO_TRACE) { \
OFFLOAD_TRACE(level, __VA_ARGS__) \
}
#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b) \
__dump_bytes(level, a, b)
extern void __dump_bytes(
int level,
const void *data,
int len
);
#else
#define OFFLOAD_DEBUG_LOG(level, ...)
#define OFFLOAD_DEBUG_DUMP_BYTES(level, a, b)
#endif
// Runtime interface
#define OFFLOAD_PREFIX(a) __offload_##a
#define OFFLOAD_MALLOC OFFLOAD_PREFIX(malloc)
#define OFFLOAD_FREE(a) _mm_free(a)
// Forward functions
extern void *OFFLOAD_MALLOC(size_t size, size_t align);
// The Marshaller
//! \enum Indicator for the type of entry on an offload item list.
enum OffloadItemType {
c_data = 1, //!< Plain data
c_data_ptr, //!< Pointer data
c_func_ptr, //!< Function pointer
c_void_ptr, //!< void*
c_string_ptr, //!< C string
c_dv, //!< Dope vector variable
c_dv_data, //!< Dope-vector data
c_dv_data_slice, //!< Dope-vector data's slice
c_dv_ptr, //!< Dope-vector variable pointer
c_dv_ptr_data, //!< Dope-vector pointer data
c_dv_ptr_data_slice,//!< Dope-vector pointer data's slice
c_cean_var, //!< CEAN variable
c_cean_var_ptr, //!< Pointer to CEAN variable
c_data_ptr_array, //!< Pointer to data pointer array
c_func_ptr_array, //!< Pointer to function pointer array
c_void_ptr_array, //!< Pointer to void* pointer array
c_string_ptr_array //!< Pointer to char* pointer array
};
#define VAR_TYPE_IS_PTR(t) ((t) == c_string_ptr || \
(t) == c_data_ptr || \
(t) == c_cean_var_ptr || \
(t) == c_dv_ptr)
#define VAR_TYPE_IS_SCALAR(t) ((t) == c_data || \
(t) == c_void_ptr || \
(t) == c_cean_var || \
(t) == c_dv)
#define VAR_TYPE_IS_DV_DATA(t) ((t) == c_dv_data || \
(t) == c_dv_ptr_data)
#define VAR_TYPE_IS_DV_DATA_SLICE(t) ((t) == c_dv_data_slice || \
(t) == c_dv_ptr_data_slice)
//! \enum Specify direction to copy offloaded variable.
enum OffloadParameterType {
c_parameter_unknown = -1, //!< Unknown clause
c_parameter_nocopy, //!< Variable listed in "nocopy" clause
c_parameter_in, //!< Variable listed in "in" clause
c_parameter_out, //!< Variable listed in "out" clause
c_parameter_inout //!< Variable listed in "inout" clause
};
//! An Offload Variable descriptor
struct VarDesc {
//! OffloadItemTypes of source and destination
union {
struct {
uint8_t dst : 4; //!< OffloadItemType of destination
uint8_t src : 4; //!< OffloadItemType of source
};
uint8_t bits;
} type;
//! OffloadParameterType that describes direction of data transfer
union {
struct {
uint8_t in : 1; //!< Set if IN or INOUT
uint8_t out : 1; //!< Set if OUT or INOUT
};
uint8_t bits;
} direction;
uint8_t alloc_if; //!< alloc_if modifier value
uint8_t free_if; //!< free_if modifier value
uint32_t align; //!< MIC alignment requested for pointer data
//! Not used by compiler; set to 0
/*! Used by runtime as offset to data from start of MIC buffer */
uint32_t mic_offset;
//! Flags describing this variable
union {
struct {
//! source variable has persistent storage
uint32_t is_static : 1;
//! destination variable has persistent storage
uint32_t is_static_dstn : 1;
//! has length for c_dv && c_dv_ptr
uint32_t has_length : 1;
//! persisted local scalar is in stack buffer
uint32_t is_stack_buf : 1;
//! buffer address is sent in data
uint32_t sink_addr : 1;
//! alloc displacement is sent in data
uint32_t alloc_disp : 1;
//! source data is noncontiguous
uint32_t is_noncont_src : 1;
//! destination data is noncontiguous
uint32_t is_noncont_dst : 1;
};
uint32_t bits;
} flags;
//! Not used by compiler; set to 0
/*! Used by runtime as offset to base from data stored in a buffer */
int64_t offset;
//! Element byte-size of data to be transferred
/*! For dope-vector, the size of the dope-vector */
int64_t size;
union {
//! Set to 0 for array expressions and dope-vectors
/*! Set to 1 for scalars */
/*! Set to value of length modifier for pointers */
int64_t count;
//! Displacement not used by compiler
int64_t disp;
};
//! This field not used by OpenMP 4.0
/*! The alloc section expression in #pragma offload */
union {
void *alloc;
int64_t ptr_arr_offset;
};
//! This field not used by OpenMP 4.0
/*! The into section expression in #pragma offload */
/*! For c_data_ptr_array this is the into ptr array */
void *into;
//! For an ordinary variable, address of the variable
/*! For c_cean_var (C/C++ array expression),
pointer to arr_desc, which is an array descriptor. */
/*! For c_data_ptr_array (array of data pointers),
pointer to ptr_array_descriptor,
which is a descriptor for pointer array transfers. */
void *ptr;
};
//! Auxiliary struct used when -g is enabled that holds variable names
struct VarDesc2 {
const char *sname; //!< Source name
const char *dname; //!< Destination name (when "into" is used)
};
/*! When the OffloadItemType is c_data_ptr_array
the ptr field of the main descriptor points to this struct. */
/*! The type in VarDesc1 merely says c_cean_data_ptr, but the pointer
type can be c_data_ptr, c_func_ptr, c_void_ptr, or c_string_ptr.
Therefore the actual pointer type is in the flags field of VarDesc3. */
/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
is 0 then alignment/alloc_if/free_if are specified in VarDesc1. */
/*! If flag_align_is_array/flag_alloc_if_is_array/flag_free_if_is_array
is 1 then align_array/alloc_if_array/free_if_array specify
the set of alignment/alloc_if/free_if values. */
/*! For the other fields, if neither the scalar nor the array flag
is set, then that modifier was not specified. If the bits are set
they specify which modifier was set and whether it was a
scalar or an array expression. */
struct VarDesc3
{
void *ptr_array; //!< Pointer to arr_desc of array of pointers
void *align_array; //!< Scalar value or pointer to arr_desc
void *alloc_if_array; //!< Scalar value or pointer to arr_desc
void *free_if_array; //!< Scalar value or pointer to arr_desc
void *extent_start; //!< Scalar value or pointer to arr_desc
void *extent_elements; //!< Scalar value or pointer to arr_desc
void *into_start; //!< Scalar value or pointer to arr_desc
void *into_elements; //!< Scalar value or pointer to arr_desc
void *alloc_start; //!< Scalar value or pointer to arr_desc
void *alloc_elements; //!< Scalar value or pointer to arr_desc
/*! Flags that describe the pointer type and whether each field
is a scalar value or an array expression. */
/*! First 6 bits are pointer array element type:
c_data_ptr, c_func_ptr, c_void_ptr, c_string_ptr */
/*! Then single bits specify: */
/*! align_array is an array */
/*! alloc_if_array is an array */
/*! free_if_array is an array */
/*! extent_start is a scalar expression */
/*! extent_start is an array expression */
/*! extent_elements is a scalar expression */
/*! extent_elements is an array expression */
/*! into_start is a scalar expression */
/*! into_start is an array expression */
/*! into_elements is a scalar expression */
/*! into_elements is an array expression */
/*! alloc_start is a scalar expression */
/*! alloc_start is an array expression */
/*! alloc_elements is a scalar expression */
/*! alloc_elements is an array expression */
uint32_t array_fields;
};
const int flag_align_is_array = 6;
const int flag_alloc_if_is_array = 7;
const int flag_free_if_is_array = 8;
const int flag_extent_start_is_scalar = 9;
const int flag_extent_start_is_array = 10;
const int flag_extent_elements_is_scalar = 11;
const int flag_extent_elements_is_array = 12;
const int flag_into_start_is_scalar = 13;
const int flag_into_start_is_array = 14;
const int flag_into_elements_is_scalar = 15;
const int flag_into_elements_is_array = 16;
const int flag_alloc_start_is_scalar = 17;
const int flag_alloc_start_is_array = 18;
const int flag_alloc_elements_is_scalar = 19;
const int flag_alloc_elements_is_array = 20;
// The Marshaller
class Marshaller
{
private:
// Start address of buffer
char *buffer_start;
// Current pointer within buffer
char *buffer_ptr;
// Physical size of data sent (including flags)
long long buffer_size;
// User data sent/received
long long tfr_size;
public:
// Constructor
Marshaller() :
buffer_start(0), buffer_ptr(0),
buffer_size(0), tfr_size(0)
{
}
// Return count of user data sent/received
long long get_tfr_size() const
{
return tfr_size;
}
// Return pointer to buffer
char *get_buffer_start() const
{
return buffer_start;
}
// Return current size of data in buffer
long long get_buffer_size() const
{
return buffer_size;
}
// Set buffer pointer
void init_buffer(
char *d,
long long s
)
{
buffer_start = buffer_ptr = d;
buffer_size = s;
}
// Send data
void send_data(
const void *data,
int64_t length
);
// Receive data
void receive_data(
void *data,
int64_t length
);
// Send function pointer
void send_func_ptr(
const void* data
);
// Receive function pointer
void receive_func_ptr(
const void** data
);
};
// End of the Marshaller
// The offloaded function descriptor.
// Sent from host to target to specify which function to run.
// Also, sets console and file tracing levels.
struct FunctionDescriptor
{
// Input data size.
long long in_datalen;
// Output data size.
long long out_datalen;
// Whether trace is requested on console.
// A value of 1 produces only function name and data sent/received.
// Values > 1 produce copious trace information.
uint8_t console_enabled;
// Flag controlling timing on the target side.
// Values > 0 enable timing on sink.
uint8_t timer_enabled;
int offload_report_level;
int offload_number;
// number of variable descriptors
int vars_num;
// inout data offset if data is passed as misc/return data
// otherwise it should be zero.
int data_offset;
// The name of the offloaded function
char data[];
};
// typedef OFFLOAD.
// Pointer to OffloadDescriptor.
typedef struct OffloadDescriptor *OFFLOAD;
#endif // OFFLOAD_COMMON_H_INCLUDED
+531
View File
@@ -0,0 +1,531 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_engine.h"
#include <signal.h>
#include <errno.h>
#include <algorithm>
#include <vector>
#include "offload_host.h"
#include "offload_table.h"
const char* Engine::m_func_names[Engine::c_funcs_total] =
{
"server_compute",
#ifdef MYO_SUPPORT
"server_myoinit",
"server_myofini",
#endif // MYO_SUPPORT
"server_init",
"server_var_table_size",
"server_var_table_copy"
};
// Symbolic representation of system signals. Fix for CQ233593
const char* Engine::c_signal_names[Engine::c_signal_max] =
{
"Unknown SIGNAL",
"SIGHUP", /* 1, Hangup (POSIX). */
"SIGINT", /* 2, Interrupt (ANSI). */
"SIGQUIT", /* 3, Quit (POSIX). */
"SIGILL", /* 4, Illegal instruction (ANSI). */
"SIGTRAP", /* 5, Trace trap (POSIX). */
"SIGABRT", /* 6, Abort (ANSI). */
"SIGBUS", /* 7, BUS error (4.2 BSD). */
"SIGFPE", /* 8, Floating-point exception (ANSI). */
"SIGKILL", /* 9, Kill, unblockable (POSIX). */
"SIGUSR1", /* 10, User-defined signal 1 (POSIX). */
"SIGSEGV", /* 11, Segmentation violation (ANSI). */
"SIGUSR2", /* 12, User-defined signal 2 (POSIX). */
"SIGPIPE", /* 13, Broken pipe (POSIX). */
"SIGALRM", /* 14, Alarm clock (POSIX). */
"SIGTERM", /* 15, Termination (ANSI). */
"SIGSTKFLT", /* 16, Stack fault. */
"SIGCHLD", /* 17, Child status has changed (POSIX). */
"SIGCONT", /* 18, Continue (POSIX). */
"SIGSTOP", /* 19, Stop, unblockable (POSIX). */
"SIGTSTP", /* 20, Keyboard stop (POSIX). */
"SIGTTIN", /* 21, Background read from tty (POSIX). */
"SIGTTOU", /* 22, Background write to tty (POSIX). */
"SIGURG", /* 23, Urgent condition on socket (4.2 BSD). */
"SIGXCPU", /* 24, CPU limit exceeded (4.2 BSD). */
"SIGXFSZ", /* 25, File size limit exceeded (4.2 BSD). */
"SIGVTALRM", /* 26, Virtual alarm clock (4.2 BSD). */
"SIGPROF", /* 27, Profiling alarm clock (4.2 BSD). */
"SIGWINCH", /* 28, Window size change (4.3 BSD, Sun). */
"SIGIO", /* 29, I/O now possible (4.2 BSD). */
"SIGPWR", /* 30, Power failure restart (System V). */
"SIGSYS" /* 31, Bad system call. */
};
void Engine::init(void)
{
if (!m_ready) {
mutex_locker_t locker(m_lock);
if (!m_ready) {
// start process if not done yet
if (m_process == 0) {
init_process();
}
// load penging images
load_libraries();
// and (re)build pointer table
init_ptr_data();
// it is ready now
m_ready = true;
}
}
}
void Engine::init_process(void)
{
COIENGINE engine;
COIRESULT res;
const char **environ;
// create environment for the target process
environ = (const char**) mic_env_vars.create_environ_for_card(m_index);
if (environ != 0) {
for (const char **p = environ; *p != 0; p++) {
OFFLOAD_DEBUG_TRACE(3, "Env Var for card %d: %s\n", m_index, *p);
}
}
// Create execution context in the specified device
OFFLOAD_DEBUG_TRACE(2, "Getting device %d (engine %d) handle\n", m_index,
m_physical_index);
res = COI::EngineGetHandle(COI_ISA_KNC, m_physical_index, &engine);
check_result(res, c_get_engine_handle, m_index, res);
// Target executable should be available by the time when we
// attempt to initialize the device
if (__target_exe == 0) {
LIBOFFLOAD_ERROR(c_no_target_exe);
exit(1);
}
OFFLOAD_DEBUG_TRACE(2,
"Loading target executable \"%s\" from %p, size %lld\n",
__target_exe->name, __target_exe->data, __target_exe->size);
res = COI::ProcessCreateFromMemory(
engine, // in_Engine
__target_exe->name, // in_pBinaryName
__target_exe->data, // in_pBinaryBuffer
__target_exe->size, // in_BinaryBufferLength,
0, // in_Argc
0, // in_ppArgv
environ == 0, // in_DupEnv
environ, // in_ppAdditionalEnv
mic_proxy_io, // in_ProxyActive
mic_proxy_fs_root, // in_ProxyfsRoot
mic_buffer_size, // in_BufferSpace
mic_library_path, // in_LibrarySearchPath
__target_exe->origin, // in_FileOfOrigin
__target_exe->offset, // in_FileOfOriginOffset
&m_process // out_pProcess
);
check_result(res, c_process_create, m_index, res);
// get function handles
res = COI::ProcessGetFunctionHandles(m_process, c_funcs_total,
m_func_names, m_funcs);
check_result(res, c_process_get_func_handles, m_index, res);
// initialize device side
pid_t pid = init_device();
// For IDB
if (__dbg_is_attached) {
// TODO: we have in-memory executable now.
// Check with IDB team what should we provide them now?
if (strlen(__target_exe->name) < MAX_TARGET_NAME) {
strcpy(__dbg_target_exe_name, __target_exe->name);
}
__dbg_target_so_pid = pid;
__dbg_target_id = m_physical_index;
__dbg_target_so_loaded();
}
}
void Engine::fini_process(bool verbose)
{
if (m_process != 0) {
uint32_t sig;
int8_t ret;
// destroy target process
OFFLOAD_DEBUG_TRACE(2, "Destroying process on the device %d\n",
m_index);
COIRESULT res = COI::ProcessDestroy(m_process, -1, 0, &ret, &sig);
m_process = 0;
if (res == COI_SUCCESS) {
OFFLOAD_DEBUG_TRACE(3, "Device process: signal %d, exit code %d\n",
sig, ret);
if (verbose) {
if (sig != 0) {
LIBOFFLOAD_ERROR(
c_mic_process_exit_sig, m_index, sig,
c_signal_names[sig >= c_signal_max ? 0 : sig]);
}
else {
LIBOFFLOAD_ERROR(c_mic_process_exit_ret, m_index, ret);
}
}
// for idb
if (__dbg_is_attached) {
__dbg_target_so_unloaded();
}
}
else {
if (verbose) {
LIBOFFLOAD_ERROR(c_mic_process_exit, m_index);
}
}
}
}
void Engine::load_libraries()
{
// load libraries collected so far
for (TargetImageList::iterator it = m_images.begin();
it != m_images.end(); it++) {
OFFLOAD_DEBUG_TRACE(2, "Loading library \"%s\" from %p, size %llu\n",
it->name, it->data, it->size);
// load library to the device
COILIBRARY lib;
COIRESULT res;
res = COI::ProcessLoadLibraryFromMemory(m_process,
it->data,
it->size,
it->name,
mic_library_path,
it->origin,
it->offset,
COI_LOADLIBRARY_V1_FLAGS,
&lib);
if (res != COI_SUCCESS && res != COI_ALREADY_EXISTS) {
check_result(res, c_load_library, m_index, res);
}
}
m_images.clear();
}
static bool target_entry_cmp(
const VarList::BufEntry &l,
const VarList::BufEntry &r
)
{
const char *l_name = reinterpret_cast<const char*>(l.name);
const char *r_name = reinterpret_cast<const char*>(r.name);
return strcmp(l_name, r_name) < 0;
}
static bool host_entry_cmp(
const VarTable::Entry *l,
const VarTable::Entry *r
)
{
return strcmp(l->name, r->name) < 0;
}
void Engine::init_ptr_data(void)
{
COIRESULT res;
COIEVENT event;
// Prepare table of host entries
std::vector<const VarTable::Entry*> host_table(__offload_vars.begin(),
__offload_vars.end());
// no need to do anything further is host table is empty
if (host_table.size() <= 0) {
return;
}
// Get var table entries from the target.
// First we need to get size for the buffer to copy data
struct {
int64_t nelems;
int64_t length;
} params;
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_var_table_size],
0, 0, 0,
0, 0,
0, 0,
&params, sizeof(params),
&event);
check_result(res, c_pipeline_run_func, m_index, res);
res = COI::EventWait(1, &event, -1, 1, 0, 0);
check_result(res, c_event_wait, res);
if (params.length == 0) {
return;
}
// create buffer for target entries and copy data to host
COIBUFFER buffer;
res = COI::BufferCreate(params.length, COI_BUFFER_NORMAL, 0, 0, 1,
&m_process, &buffer);
check_result(res, c_buf_create, m_index, res);
COI_ACCESS_FLAGS flags = COI_SINK_WRITE;
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_var_table_copy],
1, &buffer, &flags,
0, 0,
&params.nelems, sizeof(params.nelems),
0, 0,
&event);
check_result(res, c_pipeline_run_func, m_index, res);
res = COI::EventWait(1, &event, -1, 1, 0, 0);
check_result(res, c_event_wait, res);
// patch names in target data
VarList::BufEntry *target_table;
COIMAPINSTANCE map_inst;
res = COI::BufferMap(buffer, 0, params.length, COI_MAP_READ_ONLY, 0, 0,
0, &map_inst,
reinterpret_cast<void**>(&target_table));
check_result(res, c_buf_map, res);
VarList::table_patch_names(target_table, params.nelems);
// and sort entries
std::sort(target_table, target_table + params.nelems, target_entry_cmp);
std::sort(host_table.begin(), host_table.end(), host_entry_cmp);
// merge host and target entries and enter matching vars map
std::vector<const VarTable::Entry*>::const_iterator hi =
host_table.begin();
std::vector<const VarTable::Entry*>::const_iterator he =
host_table.end();
const VarList::BufEntry *ti = target_table;
const VarList::BufEntry *te = target_table + params.nelems;
while (hi != he && ti != te) {
int res = strcmp((*hi)->name, reinterpret_cast<const char*>(ti->name));
if (res == 0) {
// add matching entry to var map
std::pair<PtrSet::iterator, bool> res =
m_ptr_set.insert(PtrData((*hi)->addr, (*hi)->size));
// store address for new entries
if (res.second) {
PtrData *ptr = const_cast<PtrData*>(res.first.operator->());
ptr->mic_addr = ti->addr;
ptr->is_static = true;
}
hi++;
ti++;
}
else if (res < 0) {
hi++;
}
else {
ti++;
}
}
// cleanup
res = COI::BufferUnmap(map_inst, 0, 0, 0);
check_result(res, c_buf_unmap, res);
res = COI::BufferDestroy(buffer);
check_result(res, c_buf_destroy, res);
}
COIRESULT Engine::compute(
const std::list<COIBUFFER> &buffers,
const void* data,
uint16_t data_size,
void* ret,
uint16_t ret_size,
uint32_t num_deps,
const COIEVENT* deps,
COIEVENT* event
) /* const */
{
COIBUFFER *bufs;
COI_ACCESS_FLAGS *flags;
COIRESULT res;
// convert buffers list to array
int num_bufs = buffers.size();
if (num_bufs > 0) {
bufs = (COIBUFFER*) alloca(num_bufs * sizeof(COIBUFFER));
flags = (COI_ACCESS_FLAGS*) alloca(num_bufs *
sizeof(COI_ACCESS_FLAGS));
int i = 0;
for (std::list<COIBUFFER>::const_iterator it = buffers.begin();
it != buffers.end(); it++) {
bufs[i] = *it;
// TODO: this should be fixed
flags[i++] = COI_SINK_WRITE;
}
}
else {
bufs = 0;
flags = 0;
}
// start computation
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_compute],
num_bufs, bufs, flags,
num_deps, deps,
data, data_size,
ret, ret_size,
event);
return res;
}
pid_t Engine::init_device(void)
{
struct init_data {
int device_index;
int devices_total;
int console_level;
int offload_report_level;
} data;
COIRESULT res;
COIEVENT event;
pid_t pid;
OFFLOAD_DEBUG_TRACE_1(2, 0, c_offload_init,
"Initializing device with logical index %d "
"and physical index %d\n",
m_index, m_physical_index);
// setup misc data
data.device_index = m_index;
data.devices_total = mic_engines_total;
data.console_level = console_enabled;
data.offload_report_level = offload_report_level;
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_init],
0, 0, 0, 0, 0,
&data, sizeof(data),
&pid, sizeof(pid),
&event);
check_result(res, c_pipeline_run_func, m_index, res);
res = COI::EventWait(1, &event, -1, 1, 0, 0);
check_result(res, c_event_wait, res);
OFFLOAD_DEBUG_TRACE(2, "Device process pid is %d\n", pid);
return pid;
}
// data associated with each thread
struct Thread {
Thread(long* addr_coipipe_counter) {
m_addr_coipipe_counter = addr_coipipe_counter;
memset(m_pipelines, 0, sizeof(m_pipelines));
}
~Thread() {
#ifndef TARGET_WINNT
__sync_sub_and_fetch(m_addr_coipipe_counter, 1);
#else // TARGET_WINNT
_InterlockedDecrement(m_addr_coipipe_counter);
#endif // TARGET_WINNT
for (int i = 0; i < mic_engines_total; i++) {
if (m_pipelines[i] != 0) {
COI::PipelineDestroy(m_pipelines[i]);
}
}
}
COIPIPELINE get_pipeline(int index) const {
return m_pipelines[index];
}
void set_pipeline(int index, COIPIPELINE pipeline) {
m_pipelines[index] = pipeline;
}
AutoSet& get_auto_vars() {
return m_auto_vars;
}
private:
long* m_addr_coipipe_counter;
AutoSet m_auto_vars;
COIPIPELINE m_pipelines[MIC_ENGINES_MAX];
};
COIPIPELINE Engine::get_pipeline(void)
{
Thread* thread = (Thread*) thread_getspecific(mic_thread_key);
if (thread == 0) {
thread = new Thread(&m_proc_number);
thread_setspecific(mic_thread_key, thread);
}
COIPIPELINE pipeline = thread->get_pipeline(m_index);
if (pipeline == 0) {
COIRESULT res;
int proc_num;
#ifndef TARGET_WINNT
proc_num = __sync_fetch_and_add(&m_proc_number, 1);
#else // TARGET_WINNT
proc_num = _InterlockedIncrement(&m_proc_number);
#endif // TARGET_WINNT
if (proc_num > COI_PIPELINE_MAX_PIPELINES) {
LIBOFFLOAD_ERROR(c_coipipe_max_number, COI_PIPELINE_MAX_PIPELINES);
LIBOFFLOAD_ABORT;
}
// create pipeline for this thread
res = COI::PipelineCreate(m_process, 0, mic_stack_size, &pipeline);
check_result(res, c_pipeline_create, m_index, res);
thread->set_pipeline(m_index, pipeline);
}
return pipeline;
}
AutoSet& Engine::get_auto_vars(void)
{
Thread* thread = (Thread*) thread_getspecific(mic_thread_key);
if (thread == 0) {
thread = new Thread(&m_proc_number);
thread_setspecific(mic_thread_key, thread);
}
return thread->get_auto_vars();
}
void Engine::destroy_thread_data(void *data)
{
delete static_cast<Thread*>(data);
}
+482
View File
@@ -0,0 +1,482 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_ENGINE_H_INCLUDED
#define OFFLOAD_ENGINE_H_INCLUDED
#include <limits.h>
#include <list>
#include <set>
#include <map>
#include "offload_common.h"
#include "coi/coi_client.h"
// Address range
class MemRange {
public:
MemRange() : m_start(0), m_length(0) {}
MemRange(const void *addr, uint64_t len) : m_start(addr), m_length(len) {}
const void* start() const {
return m_start;
}
const void* end() const {
return static_cast<const char*>(m_start) + m_length;
}
uint64_t length() const {
return m_length;
}
// returns true if given range overlaps with another one
bool overlaps(const MemRange &o) const {
// Two address ranges A[start, end) and B[start,end) overlap
// if A.start < B.end and A.end > B.start.
return start() < o.end() && end() > o.start();
}
// returns true if given range contains the other range
bool contains(const MemRange &o) const {
return start() <= o.start() && o.end() <= end();
}
private:
const void* m_start;
uint64_t m_length;
};
// Data associated with a pointer variable
class PtrData {
public:
PtrData(const void *addr, uint64_t len) :
cpu_addr(addr, len), cpu_buf(0),
mic_addr(0), alloc_disp(0), mic_buf(0), mic_offset(0),
ref_count(0), is_static(false)
{}
//
// Copy constructor
//
PtrData(const PtrData& ptr):
cpu_addr(ptr.cpu_addr), cpu_buf(ptr.cpu_buf),
mic_addr(ptr.mic_addr), alloc_disp(ptr.alloc_disp),
mic_buf(ptr.mic_buf), mic_offset(ptr.mic_offset),
ref_count(ptr.ref_count), is_static(ptr.is_static)
{}
bool operator<(const PtrData &o) const {
// Variables are sorted by the CPU start address.
// Overlapping memory ranges are considered equal.
return (cpu_addr.start() < o.cpu_addr.start()) &&
!cpu_addr.overlaps(o.cpu_addr);
}
long add_reference() {
if (is_static) {
return LONG_MAX;
}
#ifndef TARGET_WINNT
return __sync_fetch_and_add(&ref_count, 1);
#else // TARGET_WINNT
return _InterlockedIncrement(&ref_count) - 1;
#endif // TARGET_WINNT
}
long remove_reference() {
if (is_static) {
return LONG_MAX;
}
#ifndef TARGET_WINNT
return __sync_sub_and_fetch(&ref_count, 1);
#else // TARGET_WINNT
return _InterlockedDecrement(&ref_count);
#endif // TARGET_WINNT
}
long get_reference() const {
if (is_static) {
return LONG_MAX;
}
return ref_count;
}
public:
// CPU address range
const MemRange cpu_addr;
// CPU and MIC buffers
COIBUFFER cpu_buf;
COIBUFFER mic_buf;
// placeholder for buffer address on mic
uint64_t mic_addr;
uint64_t alloc_disp;
// additional offset to pointer data on MIC for improving bandwidth for
// data which is not 4K aligned
uint32_t mic_offset;
// if true buffers are created from static memory
bool is_static;
mutex_t alloc_ptr_data_lock;
private:
// reference count for the entry
long ref_count;
};
typedef std::list<PtrData*> PtrDataList;
// Data associated with automatic variable
class AutoData {
public:
AutoData(const void *addr, uint64_t len) :
cpu_addr(addr, len), ref_count(0)
{}
bool operator<(const AutoData &o) const {
// Variables are sorted by the CPU start address.
// Overlapping memory ranges are considered equal.
return (cpu_addr.start() < o.cpu_addr.start()) &&
!cpu_addr.overlaps(o.cpu_addr);
}
long add_reference() {
#ifndef TARGET_WINNT
return __sync_fetch_and_add(&ref_count, 1);
#else // TARGET_WINNT
return _InterlockedIncrement(&ref_count) - 1;
#endif // TARGET_WINNT
}
long remove_reference() {
#ifndef TARGET_WINNT
return __sync_sub_and_fetch(&ref_count, 1);
#else // TARGET_WINNT
return _InterlockedDecrement(&ref_count);
#endif // TARGET_WINNT
}
long get_reference() const {
return ref_count;
}
public:
// CPU address range
const MemRange cpu_addr;
private:
// reference count for the entry
long ref_count;
};
// Set of autimatic variables
typedef std::set<AutoData> AutoSet;
// Target image data
struct TargetImage
{
TargetImage(const char *_name, const void *_data, uint64_t _size,
const char *_origin, uint64_t _offset) :
name(_name), data(_data), size(_size),
origin(_origin), offset(_offset)
{}
// library name
const char* name;
// contents and size
const void* data;
uint64_t size;
// file of origin and offset within that file
const char* origin;
uint64_t offset;
};
typedef std::list<TargetImage> TargetImageList;
// Data associated with persistent auto objects
struct PersistData
{
PersistData(const void *addr, uint64_t routine_num, uint64_t size) :
stack_cpu_addr(addr), routine_id(routine_num)
{
stack_ptr_data = new PtrData(0, size);
}
// 1-st key value - beginning of the stack at CPU
const void * stack_cpu_addr;
// 2-nd key value - identifier of routine invocation at CPU
uint64_t routine_id;
// corresponded PtrData; only stack_ptr_data->mic_buf is used
PtrData * stack_ptr_data;
// used to get offset of the variable in stack buffer
char * cpu_stack_addr;
};
typedef std::list<PersistData> PersistDataList;
// class representing a single engine
struct Engine {
friend void __offload_init_library_once(void);
friend void __offload_fini_library(void);
#define check_result(res, tag, ...) \
{ \
if (res == COI_PROCESS_DIED) { \
fini_process(true); \
exit(1); \
} \
if (res != COI_SUCCESS) { \
__liboffload_error_support(tag, __VA_ARGS__); \
exit(1); \
} \
}
int get_logical_index() const {
return m_index;
}
int get_physical_index() const {
return m_physical_index;
}
const COIPROCESS& get_process() const {
return m_process;
}
// initialize device
void init(void);
// add new library
void add_lib(const TargetImage &lib)
{
m_lock.lock();
m_ready = false;
m_images.push_back(lib);
m_lock.unlock();
}
COIRESULT compute(
const std::list<COIBUFFER> &buffers,
const void* data,
uint16_t data_size,
void* ret,
uint16_t ret_size,
uint32_t num_deps,
const COIEVENT* deps,
COIEVENT* event
);
#ifdef MYO_SUPPORT
// temporary workaround for blocking behavior for myoiLibInit/Fini calls
void init_myo(COIEVENT *event) {
COIRESULT res;
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_myo_init],
0, 0, 0, 0, 0, 0, 0, 0, 0,
event);
check_result(res, c_pipeline_run_func, m_index, res);
}
void fini_myo(COIEVENT *event) {
COIRESULT res;
res = COI::PipelineRunFunction(get_pipeline(),
m_funcs[c_func_myo_fini],
0, 0, 0, 0, 0, 0, 0, 0, 0,
event);
check_result(res, c_pipeline_run_func, m_index, res);
}
#endif // MYO_SUPPORT
//
// Memory association table
//
PtrData* find_ptr_data(const void *ptr) {
m_ptr_lock.lock();
PtrSet::iterator res = m_ptr_set.find(PtrData(ptr, 0));
m_ptr_lock.unlock();
if (res == m_ptr_set.end()) {
return 0;
}
return const_cast<PtrData*>(res.operator->());
}
PtrData* insert_ptr_data(const void *ptr, uint64_t len, bool &is_new) {
m_ptr_lock.lock();
std::pair<PtrSet::iterator, bool> res =
m_ptr_set.insert(PtrData(ptr, len));
PtrData* ptr_data = const_cast<PtrData*>(res.first.operator->());
m_ptr_lock.unlock();
is_new = res.second;
if (is_new) {
// It's necessary to lock as soon as possible.
// unlock must be done at call site of insert_ptr_data at
// branch for is_new
ptr_data->alloc_ptr_data_lock.lock();
}
return ptr_data;
}
void remove_ptr_data(const void *ptr) {
m_ptr_lock.lock();
m_ptr_set.erase(PtrData(ptr, 0));
m_ptr_lock.unlock();
}
//
// Automatic variables
//
AutoData* find_auto_data(const void *ptr) {
AutoSet &auto_vars = get_auto_vars();
AutoSet::iterator res = auto_vars.find(AutoData(ptr, 0));
if (res == auto_vars.end()) {
return 0;
}
return const_cast<AutoData*>(res.operator->());
}
AutoData* insert_auto_data(const void *ptr, uint64_t len) {
AutoSet &auto_vars = get_auto_vars();
std::pair<AutoSet::iterator, bool> res =
auto_vars.insert(AutoData(ptr, len));
return const_cast<AutoData*>(res.first.operator->());
}
void remove_auto_data(const void *ptr) {
get_auto_vars().erase(AutoData(ptr, 0));
}
//
// Signals
//
void add_signal(const void *signal, OffloadDescriptor *desc) {
m_signal_lock.lock();
m_signal_map[signal] = desc;
m_signal_lock.unlock();
}
OffloadDescriptor* find_signal(const void *signal, bool remove) {
OffloadDescriptor *desc = 0;
m_signal_lock.lock();
{
SignalMap::iterator it = m_signal_map.find(signal);
if (it != m_signal_map.end()) {
desc = it->second;
if (remove) {
m_signal_map.erase(it);
}
}
}
m_signal_lock.unlock();
return desc;
}
// stop device process
void fini_process(bool verbose);
// list of stacks active at the engine
PersistDataList m_persist_list;
private:
Engine() : m_index(-1), m_physical_index(-1), m_process(0), m_ready(false),
m_proc_number(0)
{}
~Engine() {
if (m_process != 0) {
fini_process(false);
}
}
// set indexes
void set_indexes(int logical_index, int physical_index) {
m_index = logical_index;
m_physical_index = physical_index;
}
// start process on device
void init_process();
void load_libraries(void);
void init_ptr_data(void);
// performs library intialization on the device side
pid_t init_device(void);
private:
// get pipeline associated with a calling thread
COIPIPELINE get_pipeline(void);
// get automatic vars set associated with the calling thread
AutoSet& get_auto_vars(void);
// destructor for thread data
static void destroy_thread_data(void *data);
private:
typedef std::set<PtrData> PtrSet;
typedef std::map<const void*, OffloadDescriptor*> SignalMap;
// device indexes
int m_index;
int m_physical_index;
// number of COI pipes created for the engine
long m_proc_number;
// process handle
COIPROCESS m_process;
// If false, device either has not been initialized or new libraries
// have been added.
bool m_ready;
mutex_t m_lock;
// List of libraries to be loaded
TargetImageList m_images;
// var table
PtrSet m_ptr_set;
mutex_t m_ptr_lock;
// signals
SignalMap m_signal_map;
mutex_t m_signal_lock;
// constants for accessing device function handles
enum {
c_func_compute = 0,
#ifdef MYO_SUPPORT
c_func_myo_init,
c_func_myo_fini,
#endif // MYO_SUPPORT
c_func_init,
c_func_var_table_size,
c_func_var_table_copy,
c_funcs_total
};
static const char* m_func_names[c_funcs_total];
// device function handles
COIFUNCTION m_funcs[c_funcs_total];
// int -> name mapping for device signals
static const int c_signal_max = 32;
static const char* c_signal_names[c_signal_max];
};
#endif // OFFLOAD_ENGINE_H_INCLUDED
+354
View File
@@ -0,0 +1,354 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_env.h"
#include <string.h>
#include <ctype.h>
#include "offload_util.h"
#include "liboffload_error_codes.h"
// for environment variables valid on all cards
const int MicEnvVar::any_card = -1;
MicEnvVar::~MicEnvVar()
{
for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
it = card_spec_list.begin();
it != card_spec_list.end(); it++) {
CardEnvVars *card_data = *it;
delete card_data;
}
}
MicEnvVar::VarValue::~VarValue()
{
free(env_var_value);
}
MicEnvVar::CardEnvVars::~CardEnvVars()
{
for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
it != env_vars.end(); it++) {
VarValue *var_value = *it;
delete var_value;
}
}
// Searching for card in "card_spec_list" list with the same "number"
MicEnvVar::CardEnvVars* MicEnvVar::get_card(int number)
{
if (number == any_card) {
return &common_vars;
}
for (std::list<MicEnvVar::CardEnvVars*>::const_iterator
it = card_spec_list.begin();
it != card_spec_list.end(); it++) {
CardEnvVars *card_data = *it;
if (card_data->card_number == number) {
return card_data;
}
}
return NULL;
}
// Searching for environment variable in "env_var" list with the same name
MicEnvVar::VarValue* MicEnvVar::CardEnvVars::find_var(
char* env_var_name,
int env_var_name_length
)
{
for (std::list<MicEnvVar::VarValue*>::const_iterator it = env_vars.begin();
it != env_vars.end(); it++) {
VarValue *var_value = *it;
if (var_value->length == env_var_name_length &&
!strncmp(var_value->env_var, env_var_name,
env_var_name_length)) {
return var_value;
}
}
return NULL;
}
void MicEnvVar::analyze_env_var(char *env_var_string)
{
char *env_var_name;
char *env_var_def;
int card_number;
int env_var_name_length;
MicEnvVarKind env_var_kind;
env_var_kind = get_env_var_kind(env_var_string,
&card_number,
&env_var_name,
&env_var_name_length,
&env_var_def);
switch (env_var_kind) {
case c_mic_var:
case c_mic_card_var:
add_env_var(card_number,
env_var_name,
env_var_name_length,
env_var_def);
break;
case c_mic_card_env:
mic_parse_env_var_list(card_number, env_var_def);
break;
case c_no_mic:
default:
break;
}
}
void MicEnvVar::add_env_var(
int card_number,
char *env_var_name,
int env_var_name_length,
char *env_var_def
)
{
VarValue *var;
CardEnvVars *card;
// The case corresponds to common env var definition of kind
// <mic-prefix>_<var>
if (card_number == any_card) {
card = &common_vars;
}
else {
card = get_card(card_number);
if (!card) {
// definition for new card occurred
card = new CardEnvVars(card_number);
card_spec_list.push_back(card);
}
}
var = card->find_var(env_var_name, env_var_name_length);
if (!var) {
// put new env var definition in "env_var" list
var = new VarValue(env_var_name, env_var_name_length, env_var_def);
card->env_vars.push_back(var);
}
}
// The routine analyses string pointed by "env_var_string" argument
// according to the following syntax:
//
// Specification of prefix for MIC environment variables
// MIC_ENV_PREFIX=<mic-prefix>
//
// Setting single MIC environment variable
// <mic-prefix>_<var>=<value>
// <mic-prefix>_<card-number>_<var>=<value>
// Setting multiple MIC environment variables
// <mic-prefix>_<card-number>_ENV=<env-vars>
MicEnvVarKind MicEnvVar::get_env_var_kind(
char *env_var_string,
int *card_number,
char **env_var_name,
int *env_var_name_length,
char **env_var_def
)
{
int len = strlen(prefix);
char *c = env_var_string;
int num = 0;
bool card_is_set = false;
if (strncmp(c, prefix, len) != 0 || c[len] != '_') {
return c_no_mic;
}
c += len + 1;
*card_number = any_card;
if (isdigit(*c)) {
while (isdigit (*c)) {
num = (*c++ - '0') + (num * 10);
}
if (*c != '_') {
return c_no_mic;
}
c++;
*card_number = num;
card_is_set = true;
}
if (!isalpha(*c)) {
return c_no_mic;
}
*env_var_name = *env_var_def = c;
if (strncmp(c, "ENV=", 4) == 0) {
if (!card_is_set) {
*env_var_name_length = 3;
*env_var_name = *env_var_def = c;
*env_var_def = strdup(*env_var_def);
return c_mic_var;
}
*env_var_def = c + strlen("ENV=");
*env_var_def = strdup(*env_var_def);
return c_mic_card_env;
}
if (isalpha(*c)) {
*env_var_name_length = 0;
while (isalnum(*c) || *c == '_') {
c++;
(*env_var_name_length)++;
}
}
if (*c != '=') {
return c_no_mic;
}
*env_var_def = strdup(*env_var_def);
return card_is_set? c_mic_card_var : c_mic_var;
}
// analysing <env-vars> in form:
// <mic-prefix>_<card-number>_ENV=<env-vars>
// where:
//
// <env-vars>:
// <env-var>
// <env-vars> | <env-var>
//
// <env-var>:
// variable=value
// variable="value"
// variable=
void MicEnvVar::mic_parse_env_var_list(
int card_number, char *env_vars_def_list)
{
char *c = env_vars_def_list;
char *env_var_name;
int env_var_name_length;
char *env_var_def;
bool var_is_quoted;
if (*c == '"') {
c++;
}
while (*c != 0) {
var_is_quoted = false;
env_var_name = c;
env_var_name_length = 0;
if (isalpha(*c)) {
while (isalnum(*c) || *c == '_') {
c++;
env_var_name_length++;
}
}
else {
LIBOFFLOAD_ERROR(c_mic_parse_env_var_list1);
return;
}
if (*c != '=') {
LIBOFFLOAD_ERROR(c_mic_parse_env_var_list2);
return;
}
c++;
if (*c == '"') {
var_is_quoted = true;
c++;
}
// Environment variable values that contain | will need to be escaped.
while (*c != 0 && *c != '|' &&
(!var_is_quoted || *c != '"'))
{
// skip escaped symbol
if (*c == '\\') {
c++;
}
c++;
}
if (var_is_quoted) {
c++; // for "
while (*c != 0 && *c != '|') {
c++;
}
}
int sz = c - env_var_name;
env_var_def = (char*)malloc(sz);
memcpy(env_var_def, env_var_name, sz);
env_var_def[sz] = 0;
if (*c == '|') {
c++;
while (*c != 0 && *c == ' ') {
c++;
}
}
add_env_var(card_number,
env_var_name,
env_var_name_length,
env_var_def);
}
}
// Collect all definitions for the card with number "card_num".
// The returned result is vector of string pointers defining one
// environment variable. The vector is terminated by NULL pointer.
// In the beginning of the vector there are env vars defined as
// <mic-prefix>_<card-number>_<var>=<value>
// or
// <mic-prefix>_<card-number>_ENV=<env-vars>
// where <card-number> is equal to "card_num"
// They are followed by definitions valid for any card
// and absent in previous definitions.
char** MicEnvVar::create_environ_for_card(int card_num)
{
VarValue *var_value;
VarValue *var_value_find;
CardEnvVars *card_data = get_card(card_num);
CardEnvVars *card_data_common;
std::list<char*> new_env;
char **rez;
if (!prefix) {
return NULL;
}
// There is no personel env var definitions for the card with
// number "card_num"
if (!card_data) {
return create_environ_for_card(any_card);
}
for (std::list<MicEnvVar::VarValue*>::const_iterator
it = card_data->env_vars.begin();
it != card_data->env_vars.end(); it++) {
var_value = *it;
new_env.push_back(var_value->env_var_value);
}
if (card_num != any_card) {
card_data_common = get_card(any_card);
for (std::list<MicEnvVar::VarValue*>::const_iterator
it = card_data_common->env_vars.begin();
it != card_data_common->env_vars.end(); it++) {
var_value = *it;
var_value_find = card_data->find_var(var_value->env_var,
var_value->length);
if (!var_value_find) {
new_env.push_back(var_value->env_var_value);
}
}
}
int new_env_size = new_env.size();
rez = (char**) malloc((new_env_size + 1) * sizeof(char*));
std::copy(new_env.begin(), new_env.end(), rez);
rez[new_env_size] = 0;
return rez;
}
+91
View File
@@ -0,0 +1,91 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_ENV_H_INCLUDED
#define OFFLOAD_ENV_H_INCLUDED
#include <list>
// data structure and routines to parse MIC user environment and pass to MIC
enum MicEnvVarKind
{
c_no_mic, // not MIC env var
c_mic_var, // for <mic-prefix>_<var>
c_mic_card_var, // for <mic-prefix>_<card-number>_<var>
c_mic_card_env // for <mic-prefix>_<card-number>_ENV
};
struct MicEnvVar {
public:
MicEnvVar() : prefix(0) {}
~MicEnvVar();
void analyze_env_var(char *env_var_string);
char** create_environ_for_card(int card_num);
MicEnvVarKind get_env_var_kind(
char *env_var_string,
int *card_number,
char **env_var_name,
int *env_var_name_length,
char **env_var_def
);
void add_env_var(
int card_number,
char *env_var_name,
int env_var_name_length,
char *env_var_def
);
void set_prefix(const char *pref) {
prefix = (pref && *pref != '\0') ? pref : 0;
}
struct VarValue {
public:
char* env_var;
int length;
char* env_var_value;
VarValue(char* var, int ln, char* value)
{
env_var = var;
length = ln;
env_var_value = value;
}
~VarValue();
};
struct CardEnvVars {
public:
int card_number;
std::list<struct VarValue*> env_vars;
CardEnvVars() { card_number = any_card; }
CardEnvVars(int num) { card_number = num; }
~CardEnvVars();
void add_new_env_var(int number, char *env_var, int length,
char *env_var_value);
VarValue* find_var(char* env_var_name, int env_var_name_length);
};
static const int any_card;
private:
void mic_parse_env_var_list(int card_number, char *env_var_def);
CardEnvVars* get_card(int number);
const char *prefix;
std::list<struct CardEnvVars *> card_spec_list;
CardEnvVars common_vars;
};
#endif // OFFLOAD_ENV_H_INCLUDED
File diff suppressed because it is too large Load Diff
+343
View File
@@ -0,0 +1,343 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*! \file
\brief The parts of the runtime library used only on the host
*/
#ifndef OFFLOAD_HOST_H_INCLUDED
#define OFFLOAD_HOST_H_INCLUDED
#ifndef TARGET_WINNT
#include <unistd.h>
#endif // TARGET_WINNT
#include "offload_common.h"
#include "offload_util.h"
#include "offload_engine.h"
#include "offload_env.h"
#include "offload_orsl.h"
#include "coi/coi_client.h"
// MIC engines.
extern Engine* mic_engines;
extern uint32_t mic_engines_total;
//! The target image is packed as follows.
/*! 1. 8 bytes containing the size of the target binary */
/*! 2. a null-terminated string which is the binary name */
/*! 3. <size> number of bytes that are the contents of the image */
/*! The address of symbol __offload_target_image
is the address of this structure. */
struct Image {
int64_t size; //!< Size in bytes of the target binary name and contents
char data[]; //!< The name and contents of the target image
};
// The offload descriptor.
class OffloadDescriptor
{
public:
OffloadDescriptor(
int index,
_Offload_status *status,
bool is_mandatory,
bool is_openmp,
OffloadHostTimerData * timer_data
) :
m_device(mic_engines[index % mic_engines_total]),
m_is_mandatory(is_mandatory),
m_is_openmp(is_openmp),
m_inout_buf(0),
m_func_desc(0),
m_func_desc_size(0),
m_in_deps(0),
m_in_deps_total(0),
m_out_deps(0),
m_out_deps_total(0),
m_vars(0),
m_vars_extra(0),
m_status(status),
m_timer_data(timer_data)
{}
~OffloadDescriptor()
{
if (m_in_deps != 0) {
free(m_in_deps);
}
if (m_out_deps != 0) {
free(m_out_deps);
}
if (m_func_desc != 0) {
free(m_func_desc);
}
if (m_vars != 0) {
free(m_vars);
free(m_vars_extra);
}
}
bool offload(const char *name, bool is_empty,
VarDesc *vars, VarDesc2 *vars2, int vars_total,
const void **waits, int num_waits, const void **signal,
int entry_id, const void *stack_addr);
bool offload_finish();
bool is_signaled();
OffloadHostTimerData* get_timer_data() const {
return m_timer_data;
}
private:
bool wait_dependencies(const void **waits, int num_waits);
bool setup_descriptors(VarDesc *vars, VarDesc2 *vars2, int vars_total,
int entry_id, const void *stack_addr);
bool setup_misc_data(const char *name);
bool send_pointer_data(bool is_async);
bool send_noncontiguous_pointer_data(
int i,
PtrData* src_buf,
PtrData* dst_buf,
COIEVENT *event);
bool receive_noncontiguous_pointer_data(
int i,
char* src_data,
COIBUFFER dst_buf,
COIEVENT *event);
bool gather_copyin_data();
bool compute();
bool receive_pointer_data(bool is_async);
bool scatter_copyout_data();
void cleanup();
bool find_ptr_data(PtrData* &ptr_data, void *base, int64_t disp,
int64_t length, bool error_does_not_exist = true);
bool alloc_ptr_data(PtrData* &ptr_data, void *base, int64_t disp,
int64_t length, int64_t alloc_disp, int align);
bool init_static_ptr_data(PtrData *ptr_data);
bool init_mic_address(PtrData *ptr_data);
bool offload_stack_memory_manager(const void * stack_begin, int routine_id,
int buf_size, int align, bool *is_new);
bool nullify_target_stack(COIBUFFER targ_buf, uint64_t size);
bool gen_var_descs_for_pointer_array(int i);
void report_coi_error(error_types msg, COIRESULT res);
_Offload_result translate_coi_error(COIRESULT res) const;
private:
typedef std::list<COIBUFFER> BufferList;
// extra data associated with each variable descriptor
struct VarExtra {
PtrData* src_data;
PtrData* dst_data;
AutoData* auto_data;
int64_t cpu_disp;
int64_t cpu_offset;
CeanReadRanges *read_rng_src;
CeanReadRanges *read_rng_dst;
int64_t ptr_arr_offset;
bool is_arr_ptr_el;
};
template<typename T> class ReadArrElements {
public:
ReadArrElements():
ranges(NULL),
el_size(sizeof(T)),
offset(0),
count(0),
is_empty(true),
base(NULL)
{}
bool read_next(bool flag)
{
if (flag != 0) {
if (is_empty) {
if (ranges) {
if (!get_next_range(ranges, &offset)) {
// ranges are over
return false;
}
}
// all contiguous elements are over
else if (count != 0) {
return false;
}
length_cur = size;
}
else {
offset += el_size;
}
val = (T)get_el_value(base, offset, el_size);
length_cur -= el_size;
count++;
is_empty = length_cur == 0;
}
return true;
}
public:
CeanReadRanges * ranges;
T val;
int el_size;
int64_t size,
offset,
length_cur;
bool is_empty;
int count;
char *base;
};
// ptr_data for persistent auto objects
PtrData* m_stack_ptr_data;
PtrDataList m_destroy_stack;
// Engine
Engine& m_device;
// if true offload is mandatory
bool m_is_mandatory;
// if true offload has openmp origin
const bool m_is_openmp;
// The Marshaller for the inputs of the offloaded region.
Marshaller m_in;
// The Marshaller for the outputs of the offloaded region.
Marshaller m_out;
// List of buffers that are passed to dispatch call
BufferList m_compute_buffers;
// List of buffers that need to be destroyed at the end of offload
BufferList m_destroy_buffers;
// Variable descriptors
VarDesc* m_vars;
VarExtra* m_vars_extra;
int m_vars_total;
// Pointer to a user-specified status variable
_Offload_status *m_status;
// Function descriptor
FunctionDescriptor* m_func_desc;
uint32_t m_func_desc_size;
// Buffer for transferring copyin/copyout data
COIBUFFER m_inout_buf;
// Dependencies
COIEVENT *m_in_deps;
uint32_t m_in_deps_total;
COIEVENT *m_out_deps;
uint32_t m_out_deps_total;
// Timer data
OffloadHostTimerData *m_timer_data;
// copyin/copyout data length
uint64_t m_in_datalen;
uint64_t m_out_datalen;
// a boolean value calculated in setup_descriptors. If true we need to do
// a run function on the target. Otherwise it may be optimized away.
bool m_need_runfunction;
};
// Initialization types for MIC
enum OffloadInitType {
c_init_on_start, // all devices before entering main
c_init_on_offload, // single device before starting the first offload
c_init_on_offload_all // all devices before starting the first offload
};
// Initializes library and registers specified offload image.
extern "C" void __offload_register_image(const void* image);
extern "C" void __offload_unregister_image(const void* image);
// Initializes offload runtime library.
extern int __offload_init_library(void);
// thread data for associating pipelines with threads
extern pthread_key_t mic_thread_key;
// Environment variables for devices
extern MicEnvVar mic_env_vars;
// CPU frequency
extern uint64_t cpu_frequency;
// LD_LIBRARY_PATH for MIC libraries
extern char* mic_library_path;
// stack size for target
extern uint32_t mic_stack_size;
// Preallocated memory size for buffers on MIC
extern uint64_t mic_buffer_size;
// Setting controlling inout proxy
extern bool mic_proxy_io;
extern char* mic_proxy_fs_root;
// Threshold for creating buffers with large pages
extern uint64_t __offload_use_2mb_buffers;
// offload initialization type
extern OffloadInitType __offload_init_type;
// Device number to offload to when device is not explicitly specified.
extern int __omp_device_num;
// target executable
extern TargetImage* __target_exe;
// IDB support
// Called by the offload runtime after initialization of offload infrastructure
// has been completed.
extern "C" void __dbg_target_so_loaded();
// Called by the offload runtime when the offload infrastructure is about to be
// shut down, currently at application exit.
extern "C" void __dbg_target_so_unloaded();
// Null-terminated string containing path to the process image of the hosting
// application (offload_main)
#define MAX_TARGET_NAME 512
extern "C" char __dbg_target_exe_name[MAX_TARGET_NAME];
// Integer specifying the process id
extern "C" pid_t __dbg_target_so_pid;
// Integer specifying the 0-based device number
extern "C" int __dbg_target_id;
// Set to non-zero by the host-side debugger to enable offload debugging
// support
extern "C" int __dbg_is_attached;
// Major version of the debugger support API
extern "C" const int __dbg_api_major_version;
// Minor version of the debugger support API
extern "C" const int __dbg_api_minor_version;
#endif // OFFLOAD_HOST_H_INCLUDED
+805
View File
@@ -0,0 +1,805 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_myo_host.h"
#include <errno.h>
#include <malloc.h>
#include "offload_host.h"
#if defined(LINUX) || defined(FREEBSD)
#include <mm_malloc.h>
#endif
#define MYO_VERSION1 "MYO_1.0"
extern "C" void __cilkrts_cilk_for_32(void*, void*, uint32_t, int32_t);
extern "C" void __cilkrts_cilk_for_64(void*, void*, uint64_t, int32_t);
#ifndef TARGET_WINNT
#pragma weak __cilkrts_cilk_for_32
#pragma weak __cilkrts_cilk_for_64
#endif // TARGET_WINNT
#ifdef TARGET_WINNT
#define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(-1)
#else // TARGET_WINNT
#define MYO_TABLE_END_MARKER() reinterpret_cast<const char*>(0)
#endif // TARGET_WINNT
class MyoWrapper {
public:
MyoWrapper() : m_lib_handle(0), m_is_available(false)
{}
bool is_available() const {
return m_is_available;
}
bool LoadLibrary(void);
// unloads the library
void UnloadLibrary(void) {
// if (m_lib_handle != 0) {
// DL_close(m_lib_handle);
// m_lib_handle = 0;
// }
}
// Wrappers for MYO client functions
void LibInit(void *arg, void *func) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoinit,
"%s(%p, %p)\n", __func__, arg, func);
CheckResult(__func__, m_lib_init(arg, func));
}
void LibFini(void) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myofini, "%s()\n", __func__);
m_lib_fini();
}
void* SharedMalloc(size_t size) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedmalloc,
"%s(%lld)\n", __func__, size);
return m_shared_malloc(size);
}
void SharedFree(void *ptr) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedfree,
"%s(%p)\n", __func__, ptr);
m_shared_free(ptr);
}
void* SharedAlignedMalloc(size_t size, size_t align) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedalignedmalloc,
"%s(%lld, %lld)\n", __func__, size, align);
return m_shared_aligned_malloc(size, align);
}
void SharedAlignedFree(void *ptr) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myosharedalignedfree,
"%s(%p)\n", __func__, ptr);
m_shared_aligned_free(ptr);
}
void Acquire(void) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoacquire,
"%s()\n", __func__);
CheckResult(__func__, m_acquire());
}
void Release(void) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myorelease,
"%s()\n", __func__);
CheckResult(__func__, m_release());
}
void HostVarTablePropagate(void *table, int num_entries) const {
OFFLOAD_DEBUG_TRACE(4, "%s(%p, %d)\n", __func__, table, num_entries);
CheckResult(__func__, m_host_var_table_propagate(table, num_entries));
}
void HostFptrTableRegister(void *table, int num_entries,
int ordered) const {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_myoregister,
"%s(%p, %d, %d)\n", __func__, table,
num_entries, ordered);
CheckResult(__func__,
m_host_fptr_table_register(table, num_entries, ordered));
}
void RemoteThunkCall(void *thunk, void *args, int device) {
OFFLOAD_DEBUG_TRACE(4, "%s(%p, %p, %d)\n", __func__, thunk, args,
device);
CheckResult(__func__, m_remote_thunk_call(thunk, args, device));
}
MyoiRFuncCallHandle RemoteCall(char *func, void *args, int device) const {
OFFLOAD_DEBUG_TRACE(4, "%s(%s, %p, %d)\n", __func__, func, args,
device);
return m_remote_call(func, args, device);
}
void GetResult(MyoiRFuncCallHandle handle) const {
OFFLOAD_DEBUG_TRACE(4, "%s(%p)\n", __func__, handle);
CheckResult(__func__, m_get_result(handle));
}
private:
void CheckResult(const char *func, MyoError error) const {
if (error != MYO_SUCCESS) {
LIBOFFLOAD_ERROR(c_myowrapper_checkresult, func, error);
exit(1);
}
}
private:
void* m_lib_handle;
bool m_is_available;
// pointers to functions from myo library
MyoError (*m_lib_init)(void*, void*);
void (*m_lib_fini)(void);
void* (*m_shared_malloc)(size_t);
void (*m_shared_free)(void*);
void* (*m_shared_aligned_malloc)(size_t, size_t);
void (*m_shared_aligned_free)(void*);
MyoError (*m_acquire)(void);
MyoError (*m_release)(void);
MyoError (*m_host_var_table_propagate)(void*, int);
MyoError (*m_host_fptr_table_register)(void*, int, int);
MyoError (*m_remote_thunk_call)(void*, void*, int);
MyoiRFuncCallHandle (*m_remote_call)(char*, void*, int);
MyoError (*m_get_result)(MyoiRFuncCallHandle);
};
bool MyoWrapper::LoadLibrary(void)
{
#ifndef TARGET_WINNT
const char *lib_name = "libmyo-client.so";
#else // TARGET_WINNT
const char *lib_name = "myo-client.dll";
#endif // TARGET_WINNT
OFFLOAD_DEBUG_TRACE(2, "Loading MYO library %s ...\n", lib_name);
m_lib_handle = DL_open(lib_name);
if (m_lib_handle == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to load the library. errno = %d\n",
errno);
return false;
}
m_lib_init = (MyoError (*)(void*, void*))
DL_sym(m_lib_handle, "myoiLibInit", MYO_VERSION1);
if (m_lib_init == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiLibInit");
UnloadLibrary();
return false;
}
m_lib_fini = (void (*)(void))
DL_sym(m_lib_handle, "myoiLibFini", MYO_VERSION1);
if (m_lib_fini == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiLibFini");
UnloadLibrary();
return false;
}
m_shared_malloc = (void* (*)(size_t))
DL_sym(m_lib_handle, "myoSharedMalloc", MYO_VERSION1);
if (m_shared_malloc == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoSharedMalloc");
UnloadLibrary();
return false;
}
m_shared_free = (void (*)(void*))
DL_sym(m_lib_handle, "myoSharedFree", MYO_VERSION1);
if (m_shared_free == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoSharedFree");
UnloadLibrary();
return false;
}
m_shared_aligned_malloc = (void* (*)(size_t, size_t))
DL_sym(m_lib_handle, "myoSharedAlignedMalloc", MYO_VERSION1);
if (m_shared_aligned_malloc == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoSharedAlignedMalloc");
UnloadLibrary();
return false;
}
m_shared_aligned_free = (void (*)(void*))
DL_sym(m_lib_handle, "myoSharedAlignedFree", MYO_VERSION1);
if (m_shared_aligned_free == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoSharedAlignedFree");
UnloadLibrary();
return false;
}
m_acquire = (MyoError (*)(void))
DL_sym(m_lib_handle, "myoAcquire", MYO_VERSION1);
if (m_acquire == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoAcquire");
UnloadLibrary();
return false;
}
m_release = (MyoError (*)(void))
DL_sym(m_lib_handle, "myoRelease", MYO_VERSION1);
if (m_release == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoRelease");
UnloadLibrary();
return false;
}
m_host_var_table_propagate = (MyoError (*)(void*, int))
DL_sym(m_lib_handle, "myoiHostVarTablePropagate", MYO_VERSION1);
if (m_host_var_table_propagate == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiHostVarTablePropagate");
UnloadLibrary();
return false;
}
m_host_fptr_table_register = (MyoError (*)(void*, int, int))
DL_sym(m_lib_handle, "myoiHostFptrTableRegister", MYO_VERSION1);
if (m_host_fptr_table_register == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiHostFptrTableRegister");
UnloadLibrary();
return false;
}
m_remote_thunk_call = (MyoError (*)(void*, void*, int))
DL_sym(m_lib_handle, "myoiRemoteThunkCall", MYO_VERSION1);
if (m_remote_thunk_call == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiRemoteThunkCall");
UnloadLibrary();
return false;
}
m_remote_call = (MyoiRFuncCallHandle (*)(char*, void*, int))
DL_sym(m_lib_handle, "myoiRemoteCall", MYO_VERSION1);
if (m_remote_call == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiRemoteCall");
UnloadLibrary();
return false;
}
m_get_result = (MyoError (*)(MyoiRFuncCallHandle))
DL_sym(m_lib_handle, "myoiGetResult", MYO_VERSION1);
if (m_get_result == 0) {
OFFLOAD_DEBUG_TRACE(2, "Failed to find %s in MYO library\n",
"myoiGetResult");
UnloadLibrary();
return false;
}
OFFLOAD_DEBUG_TRACE(2, "The library was successfully loaded\n");
m_is_available = true;
return true;
}
static bool myo_is_available;
static MyoWrapper myo_wrapper;
struct MyoTable
{
MyoTable(SharedTableEntry *tab, int len) : var_tab(tab), var_tab_len(len)
{}
SharedTableEntry* var_tab;
int var_tab_len;
};
typedef std::list<MyoTable> MyoTableList;
static MyoTableList __myo_table_list;
static mutex_t __myo_table_lock;
static bool __myo_tables = false;
static void __offload_myo_shared_table_register(SharedTableEntry *entry);
static void __offload_myo_shared_init_table_register(InitTableEntry* entry);
static void __offload_myo_fptr_table_register(FptrTableEntry *entry);
static void __offload_myoLoadLibrary_once(void)
{
if (__offload_init_library()) {
myo_wrapper.LoadLibrary();
}
}
static bool __offload_myoLoadLibrary(void)
{
static OffloadOnceControl ctrl = OFFLOAD_ONCE_CONTROL_INIT;
__offload_run_once(&ctrl, __offload_myoLoadLibrary_once);
return myo_wrapper.is_available();
}
static void __offload_myoInit_once(void)
{
if (!__offload_myoLoadLibrary()) {
return;
}
// initialize all devices
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init();
}
// load and initialize MYO library
OFFLOAD_DEBUG_TRACE(2, "Initializing MYO library ...\n");
COIEVENT events[MIC_ENGINES_MAX];
MyoiUserParams params[MIC_ENGINES_MAX+1];
// load target library to all devices
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].init_myo(&events[i]);
params[i].type = MYOI_USERPARAMS_DEVID;
params[i].nodeid = mic_engines[i].get_physical_index() + 1;
}
params[mic_engines_total].type = MYOI_USERPARAMS_LAST_MSG;
// initialize myo runtime on host
myo_wrapper.LibInit(params, 0);
// wait for the target init calls to finish
COIRESULT res;
res = COI::EventWait(mic_engines_total, events, -1, 1, 0, 0);
if (res != COI_SUCCESS) {
LIBOFFLOAD_ERROR(c_event_wait, res);
exit(1);
}
myo_is_available = true;
OFFLOAD_DEBUG_TRACE(2, "Initializing MYO library ... done\n");
}
static bool __offload_myoInit(void)
{
static OffloadOnceControl ctrl = OFFLOAD_ONCE_CONTROL_INIT;
__offload_run_once(&ctrl, __offload_myoInit_once);
// register pending shared var tables
if (myo_is_available && __myo_tables) {
mutex_locker_t locker(__myo_table_lock);
if (__myo_tables) {
// Register tables with MYO so it can propagate to target.
for(MyoTableList::const_iterator it = __myo_table_list.begin();
it != __myo_table_list.end(); ++it) {
#ifdef TARGET_WINNT
for (SharedTableEntry *entry = it->var_tab;
entry->varName != MYO_TABLE_END_MARKER(); entry++) {
if (entry->varName == 0) {
continue;
}
myo_wrapper.HostVarTablePropagate(entry, 1);
}
#else // TARGET_WINNT
myo_wrapper.HostVarTablePropagate(it->var_tab,
it->var_tab_len);
#endif // TARGET_WINNT
}
__myo_table_list.clear();
__myo_tables = false;
}
}
return myo_is_available;
}
static bool shared_table_entries(
SharedTableEntry *entry
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
for (; entry->varName != MYO_TABLE_END_MARKER(); entry++) {
#ifdef TARGET_WINNT
if (entry->varName == 0) {
continue;
}
#endif // TARGET_WINNT
return true;
}
return false;
}
static bool fptr_table_entries(
FptrTableEntry *entry
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) {
#ifdef TARGET_WINNT
if (entry->funcName == 0) {
continue;
}
#endif // TARGET_WINNT
return true;
}
return false;
}
extern "C" void __offload_myoRegisterTables(
InitTableEntry* init_table,
SharedTableEntry *shared_table,
FptrTableEntry *fptr_table
)
{
// check whether we need to initialize MYO library. It is
// initialized only if at least one myo table is not empty
if (shared_table_entries(shared_table) || fptr_table_entries(fptr_table)) {
// make sure myo library is loaded
__offload_myoLoadLibrary();
// register tables
__offload_myo_shared_table_register(shared_table);
__offload_myo_fptr_table_register(fptr_table);
__offload_myo_shared_init_table_register(init_table);
}
}
void __offload_myoFini(void)
{
if (myo_is_available) {
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
COIEVENT events[MIC_ENGINES_MAX];
// kick off myoiLibFini calls on all devices
for (int i = 0; i < mic_engines_total; i++) {
mic_engines[i].fini_myo(&events[i]);
}
// cleanup myo runtime on host
myo_wrapper.LibFini();
// wait for the target fini calls to finish
COIRESULT res;
res = COI::EventWait(mic_engines_total, events, -1, 1, 0, 0);
if (res != COI_SUCCESS) {
LIBOFFLOAD_ERROR(c_event_wait, res);
exit(1);
}
}
}
static void __offload_myo_shared_table_register(
SharedTableEntry *entry
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
SharedTableEntry *start = entry;
int entries = 0;
// allocate shared memory for vars
for (; entry->varName != MYO_TABLE_END_MARKER(); entry++) {
#ifdef TARGET_WINNT
if (entry->varName == 0) {
OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoSharedTable entry\n");
continue;
}
#endif // TARGET_WINNT
OFFLOAD_DEBUG_TRACE(4, "registering MyoSharedTable entry for %s @%p\n",
entry->varName, entry);
// Invoke the function to create shared memory
reinterpret_cast<void(*)(void)>(entry->sharedAddr)();
entries++;
}
// and table to the list if it is not empty
if (entries > 0) {
mutex_locker_t locker(__myo_table_lock);
__myo_table_list.push_back(MyoTable(start, entries));
__myo_tables = true;
}
}
static void __offload_myo_shared_init_table_register(InitTableEntry* entry)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
#ifdef TARGET_WINNT
for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) {
if (entry->funcName == 0) {
OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoSharedInit entry\n");
continue;
}
// Invoke the function to init the shared memory
entry->func();
}
#else // TARGET_WINNT
for (; entry->func != 0; entry++) {
// Invoke the function to init the shared memory
entry->func();
}
#endif // TARGET_WINNT
}
static void __offload_myo_fptr_table_register(
FptrTableEntry *entry
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
FptrTableEntry *start = entry;
int entries = 0;
for (; entry->funcName != MYO_TABLE_END_MARKER(); entry++) {
#ifdef TARGET_WINNT
if (entry->funcName == 0) {
OFFLOAD_DEBUG_TRACE(4, "skip registering a NULL MyoFptrTable entry\n");
continue;
}
#endif // TARGET_WINNT
if (!myo_wrapper.is_available()) {
*(static_cast<void**>(entry->localThunkAddr)) = entry->funcAddr;
}
OFFLOAD_DEBUG_TRACE(4, "registering MyoFptrTable entry for %s @%p\n",
entry->funcName, entry);
#ifdef TARGET_WINNT
if (myo_wrapper.is_available()) {
myo_wrapper.HostFptrTableRegister(entry, 1, false);
}
#endif // TARGET_WINNT
entries++;
}
#ifndef TARGET_WINNT
if (myo_wrapper.is_available() && entries > 0) {
myo_wrapper.HostFptrTableRegister(start, entries, false);
}
#endif // TARGET_WINNT
}
extern "C" int __offload_myoIsAvailable(int target_number)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%d)\n", __func__, target_number);
if (target_number >= -2) {
bool is_default_number = (target_number == -2);
if (__offload_myoInit()) {
if (target_number >= 0) {
// User provided the device number
int num = target_number % mic_engines_total;
// reserve device in ORSL
target_number = ORSL::reserve(num) ? num : -1;
}
else {
// try to use device 0
target_number = ORSL::reserve(0) ? 0 : -1;
}
// make sure device is initialized
if (target_number >= 0) {
mic_engines[target_number].init();
}
}
else {
// fallback to CPU
target_number = -1;
}
if (target_number < 0 && !is_default_number) {
LIBOFFLOAD_ERROR(c_device_is_not_available);
exit(1);
}
}
else {
LIBOFFLOAD_ERROR(c_invalid_device_number);
exit(1);
}
return target_number;
}
extern "C" void __offload_myoiRemoteIThunkCall(
void *thunk,
void *arg,
int target_number
)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p, %p, %d)\n", __func__, thunk, arg,
target_number);
myo_wrapper.Release();
myo_wrapper.RemoteThunkCall(thunk, arg, target_number);
myo_wrapper.Acquire();
ORSL::release(target_number);
}
extern "C" void* _Offload_shared_malloc(size_t size)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%lld)\n", __func__, size);
if (__offload_myoLoadLibrary()) {
return myo_wrapper.SharedMalloc(size);
}
else {
return malloc(size);
}
}
extern "C" void _Offload_shared_free(void *ptr)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr);
if (__offload_myoLoadLibrary()) {
myo_wrapper.SharedFree(ptr);
}
else {
free(ptr);
}
}
extern "C" void* _Offload_shared_aligned_malloc(size_t size, size_t align)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%lld, %lld)\n", __func__, size, align);
if (__offload_myoLoadLibrary()) {
return myo_wrapper.SharedAlignedMalloc(size, align);
}
else {
if (align < sizeof(void*)) {
align = sizeof(void*);
}
return _mm_malloc(size, align);
}
}
extern "C" void _Offload_shared_aligned_free(void *ptr)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr);
if (__offload_myoLoadLibrary()) {
myo_wrapper.SharedAlignedFree(ptr);
}
else {
_mm_free(ptr);
}
}
extern "C" void __intel_cilk_for_32_offload(
int size,
void (*copy_constructor)(void*, void*),
int target_number,
void *raddr,
void *closure_object,
unsigned int iters,
unsigned int grain_size)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
target_number = __offload_myoIsAvailable(target_number);
if (target_number >= 0) {
struct S {
void *M1;
unsigned int M2;
unsigned int M3;
char closure[];
} *args;
args = (struct S*) _Offload_shared_malloc(sizeof(struct S) + size);
args->M1 = raddr;
args->M2 = iters;
args->M3 = grain_size;
if (copy_constructor == 0) {
memcpy(args->closure, closure_object, size);
}
else {
copy_constructor(args->closure, closure_object);
}
myo_wrapper.Release();
myo_wrapper.GetResult(
myo_wrapper.RemoteCall("__intel_cilk_for_32_offload",
args, target_number)
);
myo_wrapper.Acquire();
_Offload_shared_free(args);
ORSL::release(target_number);
}
else {
__cilkrts_cilk_for_32(raddr,
closure_object,
iters,
grain_size);
}
}
extern "C" void __intel_cilk_for_64_offload(
int size,
void (*copy_constructor)(void*, void*),
int target_number,
void *raddr,
void *closure_object,
uint64_t iters,
uint64_t grain_size)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
target_number = __offload_myoIsAvailable(target_number);
if (target_number >= 0) {
struct S {
void *M1;
uint64_t M2;
uint64_t M3;
char closure[];
} *args;
args = (struct S*) _Offload_shared_malloc(sizeof(struct S) + size);
args->M1 = raddr;
args->M2 = iters;
args->M3 = grain_size;
if (copy_constructor == 0) {
memcpy(args->closure, closure_object, size);
}
else {
copy_constructor(args->closure, closure_object);
}
myo_wrapper.Release();
myo_wrapper.GetResult(
myo_wrapper.RemoteCall("__intel_cilk_for_64_offload", args,
target_number)
);
myo_wrapper.Acquire();
_Offload_shared_free(args);
ORSL::release(target_number);
}
else {
__cilkrts_cilk_for_64(raddr,
closure_object,
iters,
grain_size);
}
}
+80
View File
@@ -0,0 +1,80 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_MYO_HOST_H_INCLUDED
#define OFFLOAD_MYO_HOST_H_INCLUDED
#include <myotypes.h>
#include <myoimpl.h>
#include <myo.h>
#include "offload.h"
typedef MyoiSharedVarEntry SharedTableEntry;
//typedef MyoiHostSharedFptrEntry FptrTableEntry;
typedef struct {
//! Function Name
const char *funcName;
//! Function Address
void *funcAddr;
//! Local Thunk Address
void *localThunkAddr;
#ifdef TARGET_WINNT
// Dummy to pad up to 32 bytes
void *dummy;
#endif // TARGET_WINNT
} FptrTableEntry;
struct InitTableEntry {
#ifdef TARGET_WINNT
// Dummy to pad up to 16 bytes
// Function Name
const char *funcName;
#endif // TARGET_WINNT
void (*func)(void);
};
#ifdef TARGET_WINNT
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_START ".MyoSharedTable$a"
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_END ".MyoSharedTable$z"
#define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START ".MyoSharedInitTable$a"
#define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END ".MyoSharedInitTable$z"
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_START ".MyoFptrTable$a"
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_END ".MyoFptrTable$z"
#else // TARGET_WINNT
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_START ".MyoSharedTable."
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_END ".MyoSharedTable."
#define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START ".MyoSharedInitTable."
#define OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END ".MyoSharedInitTable."
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_START ".MyoFptrTable."
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_END ".MyoFptrTable."
#endif // TARGET_WINNT
#pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_END, read, write)
#pragma section(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END, read, write)
#pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_END, read, write)
extern "C" void __offload_myoRegisterTables(
InitTableEntry *init_table,
SharedTableEntry *shared_table,
FptrTableEntry *fptr_table
);
extern void __offload_myoFini(void);
#endif // OFFLOAD_MYO_HOST_H_INCLUDED
+184
View File
@@ -0,0 +1,184 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_myo_target.h"
#include "offload_target.h"
extern "C" void __cilkrts_cilk_for_32(void*, void*, uint32_t, int32_t);
extern "C" void __cilkrts_cilk_for_64(void*, void*, uint64_t, int32_t);
#pragma weak __cilkrts_cilk_for_32
#pragma weak __cilkrts_cilk_for_64
static void CheckResult(const char *func, MyoError error) {
if (error != MYO_SUCCESS) {
LIBOFFLOAD_ERROR(c_myotarget_checkresult, func, error);
exit(1);
}
}
static void __offload_myo_shared_table_register(SharedTableEntry *entry)
{
int entries = 0;
SharedTableEntry *t_start;
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
t_start = entry;
while (t_start->varName != 0) {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_mic_myo_shared,
"myo shared entry name = \"%s\" addr = %p\n",
t_start->varName, t_start->sharedAddr);
t_start++;
entries++;
}
if (entries > 0) {
OFFLOAD_DEBUG_TRACE(3, "myoiMicVarTableRegister(%p, %d)\n", entry,
entries);
CheckResult("myoiMicVarTableRegister",
myoiMicVarTableRegister(entry, entries));
}
}
static void __offload_myo_fptr_table_register(
FptrTableEntry *entry
)
{
int entries = 0;
FptrTableEntry *t_start;
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, entry);
t_start = entry;
while (t_start->funcName != 0) {
OFFLOAD_DEBUG_TRACE_1(4, 0, c_offload_mic_myo_fptr,
"myo fptr entry name = \"%s\" addr = %p\n",
t_start->funcName, t_start->funcAddr);
t_start++;
entries++;
}
if (entries > 0) {
OFFLOAD_DEBUG_TRACE(3, "myoiTargetFptrTableRegister(%p, %d, 0)\n",
entry, entries);
CheckResult("myoiTargetFptrTableRegister",
myoiTargetFptrTableRegister(entry, entries, 0));
}
}
extern "C" void __offload_myoAcquire(void)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
CheckResult("myoAcquire", myoAcquire());
}
extern "C" void __offload_myoRelease(void)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
CheckResult("myoRelease", myoRelease());
}
extern "C" void __intel_cilk_for_32_offload_wrapper(void *args_)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
struct S {
void *M1;
unsigned int M2;
unsigned int M3;
char closure[];
} *args = (struct S*) args_;
__cilkrts_cilk_for_32(args->M1, args->closure, args->M2, args->M3);
}
extern "C" void __intel_cilk_for_64_offload_wrapper(void *args_)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
struct S {
void *M1;
uint64_t M2;
uint64_t M3;
char closure[];
} *args = (struct S*) args_;
__cilkrts_cilk_for_64(args->M1, args->closure, args->M2, args->M3);
}
static void __offload_myo_once_init(void)
{
CheckResult("myoiRemoteFuncRegister",
myoiRemoteFuncRegister(
(MyoiRemoteFuncType) __intel_cilk_for_32_offload_wrapper,
"__intel_cilk_for_32_offload"));
CheckResult("myoiRemoteFuncRegister",
myoiRemoteFuncRegister(
(MyoiRemoteFuncType) __intel_cilk_for_64_offload_wrapper,
"__intel_cilk_for_64_offload"));
}
extern "C" void __offload_myoRegisterTables(
SharedTableEntry *shared_table,
FptrTableEntry *fptr_table
)
{
OFFLOAD_DEBUG_TRACE(3, "%s\n", __func__);
// one time registration of Intel(R) Cilk(TM) language entries
static pthread_once_t once_control = PTHREAD_ONCE_INIT;
pthread_once(&once_control, __offload_myo_once_init);
// register module's tables
if (shared_table->varName == 0 && fptr_table->funcName == 0) {
return;
}
__offload_myo_shared_table_register(shared_table);
__offload_myo_fptr_table_register(fptr_table);
}
extern "C" void* _Offload_shared_malloc(size_t size)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%lld)\n", __func__, size);
return myoSharedMalloc(size);
}
extern "C" void _Offload_shared_free(void *ptr)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr);
myoSharedFree(ptr);
}
extern "C" void* _Offload_shared_aligned_malloc(size_t size, size_t align)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%lld, %lld)\n", __func__, size, align);
return myoSharedAlignedMalloc(size, align);
}
extern "C" void _Offload_shared_aligned_free(void *ptr)
{
OFFLOAD_DEBUG_TRACE(3, "%s(%p)\n", __func__, ptr);
myoSharedAlignedFree(ptr);
}
// temporary workaround for blocking behavior of myoiLibInit/Fini calls
extern "C" void __offload_myoLibInit()
{
OFFLOAD_DEBUG_TRACE(3, "%s()\n", __func__);
CheckResult("myoiLibInit", myoiLibInit(0, 0));
}
extern "C" void __offload_myoLibFini()
{
OFFLOAD_DEBUG_TRACE(3, "%s()\n", __func__);
myoiLibFini();
}
+54
View File
@@ -0,0 +1,54 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_MYO_TARGET_H_INCLUDED
#define OFFLOAD_MYO_TARGET_H_INCLUDED
#include <myotypes.h>
#include <myoimpl.h>
#include <myo.h>
#include "offload.h"
typedef MyoiSharedVarEntry SharedTableEntry;
typedef MyoiTargetSharedFptrEntry FptrTableEntry;
#ifdef TARGET_WINNT
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_START ".MyoSharedTable$a"
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_END ".MyoSharedTable$z"
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_START ".MyoFptrTable$a"
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_END ".MyoFptrTable$z"
#else // TARGET_WINNT
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_START ".MyoSharedTable."
#define OFFLOAD_MYO_SHARED_TABLE_SECTION_END ".MyoSharedTable."
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_START ".MyoFptrTable."
#define OFFLOAD_MYO_FPTR_TABLE_SECTION_END ".MyoFptrTable."
#endif // TARGET_WINNT
#pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_MYO_SHARED_TABLE_SECTION_END, read, write)
#pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_MYO_FPTR_TABLE_SECTION_END, read, write)
extern "C" void __offload_myoRegisterTables(
SharedTableEntry *shared_table,
FptrTableEntry *fptr_table
);
extern "C" void __offload_myoAcquire(void);
extern "C" void __offload_myoRelease(void);
// temporary workaround for blocking behavior for myoiLibInit/Fini calls
extern "C" void __offload_myoLibInit();
extern "C" void __offload_myoLibFini();
#endif // OFFLOAD_MYO_TARGET_H_INCLUDED
+851
View File
@@ -0,0 +1,851 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <omp.h>
#include "offload.h"
#include "compiler_if_host.h"
// OpenMP API
void omp_set_default_device(int num)
{
if (num >= 0) {
__omp_device_num = num;
}
}
int omp_get_default_device(void)
{
return __omp_device_num;
}
int omp_get_num_devices()
{
__offload_init_library();
return mic_engines_total;
}
// OpenMP API wrappers
static void omp_set_int_target(
TARGET_TYPE target_type,
int target_number,
int setting,
const char* f_name
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
f_name, 0);
if (ofld) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(int);
vars[0].count = 1;
vars[0].ptr = &setting;
OFFLOAD_OFFLOAD(ofld, f_name, 0, 1, vars, NULL, 0, 0, 0);
}
}
static int omp_get_int_target(
TARGET_TYPE target_type,
int target_number,
const char * f_name
)
{
int setting = 0;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
f_name, 0);
if (ofld) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_out;
vars[0].size = sizeof(int);
vars[0].count = 1;
vars[0].ptr = &setting;
OFFLOAD_OFFLOAD(ofld, f_name, 0, 1, vars, NULL, 0, 0, 0);
}
return setting;
}
void omp_set_num_threads_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
)
{
omp_set_int_target(target_type, target_number, num_threads,
"omp_set_num_threads_target");
}
int omp_get_max_threads_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"omp_get_max_threads_target");
}
int omp_get_num_procs_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"omp_get_num_procs_target");
}
void omp_set_dynamic_target(
TARGET_TYPE target_type,
int target_number,
int num_threads
)
{
omp_set_int_target(target_type, target_number, num_threads,
"omp_set_dynamic_target");
}
int omp_get_dynamic_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"omp_get_dynamic_target");
}
void omp_set_nested_target(
TARGET_TYPE target_type,
int target_number,
int nested
)
{
omp_set_int_target(target_type, target_number, nested,
"omp_set_nested_target");
}
int omp_get_nested_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"omp_get_nested_target");
}
void omp_set_schedule_target(
TARGET_TYPE target_type,
int target_number,
omp_sched_t kind,
int modifier
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(omp_sched_t);
vars[0].count = 1;
vars[0].ptr = &kind;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_in;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = &modifier;
OFFLOAD_OFFLOAD(ofld, "omp_set_schedule_target",
0, 2, vars, NULL, 0, 0, 0);
}
}
void omp_get_schedule_target(
TARGET_TYPE target_type,
int target_number,
omp_sched_t *kind,
int *modifier
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_out;
vars[0].size = sizeof(omp_sched_t);
vars[0].count = 1;
vars[0].ptr = kind;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_out;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = modifier;
OFFLOAD_OFFLOAD(ofld, "omp_get_schedule_target",
0, 2, vars, NULL, 0, 0, 0);
}
}
// lock API functions
void omp_init_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_out;
vars[0].size = sizeof(omp_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_init_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_destroy_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(omp_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_destroy_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_set_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_set_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_unset_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_unset_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
int omp_test_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_lock_target_t *lock
)
{
int result = 0;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_out;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "omp_test_lock_target",
0, 2, vars, NULL, 0, 0, 0);
}
return result;
}
// nested lock API functions
void omp_init_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_out;
vars[0].size = sizeof(omp_nest_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_init_nest_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_destroy_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(omp_nest_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_destroy_nest_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_set_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_nest_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_set_nest_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void omp_unset_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_nest_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
OFFLOAD_OFFLOAD(ofld, "omp_unset_nest_lock_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
int omp_test_nest_lock_target(
TARGET_TYPE target_type,
int target_number,
omp_nest_lock_target_t *lock
)
{
int result = 0;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(omp_nest_lock_target_t);
vars[0].count = 1;
vars[0].ptr = lock;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_out;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "omp_test_nest_lock_target",
0, 2, vars, NULL, 0, 0, 0);
}
return result;
}
// kmp API functions
void kmp_set_stacksize_target(
TARGET_TYPE target_type,
int target_number,
int size
)
{
omp_set_int_target(target_type, target_number, size,
"kmp_set_stacksize_target");
}
int kmp_get_stacksize_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"kmp_get_stacksize_target");
}
void kmp_set_stacksize_s_target(
TARGET_TYPE target_type,
int target_number,
size_t size
)
{
omp_set_int_target(target_type, target_number, size,
"kmp_set_stacksize_s_target");
}
size_t kmp_get_stacksize_s_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"kmp_get_stacksize_s_target");
}
void kmp_set_blocktime_target(
TARGET_TYPE target_type,
int target_number,
int time
)
{
omp_set_int_target(target_type, target_number, time,
"kmp_set_blocktime_target");
}
int kmp_get_blocktime_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"kmp_get_blocktime_target");
}
void kmp_set_library_serial_target(
TARGET_TYPE target_type,
int target_number
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
OFFLOAD_OFFLOAD(ofld, "kmp_set_library_serial_target",
0, 0, 0, 0, 0, 0, 0);
}
}
void kmp_set_library_turnaround_target(
TARGET_TYPE target_type,
int target_number
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
OFFLOAD_OFFLOAD(ofld, "kmp_set_library_turnaround_target",
0, 0, 0, 0, 0, 0, 0);
}
}
void kmp_set_library_throughput_target(
TARGET_TYPE target_type,
int target_number
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
OFFLOAD_OFFLOAD(ofld, "kmp_set_library_throughput_target",
0, 0, 0, 0, 0, 0, 0);
}
}
void kmp_set_library_target(
TARGET_TYPE target_type,
int target_number,
int mode
)
{
omp_set_int_target(target_type, target_number, mode,
"kmp_set_library_target");
}
int kmp_get_library_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"kmp_get_library_target");
}
void kmp_set_defaults_target(
TARGET_TYPE target_type,
int target_number,
char const *defaults
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_string_ptr;
vars[0].type.dst = c_string_ptr;
vars[0].direction.bits = c_parameter_in;
vars[0].alloc_if = 1;
vars[0].free_if = 1;
vars[0].ptr = &defaults;
OFFLOAD_OFFLOAD(ofld, "kmp_set_defaults_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
// affinity API functions
void kmp_create_affinity_mask_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_out;
vars[0].size = sizeof(kmp_affinity_mask_target_t);
vars[0].count = 1;
vars[0].ptr = mask;
OFFLOAD_OFFLOAD(ofld, "kmp_create_affinity_mask_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
void kmp_destroy_affinity_mask_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
)
{
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[1] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(kmp_affinity_mask_target_t);
vars[0].count = 1;
vars[0].ptr = mask;
OFFLOAD_OFFLOAD(ofld, "kmp_destroy_affinity_mask_target",
0, 1, vars, NULL, 0, 0, 0);
}
}
int kmp_set_affinity_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
)
{
int result = 1;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(kmp_affinity_mask_target_t);
vars[0].count = 1;
vars[0].ptr = mask;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_out;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "kmp_set_affinity_target",
0, 2, vars, NULL, 0, 0, 0);
}
return result;
}
int kmp_get_affinity_target(
TARGET_TYPE target_type,
int target_number,
kmp_affinity_mask_target_t *mask
)
{
int result = 1;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[2] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_inout;
vars[0].size = sizeof(kmp_affinity_mask_target_t);
vars[0].count = 1;
vars[0].ptr = mask;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_out;
vars[1].size = sizeof(int);
vars[1].count = 1;
vars[1].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "kmp_get_affinity_target",
0, 2, vars, NULL, 0, 0, 0);
}
return result;
}
int kmp_get_affinity_max_proc_target(
TARGET_TYPE target_type,
int target_number
)
{
return omp_get_int_target(target_type, target_number,
"kmp_get_affinity_max_proc_target");
}
int kmp_set_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
)
{
int result = 1;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[3] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(int);
vars[0].count = 1;
vars[0].ptr = &proc;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_inout;
vars[1].size = sizeof(kmp_affinity_mask_target_t);
vars[1].count = 1;
vars[1].ptr = mask;
vars[2].type.src = c_data;
vars[2].type.dst = c_data;
vars[2].direction.bits = c_parameter_out;
vars[2].size = sizeof(int);
vars[2].count = 1;
vars[2].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "kmp_set_affinity_mask_proc_target",
0, 3, vars, NULL, 0, 0, 0);
}
return result;
}
int kmp_unset_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
)
{
int result = 1;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[3] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(int);
vars[0].count = 1;
vars[0].ptr = &proc;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_inout;
vars[1].size = sizeof(kmp_affinity_mask_target_t);
vars[1].count = 1;
vars[1].ptr = mask;
vars[2].type.src = c_data;
vars[2].type.dst = c_data;
vars[2].direction.bits = c_parameter_out;
vars[2].size = sizeof(int);
vars[2].count = 1;
vars[2].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "kmp_unset_affinity_mask_proc_target",
0, 3, vars, NULL, 0, 0, 0);
}
return result;
}
int kmp_get_affinity_mask_proc_target(
TARGET_TYPE target_type,
int target_number,
int proc,
kmp_affinity_mask_target_t *mask
)
{
int result = 1;
OFFLOAD ofld = OFFLOAD_TARGET_ACQUIRE(target_type, target_number, 0, NULL,
__func__, 0);
if (ofld != 0) {
VarDesc vars[3] = {0};
vars[0].type.src = c_data;
vars[0].type.dst = c_data;
vars[0].direction.bits = c_parameter_in;
vars[0].size = sizeof(int);
vars[0].count = 1;
vars[0].ptr = &proc;
vars[1].type.src = c_data;
vars[1].type.dst = c_data;
vars[1].direction.bits = c_parameter_in;
vars[1].size = sizeof(kmp_affinity_mask_target_t);
vars[1].count = 1;
vars[1].ptr = mask;
vars[2].type.src = c_data;
vars[2].type.dst = c_data;
vars[2].direction.bits = c_parameter_out;
vars[2].size = sizeof(int);
vars[2].count = 1;
vars[2].ptr = &result;
OFFLOAD_OFFLOAD(ofld, "kmp_get_affinity_mask_proc_target",
0, 3, vars, NULL, 0, 0, 0);
}
return result;
}
File diff suppressed because it is too large Load Diff
+84
View File
@@ -0,0 +1,84 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_orsl.h"
#include <stdlib.h>
#include "offload_host.h"
#include "orsl-lite/include/orsl-lite.h"
namespace ORSL {
static bool is_enabled = false;
static const ORSLTag my_tag = "Offload";
void init()
{
const char *env_var = getenv("OFFLOAD_ENABLE_ORSL");
if (env_var != 0 && *env_var != '\0') {
int64_t new_val;
if (__offload_parse_int_string(env_var, new_val)) {
is_enabled = new_val;
}
else {
LIBOFFLOAD_ERROR(c_invalid_env_var_int_value,
"OFFLOAD_ENABLE_ORSL");
}
}
if (is_enabled) {
OFFLOAD_DEBUG_TRACE(2, "ORSL is enabled\n");
}
else {
OFFLOAD_DEBUG_TRACE(2, "ORSL is disabled\n");
}
}
bool reserve(int device)
{
if (is_enabled) {
int pnum = mic_engines[device].get_physical_index();
ORSLBusySet bset;
bset.type = BUSY_SET_FULL;
if (ORSLReserve(1, &pnum, &bset, my_tag) != 0) {
return false;
}
}
return true;
}
bool try_reserve(int device)
{
if (is_enabled) {
int pnum = mic_engines[device].get_physical_index();
ORSLBusySet bset;
bset.type = BUSY_SET_FULL;
if (ORSLTryReserve(1, &pnum, &bset, my_tag) != 0) {
return false;
}
}
return true;
}
void release(int device)
{
if (is_enabled) {
int pnum = mic_engines[device].get_physical_index();
ORSLBusySet bset;
bset.type = BUSY_SET_FULL;
if (ORSLRelease(1, &pnum, &bset, my_tag) != 0) {
// should never get here
}
}
}
} // namespace ORSL
+25
View File
@@ -0,0 +1,25 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_ORSL_H_INCLUDED
#define OFFLOAD_ORSL_H_INCLUDED
// ORSL interface
namespace ORSL {
extern void init();
extern bool reserve(int device);
extern bool try_reserve(int device);
extern void release(int device);
} // namespace ORSL
#endif // OFFLOAD_ORSL_H_INCLUDED
+375
View File
@@ -0,0 +1,375 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_table.h"
#include "offload_common.h"
#if !HOST_LIBRARY
// Predefined offload entries
extern void omp_set_num_threads_lrb(void*);
extern void omp_get_max_threads_lrb(void*);
extern void omp_get_num_procs_lrb(void*);
extern void omp_set_dynamic_lrb(void*);
extern void omp_get_dynamic_lrb(void*);
extern void omp_set_nested_lrb(void*);
extern void omp_get_nested_lrb(void*);
extern void omp_set_schedule_lrb(void*);
extern void omp_get_schedule_lrb(void*);
extern void omp_init_lock_lrb(void*);
extern void omp_destroy_lock_lrb(void*);
extern void omp_set_lock_lrb(void*);
extern void omp_unset_lock_lrb(void*);
extern void omp_test_lock_lrb(void*);
extern void omp_init_nest_lock_lrb(void*);
extern void omp_destroy_nest_lock_lrb(void*);
extern void omp_set_nest_lock_lrb(void*);
extern void omp_unset_nest_lock_lrb(void*);
extern void omp_test_nest_lock_lrb(void*);
extern void kmp_set_stacksize_lrb(void*);
extern void kmp_get_stacksize_lrb(void*);
extern void kmp_set_stacksize_s_lrb(void*);
extern void kmp_get_stacksize_s_lrb(void*);
extern void kmp_set_blocktime_lrb(void*);
extern void kmp_get_blocktime_lrb(void*);
extern void kmp_set_library_serial_lrb(void*);
extern void kmp_set_library_turnaround_lrb(void*);
extern void kmp_set_library_throughput_lrb(void*);
extern void kmp_set_library_lrb(void*);
extern void kmp_get_library_lrb(void*);
extern void kmp_set_defaults_lrb(void*);
extern void kmp_create_affinity_mask_lrb(void*);
extern void kmp_destroy_affinity_mask_lrb(void*);
extern void kmp_set_affinity_lrb(void*);
extern void kmp_get_affinity_lrb(void*);
extern void kmp_get_affinity_max_proc_lrb(void*);
extern void kmp_set_affinity_mask_proc_lrb(void*);
extern void kmp_unset_affinity_mask_proc_lrb(void*);
extern void kmp_get_affinity_mask_proc_lrb(void*);
// Predefined entries on the target side
static FuncTable::Entry predefined_entries[] = {
"omp_set_num_threads_target",
(void*) &omp_set_num_threads_lrb,
"omp_get_max_threads_target",
(void*) &omp_get_max_threads_lrb,
"omp_get_num_procs_target",
(void*) &omp_get_num_procs_lrb,
"omp_set_dynamic_target",
(void*) &omp_set_dynamic_lrb,
"omp_get_dynamic_target",
(void*) &omp_get_dynamic_lrb,
"omp_set_nested_target",
(void*) &omp_set_nested_lrb,
"omp_get_nested_target",
(void*) &omp_get_nested_lrb,
"omp_set_schedule_target",
(void*) &omp_set_schedule_lrb,
"omp_get_schedule_target",
(void*) &omp_get_schedule_lrb,
"omp_init_lock_target",
(void*) &omp_init_lock_lrb,
"omp_destroy_lock_target",
(void*) &omp_destroy_lock_lrb,
"omp_set_lock_target",
(void*) &omp_set_lock_lrb,
"omp_unset_lock_target",
(void*) &omp_unset_lock_lrb,
"omp_test_lock_target",
(void*) &omp_test_lock_lrb,
"omp_init_nest_lock_target",
(void*) &omp_init_nest_lock_lrb,
"omp_destroy_nest_lock_target",
(void*) &omp_destroy_nest_lock_lrb,
"omp_set_nest_lock_target",
(void*) &omp_set_nest_lock_lrb,
"omp_unset_nest_lock_target",
(void*) &omp_unset_nest_lock_lrb,
"omp_test_nest_lock_target",
(void*) &omp_test_nest_lock_lrb,
"kmp_set_stacksize_target",
(void*) &kmp_set_stacksize_lrb,
"kmp_get_stacksize_target",
(void*) &kmp_get_stacksize_lrb,
"kmp_set_stacksize_s_target",
(void*) &kmp_set_stacksize_s_lrb,
"kmp_get_stacksize_s_target",
(void*) &kmp_get_stacksize_s_lrb,
"kmp_set_blocktime_target",
(void*) &kmp_set_blocktime_lrb,
"kmp_get_blocktime_target",
(void*) &kmp_get_blocktime_lrb,
"kmp_set_library_serial_target",
(void*) &kmp_set_library_serial_lrb,
"kmp_set_library_turnaround_target",
(void*) &kmp_set_library_turnaround_lrb,
"kmp_set_library_throughput_target",
(void*) &kmp_set_library_throughput_lrb,
"kmp_set_library_target",
(void*) &kmp_set_library_lrb,
"kmp_get_library_target",
(void*) &kmp_get_library_lrb,
"kmp_set_defaults_target",
(void*) &kmp_set_defaults_lrb,
"kmp_create_affinity_mask_target",
(void*) &kmp_create_affinity_mask_lrb,
"kmp_destroy_affinity_mask_target",
(void*) &kmp_destroy_affinity_mask_lrb,
"kmp_set_affinity_target",
(void*) &kmp_set_affinity_lrb,
"kmp_get_affinity_target",
(void*) &kmp_get_affinity_lrb,
"kmp_get_affinity_max_proc_target",
(void*) &kmp_get_affinity_max_proc_lrb,
"kmp_set_affinity_mask_proc_target",
(void*) &kmp_set_affinity_mask_proc_lrb,
"kmp_unset_affinity_mask_proc_target",
(void*) &kmp_unset_affinity_mask_proc_lrb,
"kmp_get_affinity_mask_proc_target",
(void*) &kmp_get_affinity_mask_proc_lrb,
(const char*) -1,
(void*) -1
};
static FuncList::Node predefined_table = {
{ predefined_entries, -1 },
0, 0
};
// Entry table
FuncList __offload_entries(&predefined_table);
#else
FuncList __offload_entries;
#endif // !HOST_LIBRARY
// Function table. No predefined entries.
FuncList __offload_funcs;
// Var table
VarList __offload_vars;
// Given the function name returns the associtated function pointer
const void* FuncList::find_addr(const char *name)
{
const void* func = 0;
m_lock.lock();
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0 && strcmp(e->name, name) == 0) {
func = e->func;
break;
}
}
}
m_lock.unlock();
return func;
}
// Given the function pointer returns the associtated function name
const char* FuncList::find_name(const void *func)
{
const char* name = 0;
m_lock.lock();
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->func == func) {
name = e->name;
break;
}
}
}
m_lock.unlock();
return name;
}
// Returns max name length from all tables
int64_t FuncList::max_name_length(void)
{
if (m_max_name_len < 0) {
m_lock.lock();
m_max_name_len = 0;
for (Node *n = m_head; n != 0; n = n->next) {
if (n->table.max_name_len < 0) {
n->table.max_name_len = 0;
// calculate max name length in a single table
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0) {
size_t len = strlen(e->name) + 1;
if (n->table.max_name_len < len) {
n->table.max_name_len = len;
}
}
}
}
// select max from all tables
if (m_max_name_len < n->table.max_name_len) {
m_max_name_len = n->table.max_name_len;
}
}
m_lock.unlock();
}
return m_max_name_len;
}
// Debugging dump
void FuncList::dump(void)
{
OFFLOAD_DEBUG_TRACE(2, "Function table:\n");
m_lock.lock();
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0) {
OFFLOAD_DEBUG_TRACE(2, "%p %s\n", e->func, e->name);
}
}
}
m_lock.unlock();
}
// Debugging dump
void VarList::dump(void)
{
OFFLOAD_DEBUG_TRACE(2, "Var table:\n");
m_lock.lock();
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0) {
#if HOST_LIBRARY
OFFLOAD_DEBUG_TRACE(2, "%s %p %ld\n", e->name, e->addr,
e->size);
#else // HOST_LIBRARY
OFFLOAD_DEBUG_TRACE(2, "%s %p\n", e->name, e->addr);
#endif // HOST_LIBRARY
}
}
}
m_lock.unlock();
}
//
int64_t VarList::table_size(int64_t &nelems)
{
int64_t length = 0;
nelems = 0;
// calculate string table size and number of elements
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0) {
length += strlen(e->name) + 1;
nelems++;
}
}
}
return nelems * sizeof(BufEntry) + length;
}
// copy table to the gven buffer
void VarList::table_copy(void *buf, int64_t nelems)
{
BufEntry* elems = static_cast<BufEntry*>(buf);
char* names = reinterpret_cast<char*>(elems + nelems);
// copy entries to buffer
for (Node *n = m_head; n != 0; n = n->next) {
for (const Table::Entry *e = n->table.entries;
e->name != (const char*) -1; e++) {
if (e->name != 0) {
// name field contains offset to the name from the beginning
// of the buffer
elems->name = names - static_cast<char*>(buf);
elems->addr = reinterpret_cast<intptr_t>(e->addr);
// copy name to string table
const char *name = e->name;
while ((*names++ = *name++) != '\0');
elems++;
}
}
}
}
// patch name offsets in a buffer
void VarList::table_patch_names(void *buf, int64_t nelems)
{
BufEntry* elems = static_cast<BufEntry*>(buf);
for (int i = 0; i < nelems; i++) {
elems[i].name += reinterpret_cast<intptr_t>(buf);
}
}
// Adds given list element to the global lookup table list
extern "C" void __offload_register_tables(
FuncList::Node *entry_table,
FuncList::Node *func_table,
VarList::Node *var_table
)
{
OFFLOAD_DEBUG_TRACE(2, "Registering offload function entry table %p\n",
entry_table);
__offload_entries.add_table(entry_table);
OFFLOAD_DEBUG_TRACE(2, "Registering function table %p\n", func_table);
__offload_funcs.add_table(func_table);
OFFLOAD_DEBUG_TRACE(2, "Registering var table %p\n", var_table);
__offload_vars.add_table(var_table);
}
// Removes given list element from the global lookup table list
extern "C" void __offload_unregister_tables(
FuncList::Node *entry_table,
FuncList::Node *func_table,
VarList::Node *var_table
)
{
__offload_entries.remove_table(entry_table);
OFFLOAD_DEBUG_TRACE(2, "Unregistering function table %p\n", func_table);
__offload_funcs.remove_table(func_table);
OFFLOAD_DEBUG_TRACE(2, "Unregistering var table %p\n", var_table);
__offload_vars.remove_table(var_table);
}
+301
View File
@@ -0,0 +1,301 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
/*! \file
\brief Function and Variable tables used by the runtime library
*/
#ifndef OFFLOAD_TABLE_H_INCLUDED
#define OFFLOAD_TABLE_H_INCLUDED
#include <iterator>
#include "offload_util.h"
// Template representing double linked list of tables
template <typename T> class TableList {
public:
// table type
typedef T Table;
// List node
struct Node {
Table table;
Node* prev;
Node* next;
};
public:
explicit TableList(Node *node = 0) : m_head(node) {}
void add_table(Node *node) {
m_lock.lock();
if (m_head != 0) {
node->next = m_head;
m_head->prev = node;
}
m_head = node;
m_lock.unlock();
}
void remove_table(Node *node) {
m_lock.lock();
if (node->next != 0) {
node->next->prev = node->prev;
}
if (node->prev != 0) {
node->prev->next = node->next;
}
if (m_head == node) {
m_head = node->next;
}
m_lock.unlock();
}
protected:
Node* m_head;
mutex_t m_lock;
};
// Function lookup table.
struct FuncTable {
//! Function table entry
/*! This table contains functions created from offload regions. */
/*! Each entry consists of a pointer to the function's "key"
and the function address. */
/*! Each shared library or executable may contain one such table. */
/*! The end of the table is marked with an entry whose name field
has value -1. */
struct Entry {
const char* name; //!< Name of the function
void* func; //!< Address of the function
};
// entries
const Entry *entries;
// max name length
int64_t max_name_len;
};
// Function table
class FuncList : public TableList<FuncTable> {
public:
explicit FuncList(Node *node = 0) : TableList<Table>(node),
m_max_name_len(-1)
{}
// add table to the list
void add_table(Node *node) {
// recalculate max function name length
m_max_name_len = -1;
// add table
TableList<Table>::add_table(node);
}
// find function address for the given name
const void* find_addr(const char *name);
// find function name for the given address
const char* find_name(const void *addr);
// max name length from all tables in the list
int64_t max_name_length(void);
// debug dump
void dump(void);
private:
// max name length within from all tables
int64_t m_max_name_len;
};
// Table entry for static variables
struct VarTable {
//! Variable table entry
/*! This table contains statically allocated variables marked with
__declspec(target(mic) or #pragma omp declare target. */
/*! Each entry consists of a pointer to the variable's "key",
the variable address and its size in bytes. */
/*! Because memory allocation is done from the host,
the MIC table does not need the size of the variable. */
/*! Padding to make the table entry size a power of 2 is necessary
to avoid "holes" between table contributions from different object
files on Windows when debug information is specified with /Zi. */
struct Entry {
const char* name; //!< Name of the variable
void* addr; //!< Address of the variable
#if HOST_LIBRARY
uint64_t size;
#ifdef TARGET_WINNT
// padding to make entry size a power of 2
uint64_t padding;
#endif // TARGET_WINNT
#endif
};
// Table terminated by an entry with name == -1
const Entry *entries;
};
// List of var tables
class VarList : public TableList<VarTable> {
public:
VarList() : TableList<Table>()
{}
// debug dump
void dump();
public:
// var table list iterator
class Iterator : public std::iterator<std::input_iterator_tag,
Table::Entry> {
public:
Iterator() : m_node(0), m_entry(0) {}
explicit Iterator(Node *node) {
new_node(node);
}
Iterator& operator++() {
if (m_entry != 0) {
m_entry++;
while (m_entry->name == 0) {
m_entry++;
}
if (m_entry->name == reinterpret_cast<const char*>(-1)) {
new_node(m_node->next);
}
}
return *this;
}
bool operator==(const Iterator &other) const {
return m_entry == other.m_entry;
}
bool operator!=(const Iterator &other) const {
return m_entry != other.m_entry;
}
const Table::Entry* operator*() const {
return m_entry;
}
private:
void new_node(Node *node) {
m_node = node;
m_entry = 0;
while (m_node != 0) {
m_entry = m_node->table.entries;
while (m_entry->name == 0) {
m_entry++;
}
if (m_entry->name != reinterpret_cast<const char*>(-1)) {
break;
}
m_node = m_node->next;
m_entry = 0;
}
}
private:
Node *m_node;
const Table::Entry *m_entry;
};
Iterator begin() const {
return Iterator(m_head);
}
Iterator end() const {
return Iterator();
}
public:
// Entry representation in a copy buffer
struct BufEntry {
intptr_t name;
intptr_t addr;
};
// Calculate the number of elements in the table and
// returns the size of buffer for the table
int64_t table_size(int64_t &nelems);
// Copy table contents to given buffer. It is supposed to be large
// enough to hold all elements as string table.
void table_copy(void *buf, int64_t nelems);
// Patch name offsets in a table after it's been copied to other side
static void table_patch_names(void *buf, int64_t nelems);
};
extern FuncList __offload_entries;
extern FuncList __offload_funcs;
extern VarList __offload_vars;
// Section names where the lookup tables are stored
#ifdef TARGET_WINNT
#define OFFLOAD_ENTRY_TABLE_SECTION_START ".OffloadEntryTable$a"
#define OFFLOAD_ENTRY_TABLE_SECTION_END ".OffloadEntryTable$z"
#define OFFLOAD_FUNC_TABLE_SECTION_START ".OffloadFuncTable$a"
#define OFFLOAD_FUNC_TABLE_SECTION_END ".OffloadFuncTable$z"
#define OFFLOAD_VAR_TABLE_SECTION_START ".OffloadVarTable$a"
#define OFFLOAD_VAR_TABLE_SECTION_END ".OffloadVarTable$z"
#define OFFLOAD_CRTINIT_SECTION_START ".CRT$XCT"
#pragma section(OFFLOAD_CRTINIT_SECTION_START, read)
#else // TARGET_WINNT
#define OFFLOAD_ENTRY_TABLE_SECTION_START ".OffloadEntryTable."
#define OFFLOAD_ENTRY_TABLE_SECTION_END ".OffloadEntryTable."
#define OFFLOAD_FUNC_TABLE_SECTION_START ".OffloadFuncTable."
#define OFFLOAD_FUNC_TABLE_SECTION_END ".OffloadFuncTable."
#define OFFLOAD_VAR_TABLE_SECTION_START ".OffloadVarTable."
#define OFFLOAD_VAR_TABLE_SECTION_END ".OffloadVarTable."
#endif // TARGET_WINNT
#pragma section(OFFLOAD_ENTRY_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_ENTRY_TABLE_SECTION_END, read, write)
#pragma section(OFFLOAD_FUNC_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_FUNC_TABLE_SECTION_END, read, write)
#pragma section(OFFLOAD_VAR_TABLE_SECTION_START, read, write)
#pragma section(OFFLOAD_VAR_TABLE_SECTION_END, read, write)
// register/unregister given tables
extern "C" void __offload_register_tables(
FuncList::Node *entry_table,
FuncList::Node *func_table,
VarList::Node *var_table
);
extern "C" void __offload_unregister_tables(
FuncList::Node *entry_table,
FuncList::Node *func_table,
VarList::Node *var_table
);
#endif // OFFLOAD_TABLE_H_INCLUDED
+754
View File
@@ -0,0 +1,754 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_target.h"
#include <stdlib.h>
#include <unistd.h>
#ifdef SEP_SUPPORT
#include <fcntl.h>
#include <sys/ioctl.h>
#endif // SEP_SUPPORT
#include <omp.h>
#include <map>
// typedef offload_func_with_parms.
// Pointer to function that represents an offloaded entry point.
// The parameters are a temporary fix for parameters on the stack.
typedef void (*offload_func_with_parms)(void *);
// Target console and file logging
const char *prefix;
int console_enabled = 0;
int offload_report_level = 0;
// Trace information
static const char* vardesc_direction_as_string[] = {
"NOCOPY",
"IN",
"OUT",
"INOUT"
};
static const char* vardesc_type_as_string[] = {
"unknown",
"data",
"data_ptr",
"func_ptr",
"void_ptr",
"string_ptr",
"dv",
"dv_data",
"dv_data_slice",
"dv_ptr",
"dv_ptr_data",
"dv_ptr_data_slice",
"cean_var",
"cean_var_ptr",
"c_data_ptr_array"
};
int mic_index = -1;
int mic_engines_total = -1;
uint64_t mic_frequency = 0;
int offload_number = 0;
static std::map<void*, RefInfo*> ref_data;
static mutex_t add_ref_lock;
#ifdef SEP_SUPPORT
static const char* sep_monitor_env = "SEP_MONITOR";
static bool sep_monitor = false;
static const char* sep_device_env = "SEP_DEVICE";
static const char* sep_device = "/dev/sep3.8/c";
static int sep_counter = 0;
#define SEP_API_IOC_MAGIC 99
#define SEP_IOCTL_PAUSE _IO (SEP_API_IOC_MAGIC, 31)
#define SEP_IOCTL_RESUME _IO (SEP_API_IOC_MAGIC, 32)
static void add_ref_count(void * buf, bool created)
{
mutex_locker_t locker(add_ref_lock);
RefInfo * info = ref_data[buf];
if (info) {
info->count++;
}
else {
info = new RefInfo((int)created,(long)1);
}
info->is_added |= created;
ref_data[buf] = info;
}
static void BufReleaseRef(void * buf)
{
mutex_locker_t locker(add_ref_lock);
RefInfo * info = ref_data[buf];
if (info) {
--info->count;
if (info->count == 0 && info->is_added) {
BufferReleaseRef(buf);
info->is_added = 0;
}
}
}
static int VTPauseSampling(void)
{
int ret = -1;
int handle = open(sep_device, O_RDWR);
if (handle > 0) {
ret = ioctl(handle, SEP_IOCTL_PAUSE);
close(handle);
}
return ret;
}
static int VTResumeSampling(void)
{
int ret = -1;
int handle = open(sep_device, O_RDWR);
if (handle > 0) {
ret = ioctl(handle, SEP_IOCTL_RESUME);
close(handle);
}
return ret;
}
#endif // SEP_SUPPORT
void OffloadDescriptor::offload(
uint32_t buffer_count,
void** buffers,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
)
{
FunctionDescriptor *func = (FunctionDescriptor*) misc_data;
const char *name = func->data;
OffloadDescriptor ofld;
char *in_data = 0;
char *out_data = 0;
char *timer_data = 0;
console_enabled = func->console_enabled;
timer_enabled = func->timer_enabled;
offload_report_level = func->offload_report_level;
offload_number = func->offload_number;
ofld.set_offload_number(func->offload_number);
#ifdef SEP_SUPPORT
if (sep_monitor) {
if (__sync_fetch_and_add(&sep_counter, 1) == 0) {
OFFLOAD_DEBUG_TRACE(2, "VTResumeSampling\n");
VTResumeSampling();
}
}
#endif // SEP_SUPPORT
OFFLOAD_DEBUG_TRACE_1(2, ofld.get_offload_number(),
c_offload_start_target_func,
"Offload \"%s\" started\n", name);
// initialize timer data
OFFLOAD_TIMER_INIT();
OFFLOAD_TIMER_START(c_offload_target_total_time);
OFFLOAD_TIMER_START(c_offload_target_descriptor_setup);
// get input/output buffer addresses
if (func->in_datalen > 0 || func->out_datalen > 0) {
if (func->data_offset != 0) {
in_data = (char*) misc_data + func->data_offset;
out_data = (char*) return_data;
}
else {
char *inout_buf = (char*) buffers[--buffer_count];
in_data = inout_buf;
out_data = inout_buf;
}
}
// assign variable descriptors
ofld.m_vars_total = func->vars_num;
if (ofld.m_vars_total > 0) {
uint64_t var_data_len = ofld.m_vars_total * sizeof(VarDesc);
ofld.m_vars = (VarDesc*) malloc(var_data_len);
memcpy(ofld.m_vars, in_data, var_data_len);
in_data += var_data_len;
func->in_datalen -= var_data_len;
}
// timer data
if (func->timer_enabled) {
uint64_t timer_data_len = OFFLOAD_TIMER_DATALEN();
timer_data = out_data;
out_data += timer_data_len;
func->out_datalen -= timer_data_len;
}
// init Marshallers
ofld.m_in.init_buffer(in_data, func->in_datalen);
ofld.m_out.init_buffer(out_data, func->out_datalen);
// copy buffers to offload descriptor
std::copy(buffers, buffers + buffer_count,
std::back_inserter(ofld.m_buffers));
OFFLOAD_TIMER_STOP(c_offload_target_descriptor_setup);
// find offload entry address
OFFLOAD_TIMER_START(c_offload_target_func_lookup);
offload_func_with_parms entry = (offload_func_with_parms)
__offload_entries.find_addr(name);
if (entry == NULL) {
#if OFFLOAD_DEBUG > 0
if (console_enabled > 2) {
__offload_entries.dump();
}
#endif
LIBOFFLOAD_ERROR(c_offload_descriptor_offload, name);
exit(1);
}
OFFLOAD_TIMER_STOP(c_offload_target_func_lookup);
OFFLOAD_TIMER_START(c_offload_target_func_time);
// execute offload entry
entry(&ofld);
OFFLOAD_TIMER_STOP(c_offload_target_func_time);
OFFLOAD_TIMER_STOP(c_offload_target_total_time);
// copy timer data to the buffer
OFFLOAD_TIMER_TARGET_DATA(timer_data);
OFFLOAD_DEBUG_TRACE(2, "Offload \"%s\" finished\n", name);
#ifdef SEP_SUPPORT
if (sep_monitor) {
if (__sync_sub_and_fetch(&sep_counter, 1) == 0) {
OFFLOAD_DEBUG_TRACE(2, "VTPauseSampling\n");
VTPauseSampling();
}
}
#endif // SEP_SUPPORT
}
void OffloadDescriptor::merge_var_descs(
VarDesc *vars,
VarDesc2 *vars2,
int vars_total
)
{
// number of variable descriptors received from host and generated
// locally should match
if (m_vars_total < vars_total) {
LIBOFFLOAD_ERROR(c_merge_var_descs1);
exit(1);
}
for (int i = 0; i < m_vars_total; i++) {
if (i < vars_total) {
// variable type must match
if (m_vars[i].type.bits != vars[i].type.bits) {
LIBOFFLOAD_ERROR(c_merge_var_descs2);
exit(1);
}
m_vars[i].ptr = vars[i].ptr;
m_vars[i].into = vars[i].into;
const char *var_sname = "";
if (vars2 != NULL) {
if (vars2[i].sname != NULL) {
var_sname = vars2[i].sname;
}
}
OFFLOAD_DEBUG_TRACE_1(2, get_offload_number(), c_offload_var,
" VarDesc %d, var=%s, %s, %s\n",
i, var_sname,
vardesc_direction_as_string[m_vars[i].direction.bits],
vardesc_type_as_string[m_vars[i].type.src]);
if (vars2 != NULL && vars2[i].dname != NULL) {
OFFLOAD_TRACE(2, " into=%s, %s\n", vars2[i].dname,
vardesc_type_as_string[m_vars[i].type.dst]);
}
}
OFFLOAD_TRACE(2,
" type_src=%d, type_dstn=%d, direction=%d, "
"alloc_if=%d, free_if=%d, align=%d, mic_offset=%d, flags=0x%x, "
"offset=%lld, size=%lld, count/disp=%lld, ptr=%p into=%p\n",
m_vars[i].type.src,
m_vars[i].type.dst,
m_vars[i].direction.bits,
m_vars[i].alloc_if,
m_vars[i].free_if,
m_vars[i].align,
m_vars[i].mic_offset,
m_vars[i].flags.bits,
m_vars[i].offset,
m_vars[i].size,
m_vars[i].count,
m_vars[i].ptr,
m_vars[i].into);
}
}
void OffloadDescriptor::scatter_copyin_data()
{
OFFLOAD_TIMER_START(c_offload_target_scatter_inputs);
OFFLOAD_DEBUG_TRACE(2, "IN buffer @ %p size %lld\n",
m_in.get_buffer_start(),
m_in.get_buffer_size());
OFFLOAD_DEBUG_DUMP_BYTES(2, m_in.get_buffer_start(),
m_in.get_buffer_size());
// receive data
for (int i = 0; i < m_vars_total; i++) {
bool src_is_for_mic = (m_vars[i].direction.out ||
m_vars[i].into == NULL);
void** ptr_addr = src_is_for_mic ?
static_cast<void**>(m_vars[i].ptr) :
static_cast<void**>(m_vars[i].into);
int type = src_is_for_mic ? m_vars[i].type.src :
m_vars[i].type.dst;
bool is_static = src_is_for_mic ?
m_vars[i].flags.is_static :
m_vars[i].flags.is_static_dstn;
void *ptr = NULL;
if (m_vars[i].flags.alloc_disp) {
int64_t offset = 0;
m_in.receive_data(&offset, sizeof(offset));
m_vars[i].offset = -offset;
}
if (VAR_TYPE_IS_DV_DATA_SLICE(type) ||
VAR_TYPE_IS_DV_DATA(type)) {
ArrDesc *dvp = (type == c_dv_data_slice || type == c_dv_data)?
reinterpret_cast<ArrDesc*>(ptr_addr) :
*reinterpret_cast<ArrDesc**>(ptr_addr);
ptr_addr = reinterpret_cast<void**>(&dvp->Base);
}
// Set pointer values
switch (type) {
case c_data_ptr_array:
{
int j = m_vars[i].ptr_arr_offset;
int max_el = j + m_vars[i].count;
char *dst_arr_ptr = (src_is_for_mic)?
*(reinterpret_cast<char**>(m_vars[i].ptr)) :
reinterpret_cast<char*>(m_vars[i].into);
for (; j < max_el; j++) {
if (src_is_for_mic) {
m_vars[j].ptr =
dst_arr_ptr + m_vars[j].ptr_arr_offset;
}
else {
m_vars[j].into =
dst_arr_ptr + m_vars[j].ptr_arr_offset;
}
}
}
break;
case c_data:
case c_void_ptr:
case c_cean_var:
case c_dv:
break;
case c_string_ptr:
case c_data_ptr:
case c_cean_var_ptr:
case c_dv_ptr:
if (m_vars[i].alloc_if) {
void *buf;
if (m_vars[i].flags.sink_addr) {
m_in.receive_data(&buf, sizeof(buf));
}
else {
buf = m_buffers.front();
m_buffers.pop_front();
}
if (buf) {
if (!is_static) {
if (!m_vars[i].flags.sink_addr) {
// increment buffer reference
OFFLOAD_TIMER_START(c_offload_target_add_buffer_refs);
BufferAddRef(buf);
OFFLOAD_TIMER_STOP(c_offload_target_add_buffer_refs);
}
add_ref_count(buf, 0 == m_vars[i].flags.sink_addr);
}
ptr = static_cast<char*>(buf) +
m_vars[i].mic_offset +
(m_vars[i].flags.is_stack_buf ?
0 : m_vars[i].offset);
}
*ptr_addr = ptr;
}
else if (m_vars[i].flags.sink_addr) {
void *buf;
m_in.receive_data(&buf, sizeof(buf));
void *ptr = static_cast<char*>(buf) +
m_vars[i].mic_offset +
(m_vars[i].flags.is_stack_buf ?
0 : m_vars[i].offset);
*ptr_addr = ptr;
}
break;
case c_func_ptr:
break;
case c_dv_data:
case c_dv_ptr_data:
case c_dv_data_slice:
case c_dv_ptr_data_slice:
if (m_vars[i].alloc_if) {
void *buf;
if (m_vars[i].flags.sink_addr) {
m_in.receive_data(&buf, sizeof(buf));
}
else {
buf = m_buffers.front();
m_buffers.pop_front();
}
if (buf) {
if (!is_static) {
if (!m_vars[i].flags.sink_addr) {
// increment buffer reference
OFFLOAD_TIMER_START(c_offload_target_add_buffer_refs);
BufferAddRef(buf);
OFFLOAD_TIMER_STOP(c_offload_target_add_buffer_refs);
}
add_ref_count(buf, 0 == m_vars[i].flags.sink_addr);
}
ptr = static_cast<char*>(buf) +
m_vars[i].mic_offset + m_vars[i].offset;
}
*ptr_addr = ptr;
}
else if (m_vars[i].flags.sink_addr) {
void *buf;
m_in.receive_data(&buf, sizeof(buf));
ptr = static_cast<char*>(buf) +
m_vars[i].mic_offset + m_vars[i].offset;
*ptr_addr = ptr;
}
break;
default:
LIBOFFLOAD_ERROR(c_unknown_var_type, type);
abort();
}
// Release obsolete buffers for stack of persistent objects
if (type = c_data_ptr &&
m_vars[i].flags.is_stack_buf &&
!m_vars[i].direction.bits &&
m_vars[i].alloc_if &&
m_vars[i].size != 0) {
for (int j=0; j < m_vars[i].size; j++) {
void *buf;
m_in.receive_data(&buf, sizeof(buf));
BufferReleaseRef(buf);
ref_data.erase(buf);
}
}
// Do copyin
switch (m_vars[i].type.dst) {
case c_data_ptr_array:
break;
case c_data:
case c_void_ptr:
case c_cean_var:
if (m_vars[i].direction.in &&
!m_vars[i].flags.is_static_dstn) {
int64_t size;
int64_t disp;
char* ptr = m_vars[i].into ?
static_cast<char*>(m_vars[i].into) :
static_cast<char*>(m_vars[i].ptr);
if (m_vars[i].type.dst == c_cean_var) {
m_in.receive_data((&size), sizeof(int64_t));
m_in.receive_data((&disp), sizeof(int64_t));
}
else {
size = m_vars[i].size;
disp = 0;
}
m_in.receive_data(ptr + disp, size);
}
break;
case c_dv:
if (m_vars[i].direction.bits ||
m_vars[i].alloc_if ||
m_vars[i].free_if) {
char* ptr = m_vars[i].into ?
static_cast<char*>(m_vars[i].into) :
static_cast<char*>(m_vars[i].ptr);
m_in.receive_data(ptr + sizeof(uint64_t),
m_vars[i].size - sizeof(uint64_t));
}
break;
case c_string_ptr:
case c_data_ptr:
case c_cean_var_ptr:
case c_dv_ptr:
case c_dv_data:
case c_dv_ptr_data:
case c_dv_data_slice:
case c_dv_ptr_data_slice:
break;
case c_func_ptr:
if (m_vars[i].direction.in) {
m_in.receive_func_ptr((const void**) m_vars[i].ptr);
}
break;
default:
LIBOFFLOAD_ERROR(c_unknown_var_type, m_vars[i].type.dst);
abort();
}
}
OFFLOAD_TRACE(1, "Total copyin data received from host: [%lld] bytes\n",
m_in.get_tfr_size());
OFFLOAD_TIMER_STOP(c_offload_target_scatter_inputs);
OFFLOAD_TIMER_START(c_offload_target_compute);
}
void OffloadDescriptor::gather_copyout_data()
{
OFFLOAD_TIMER_STOP(c_offload_target_compute);
OFFLOAD_TIMER_START(c_offload_target_gather_outputs);
for (int i = 0; i < m_vars_total; i++) {
bool src_is_for_mic = (m_vars[i].direction.out ||
m_vars[i].into == NULL);
switch (m_vars[i].type.src) {
case c_data_ptr_array:
break;
case c_data:
case c_void_ptr:
case c_cean_var:
if (m_vars[i].direction.out &&
!m_vars[i].flags.is_static) {
m_out.send_data(
static_cast<char*>(m_vars[i].ptr) + m_vars[i].disp,
m_vars[i].size);
}
break;
case c_dv:
break;
case c_string_ptr:
case c_data_ptr:
case c_cean_var_ptr:
case c_dv_ptr:
if (m_vars[i].free_if &&
src_is_for_mic &&
!m_vars[i].flags.is_static) {
void *buf = *static_cast<char**>(m_vars[i].ptr) -
m_vars[i].mic_offset -
(m_vars[i].flags.is_stack_buf?
0 : m_vars[i].offset);
if (buf == NULL) {
break;
}
// decrement buffer reference count
OFFLOAD_TIMER_START(c_offload_target_release_buffer_refs);
BufReleaseRef(buf);
OFFLOAD_TIMER_STOP(c_offload_target_release_buffer_refs);
}
break;
case c_func_ptr:
if (m_vars[i].direction.out) {
m_out.send_func_ptr(*((void**) m_vars[i].ptr));
}
break;
case c_dv_data:
case c_dv_ptr_data:
case c_dv_data_slice:
case c_dv_ptr_data_slice:
if (src_is_for_mic &&
m_vars[i].free_if &&
!m_vars[i].flags.is_static) {
ArrDesc *dvp = (m_vars[i].type.src == c_dv_data ||
m_vars[i].type.src == c_dv_data_slice) ?
static_cast<ArrDesc*>(m_vars[i].ptr) :
*static_cast<ArrDesc**>(m_vars[i].ptr);
void *buf = reinterpret_cast<char*>(dvp->Base) -
m_vars[i].mic_offset -
m_vars[i].offset;
if (buf == NULL) {
break;
}
// decrement buffer reference count
OFFLOAD_TIMER_START(c_offload_target_release_buffer_refs);
BufReleaseRef(buf);
OFFLOAD_TIMER_STOP(c_offload_target_release_buffer_refs);
}
break;
default:
LIBOFFLOAD_ERROR(c_unknown_var_type, m_vars[i].type.dst);
abort();
}
if (m_vars[i].into) {
switch (m_vars[i].type.dst) {
case c_data_ptr_array:
break;
case c_data:
case c_void_ptr:
case c_cean_var:
case c_dv:
break;
case c_string_ptr:
case c_data_ptr:
case c_cean_var_ptr:
case c_dv_ptr:
if (m_vars[i].direction.in &&
m_vars[i].free_if &&
!m_vars[i].flags.is_static_dstn) {
void *buf = *static_cast<char**>(m_vars[i].into) -
m_vars[i].mic_offset -
(m_vars[i].flags.is_stack_buf?
0 : m_vars[i].offset);
if (buf == NULL) {
break;
}
// decrement buffer reference count
OFFLOAD_TIMER_START(
c_offload_target_release_buffer_refs);
BufReleaseRef(buf);
OFFLOAD_TIMER_STOP(
c_offload_target_release_buffer_refs);
}
break;
case c_func_ptr:
break;
case c_dv_data:
case c_dv_ptr_data:
case c_dv_data_slice:
case c_dv_ptr_data_slice:
if (m_vars[i].free_if &&
m_vars[i].direction.in &&
!m_vars[i].flags.is_static_dstn) {
ArrDesc *dvp =
(m_vars[i].type.dst == c_dv_data_slice ||
m_vars[i].type.dst == c_dv_data) ?
static_cast<ArrDesc*>(m_vars[i].into) :
*static_cast<ArrDesc**>(m_vars[i].into);
void *buf = reinterpret_cast<char*>(dvp->Base) -
m_vars[i].mic_offset -
m_vars[i].offset;
if (buf == NULL) {
break;
}
// decrement buffer reference count
OFFLOAD_TIMER_START(
c_offload_target_release_buffer_refs);
BufReleaseRef(buf);
OFFLOAD_TIMER_STOP(
c_offload_target_release_buffer_refs);
}
break;
default:
LIBOFFLOAD_ERROR(c_unknown_var_type, m_vars[i].type.dst);
abort();
}
}
}
OFFLOAD_DEBUG_TRACE(2, "OUT buffer @ p %p size %lld\n",
m_out.get_buffer_start(),
m_out.get_buffer_size());
OFFLOAD_DEBUG_DUMP_BYTES(2,
m_out.get_buffer_start(),
m_out.get_buffer_size());
OFFLOAD_DEBUG_TRACE_1(1, get_offload_number(), c_offload_copyout_data,
"Total copyout data sent to host: [%lld] bytes\n",
m_out.get_tfr_size());
OFFLOAD_TIMER_STOP(c_offload_target_gather_outputs);
}
void __offload_target_init(void)
{
#ifdef SEP_SUPPORT
const char* env_var = getenv(sep_monitor_env);
if (env_var != 0 && *env_var != '\0') {
sep_monitor = atoi(env_var);
}
env_var = getenv(sep_device_env);
if (env_var != 0 && *env_var != '\0') {
sep_device = env_var;
}
#endif // SEP_SUPPORT
prefix = report_get_message_str(c_report_mic);
// init frequency
mic_frequency = COIPerfGetCycleFrequency();
}
// User-visible offload API
int _Offload_number_of_devices(void)
{
return mic_engines_total;
}
int _Offload_get_device_number(void)
{
return mic_index;
}
int _Offload_get_physical_device_number(void)
{
uint32_t index;
EngineGetIndex(&index);
return index;
}
+100
View File
@@ -0,0 +1,100 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// The parts of the offload library used only on the target
#ifndef OFFLOAD_TARGET_H_INCLUDED
#define OFFLOAD_TARGET_H_INCLUDED
#include "offload_common.h"
#include "coi/coi_server.h"
// The offload descriptor.
class OffloadDescriptor
{
public:
~OffloadDescriptor() {
if (m_vars != 0) {
free(m_vars);
}
}
// Entry point for COI. Synchronously execute offloaded region given
// the provided buffers, misc and return data.
static void offload(
uint32_t buffer_count,
void** buffers,
void* misc_data,
uint16_t misc_data_len,
void* return_data,
uint16_t return_data_len
);
// scatters input data from in buffer to target variables
void scatter_copyin_data();
// gathers output data to the buffer
void gather_copyout_data();
// merges local variable descriptors with the descriptors received from
// host
void merge_var_descs(VarDesc *vars, VarDesc2 *vars2, int vars_total);
int get_offload_number() const {
return m_offload_number;
}
void set_offload_number(int number) {
m_offload_number = number;
}
private:
// Constructor
OffloadDescriptor() : m_vars(0)
{}
private:
typedef std::list<void*> BufferList;
// The Marshaller for the inputs of the offloaded region.
Marshaller m_in;
// The Marshaller for the outputs of the offloaded region.
Marshaller m_out;
// List of buffers that are passed to dispatch call
BufferList m_buffers;
// Variable descriptors received from host
VarDesc* m_vars;
int m_vars_total;
int m_offload_number;
};
// one time target initialization in main
extern void __offload_target_init(void);
// logical device index
extern int mic_index;
// total number of available logical devices
extern int mic_engines_total;
// device frequency (from COI)
extern uint64_t mic_frequency;
struct RefInfo {
RefInfo(bool is_add, long amount):is_added(is_add),count(amount)
{}
bool is_added;
long count;
};
#endif // OFFLOAD_TARGET_H_INCLUDED
+17
View File
@@ -0,0 +1,17 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
extern "C" void __offload_target_main(void);
int main(int argc, char ** argv)
{
__offload_target_main();
return 0;
}
+172
View File
@@ -0,0 +1,172 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_TIMER_H_INCLUDED
#define OFFLOAD_TIMER_H_INCLUDED
#include <stdio.h>
#include <stdarg.h>
#include <stdint.h>
#include "liboffload_error_codes.h"
extern int timer_enabled;
#ifdef TIMING_SUPPORT
struct OffloadTargetTimerData {
uint64_t frequency;
struct {
uint64_t start;
uint64_t total;
} phases[c_offload_target_max_phase];
};
struct OffloadHostTimerData {
// source file name and line number
const char* file;
int line;
// host timer data
struct {
uint64_t start;
uint64_t total;
} phases[c_offload_host_max_phase];
uint64_t sent_bytes;
uint64_t received_bytes;
int card_number;
int offload_number;
// target timer data
OffloadTargetTimerData target;
// next element
OffloadHostTimerData *next;
};
#if HOST_LIBRARY
extern int offload_report_level;
extern int offload_report_enabled;
#define OFFLOAD_REPORT_1 1
#define OFFLOAD_REPORT_2 2
#define OFFLOAD_REPORT_3 3
#define OFFLOAD_REPORT_ON 1
#define OFFLOAD_REPORT_OFF 0
#define OFFLOAD_TIMER_DATALEN() \
((timer_enabled || (offload_report_level && offload_report_enabled)) ? \
((1 + c_offload_target_max_phase) * sizeof(uint64_t)) : 0)
#define OFFLOAD_TIMER_START(timer_data, pnode) \
if (timer_enabled || \
(offload_report_level && offload_report_enabled)) { \
offload_timer_start(timer_data, pnode); \
}
#define OFFLOAD_TIMER_STOP(timer_data, pnode) \
if (timer_enabled || \
(offload_report_level && offload_report_enabled)) { \
offload_timer_stop(timer_data, pnode); \
}
#define OFFLOAD_TIMER_INIT(file, line) \
offload_timer_init(file, line);
#define OFFLOAD_TIMER_TARGET_DATA(timer_data, data) \
if (timer_enabled || \
(offload_report_level && offload_report_enabled)) { \
offload_timer_fill_target_data(timer_data, data); \
}
#define OFFLOAD_TIMER_HOST_SDATA(timer_data, data) \
if (offload_report_level && offload_report_enabled) { \
offload_timer_fill_host_sdata(timer_data, data); \
}
#define OFFLOAD_TIMER_HOST_RDATA(timer_data, data) \
if (offload_report_level && offload_report_enabled) { \
offload_timer_fill_host_rdata(timer_data, data); \
}
#define OFFLOAD_TIMER_HOST_MIC_NUM(timer_data, data) \
if (offload_report_level && offload_report_enabled) { \
offload_timer_fill_host_mic_num(timer_data, data); \
}
extern void offload_timer_start(OffloadHostTimerData *,
OffloadHostPhase t_node);
extern void offload_timer_stop(OffloadHostTimerData *,
OffloadHostPhase t_node);
extern OffloadHostTimerData * offload_timer_init(const char *file, int line);
extern void offload_timer_fill_target_data(OffloadHostTimerData *,
void *data);
extern void offload_timer_fill_host_sdata(OffloadHostTimerData *,
uint64_t sent_bytes);
extern void offload_timer_fill_host_rdata(OffloadHostTimerData *,
uint64_t sent_bytes);
extern void offload_timer_fill_host_mic_num(OffloadHostTimerData *,
int card_number);
// Utility structure for starting/stopping timer
struct OffloadTimer {
OffloadTimer(OffloadHostTimerData *data, OffloadHostPhase phase) :
m_data(data),
m_phase(phase)
{
OFFLOAD_TIMER_START(m_data, m_phase);
}
~OffloadTimer()
{
OFFLOAD_TIMER_STOP(m_data, m_phase);
}
private:
OffloadHostTimerData* m_data;
OffloadHostPhase m_phase;
};
#else
#define OFFLOAD_TIMER_DATALEN() \
((timer_enabled) ? \
((1 + c_offload_target_max_phase) * sizeof(uint64_t)) : 0)
#define OFFLOAD_TIMER_START(pnode) \
if (timer_enabled) offload_timer_start(pnode);
#define OFFLOAD_TIMER_STOP(pnode) \
if (timer_enabled) offload_timer_stop(pnode);
#define OFFLOAD_TIMER_INIT() \
if (timer_enabled) offload_timer_init();
#define OFFLOAD_TIMER_TARGET_DATA(data) \
if (timer_enabled) offload_timer_fill_target_data(data);
extern void offload_timer_start(OffloadTargetPhase t_node);
extern void offload_timer_stop(OffloadTargetPhase t_node);
extern void offload_timer_init(void);
extern void offload_timer_fill_target_data(void *data);
#endif // HOST_LIBRARY
#else // TIMING_SUPPORT
#define OFFLOAD_TIMER_START(...)
#define OFFLOAD_TIMER_STOP(...)
#define OFFLOAD_TIMER_INIT(...)
#define OFFLOAD_TIMER_TARGET_DATA(...)
#define OFFLOAD_TIMER_DATALEN(...) (0)
#endif // TIMING_SUPPORT
#endif // OFFLOAD_TIMER_H_INCLUDED
+359
View File
@@ -0,0 +1,359 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_timer.h"
#ifdef __INTEL_COMPILER
#include <ia32intrin.h>
#else // __INTEL_COMPILER
#include <x86intrin.h>
#endif // __INTEL_COMPILER
#include "offload_host.h"
#include <sstream>
#include <iostream>
#include <iomanip>
int timer_enabled = 0;
#ifdef TIMING_SUPPORT
int offload_report_level = 0;
int offload_report_enabled = 1;
static const int host_timer_prefix_spaces[] = {
/*c_offload_host_setup_buffers*/ 0,
/*c_offload_host_initialize*/ 2,
/*c_offload_host_target_acquire*/ 2,
/*c_offload_host_wait_deps*/ 2,
/*c_offload_host_setup_buffers*/ 2,
/*c_offload_host_alloc_buffers*/ 4,
/*c_offload_host_setup_misc_data*/ 2,
/*c_offload_host_alloc_data_buffer*/ 4,
/*c_offload_host_send_pointers*/ 2,
/*c_offload_host_gather_inputs*/ 2,
/*c_offload_host_map_in_data_buffer*/ 4,
/*c_offload_host_unmap_in_data_buffer*/ 4,
/*c_offload_host_start_compute*/ 2,
/*c_offload_host_wait_compute*/ 2,
/*c_offload_host_start_buffers_reads*/ 2,
/*c_offload_host_scatter_outputs*/ 2,
/*c_offload_host_map_out_data_buffer*/ 4,
/*c_offload_host_unmap_out_data_buffer*/ 4,
/*c_offload_host_wait_buffers_reads*/ 2,
/*c_offload_host_destroy_buffers*/ 2
};
const static int target_timer_prefix_spaces[] = {
/*c_offload_target_total_time*/ 0,
/*c_offload_target_descriptor_setup*/ 2,
/*c_offload_target_func_lookup*/ 2,
/*c_offload_target_func_time*/ 2,
/*c_offload_target_scatter_inputs*/ 4,
/*c_offload_target_add_buffer_refs*/ 6,
/*c_offload_target_compute*/ 4,
/*c_offload_target_gather_outputs*/ 4,
/*c_offload_target_release_buffer_refs*/ 6
};
static OffloadHostTimerData* timer_data_head;
static OffloadHostTimerData* timer_data_tail;
static mutex_t timer_data_mutex;
static void offload_host_phase_name(std::stringstream &ss, int p_node);
static void offload_target_phase_name(std::stringstream &ss, int p_node);
extern void Offload_Timer_Print(void)
{
std::string buf;
std::stringstream ss;
const char *stars =
"**************************************************************";
ss << "\n\n" << stars << "\n";
ss << " ";
ss << report_get_message_str(c_report_title) << "\n";
ss << stars << "\n";
double frequency = cpu_frequency;
for (OffloadHostTimerData *pnode = timer_data_head;
pnode != 0; pnode = pnode->next) {
ss << " ";
ss << report_get_message_str(c_report_from_file) << " "<< pnode->file;
ss << report_get_message_str(c_report_line) << " " << pnode->line;
ss << "\n";
for (int i = 0; i < c_offload_host_max_phase ; i++) {
ss << " ";
offload_host_phase_name(ss, i);
ss << " " << std::fixed << std::setprecision(5);
ss << (double)pnode->phases[i].total / frequency << "\n";
}
for (int i = 0; i < c_offload_target_max_phase ; i++) {
double time = 0;
if (pnode->target.frequency != 0) {
time = (double) pnode->target.phases[i].total /
(double) pnode->target.frequency;
}
ss << " ";
offload_target_phase_name(ss, i);
ss << " " << std::fixed << std::setprecision(5);
ss << time << "\n";
}
}
buf = ss.str();
fprintf(stdout, buf.data());
fflush(stdout);
}
extern void Offload_Report_Prolog(OffloadHostTimerData *pnode)
{
double frequency = cpu_frequency;
std::string buf;
std::stringstream ss;
if (pnode) {
// [Offload] [Mic 0] [File] file.c
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic) << " ";
ss << pnode->card_number << "] [";
ss << report_get_message_str(c_report_file);
ss << "] " << pnode->file << "\n";
// [Offload] [Mic 0] [Line] 1234
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic) << " ";
ss << pnode->card_number << "] [";
ss << report_get_message_str(c_report_line);
ss << "] " << pnode->line << "\n";
// [Offload] [Mic 0] [Tag] Tag 1
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic) << " ";
ss << pnode->card_number << "] [";
ss << report_get_message_str(c_report_tag);
ss << "] " << report_get_message_str(c_report_tag);
ss << " " << pnode->offload_number << "\n";
buf = ss.str();
fprintf(stdout, buf.data());
fflush(stdout);
}
}
extern void Offload_Report_Epilog(OffloadHostTimerData * timer_data)
{
double frequency = cpu_frequency;
std::string buf;
std::stringstream ss;
OffloadHostTimerData *pnode = timer_data;
if (!pnode) {
return;
}
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_host) << "] [";
ss << report_get_message_str(c_report_tag) << " ";
ss << pnode->offload_number << "] [";
ss << report_get_message_str(c_report_cpu_time) << "] ";
ss << std::fixed << std::setprecision(6);
ss << (double) pnode->phases[0].total / frequency;
ss << report_get_message_str(c_report_seconds) << "\n";
if (offload_report_level >= OFFLOAD_REPORT_2) {
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic);
ss << " " << pnode->card_number;
ss << "] [" << report_get_message_str(c_report_tag) << " ";
ss << pnode->offload_number << "] [";
ss << report_get_message_str(c_report_cpu_to_mic_data) << "] ";
ss << pnode->sent_bytes << " ";
ss << report_get_message_str(c_report_bytes) << "\n";
}
double time = 0;
if (pnode->target.frequency != 0) {
time = (double) pnode->target.phases[0].total /
(double) pnode->target.frequency;
}
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic) << " ";
ss << pnode->card_number<< "] [";
ss << report_get_message_str(c_report_tag) << " ";
ss << pnode->offload_number << "] [";
ss << report_get_message_str(c_report_mic_time) << "] ";
ss << std::fixed << std::setprecision(6) << time;
ss << report_get_message_str(c_report_seconds) << "\n";
if (offload_report_level >= OFFLOAD_REPORT_2) {
ss << "[" << report_get_message_str(c_report_offload) << "] [";
ss << report_get_message_str(c_report_mic);
ss << " " << pnode->card_number;
ss << "] [" << report_get_message_str(c_report_tag) << " ";
ss << pnode->offload_number << "] [";
ss << report_get_message_str(c_report_mic_to_cpu_data) << "] ";
ss << pnode->received_bytes << " ";
ss << report_get_message_str(c_report_bytes) << "\n";
}
ss << "\n";
buf = ss.str();
fprintf(stdout, buf.data());
fflush(stdout);
offload_report_free_data(timer_data);
}
extern void offload_report_free_data(OffloadHostTimerData * timer_data)
{
OffloadHostTimerData *pnode_last = NULL;
for (OffloadHostTimerData *pnode = timer_data_head;
pnode != 0; pnode = pnode->next) {
if (timer_data == pnode) {
if (pnode_last) {
pnode_last->next = pnode->next;
}
else {
timer_data_head = pnode->next;
}
OFFLOAD_FREE(pnode);
break;
}
pnode_last = pnode;
}
}
static void fill_buf_with_spaces(std::stringstream &ss, int num)
{
for (; num > 0; num--) {
ss << " ";
}
}
static void offload_host_phase_name(std::stringstream &ss, int p_node)
{
int prefix_spaces;
int str_length;
int tail_length;
const int message_length = 40;
char const *str;
str = report_get_host_stage_str(p_node);
prefix_spaces = host_timer_prefix_spaces[p_node];
fill_buf_with_spaces(ss, prefix_spaces);
str_length = strlen(str);
ss << str;
tail_length = message_length - prefix_spaces - str_length;
tail_length = tail_length > 0? tail_length : 1;
fill_buf_with_spaces(ss, tail_length);
}
static void offload_target_phase_name(std::stringstream &ss, int p_node)
{
int prefix_spaces;
int str_length;
const int message_length = 40;
int tail_length;
char const *str;
str = report_get_target_stage_str(p_node);
prefix_spaces = target_timer_prefix_spaces[p_node];
fill_buf_with_spaces(ss, prefix_spaces);
str_length = strlen(str);
ss << str;
tail_length = message_length - prefix_spaces - str_length;
tail_length = (tail_length > 0)? tail_length : 1;
fill_buf_with_spaces(ss, tail_length);
}
void offload_timer_start(OffloadHostTimerData * timer_data,
OffloadHostPhase p_type)
{
timer_data->phases[p_type].start = _rdtsc();
}
void offload_timer_stop(OffloadHostTimerData * timer_data,
OffloadHostPhase p_type)
{
timer_data->phases[p_type].total += _rdtsc() -
timer_data->phases[p_type].start;
}
void offload_timer_fill_target_data(OffloadHostTimerData * timer_data,
void *buf)
{
uint64_t *data = (uint64_t*) buf;
timer_data->target.frequency = *data++;
for (int i = 0; i < c_offload_target_max_phase; i++) {
timer_data->target.phases[i].total = *data++;
}
}
void offload_timer_fill_host_sdata(OffloadHostTimerData * timer_data,
uint64_t sent_bytes)
{
if (timer_data) {
timer_data->sent_bytes += sent_bytes;
}
}
void offload_timer_fill_host_rdata(OffloadHostTimerData * timer_data,
uint64_t received_bytes)
{
if (timer_data) {
timer_data->received_bytes += received_bytes;
}
}
void offload_timer_fill_host_mic_num(OffloadHostTimerData * timer_data,
int card_number)
{
if (timer_data) {
timer_data->card_number = card_number;
}
}
OffloadHostTimerData* offload_timer_init(const char *file, int line)
{
static bool first_time = true;
OffloadHostTimerData* timer_data = NULL;
timer_data_mutex.lock();
{
if (timer_enabled ||
(offload_report_level && offload_report_enabled)) {
timer_data = (OffloadHostTimerData*)
OFFLOAD_MALLOC(sizeof(OffloadHostTimerData), 0);
memset(timer_data, 0, sizeof(OffloadHostTimerData));
timer_data->offload_number = OFFLOAD_DEBUG_INCR_OFLD_NUM() - 1;
if (timer_data_head == 0) {
timer_data_head = timer_data;
timer_data_tail = timer_data;
}
else {
timer_data_tail->next = timer_data;
timer_data_tail = timer_data;
}
timer_data->file = file;
timer_data->line = line;
}
}
timer_data_mutex.unlock();
return timer_data;
}
#endif // TIMING_SUPPORT
@@ -0,0 +1,67 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_timer.h"
#include "offload_target.h"
#ifdef __INTEL_COMPILER
#include <ia32intrin.h>
#else // __INTEL_COMPILER
#include <x86intrin.h>
#endif // __INTEL_COMPILER
int timer_enabled = 0;
#ifdef TIMING_SUPPORT
#if defined(LINUX) || defined(FREEBSD)
static __thread OffloadTargetTimerData timer_data;
#else // WINNT
static __declspec(thread) OffloadTargetTimerData timer_data;
#endif // defined(LINUX) || defined(FREEBSD)
void offload_timer_start(
OffloadTargetPhase p_type
)
{
timer_data.phases[p_type].start = _rdtsc();
}
void offload_timer_stop(
OffloadTargetPhase p_type
)
{
timer_data.phases[p_type].total += _rdtsc() -
timer_data.phases[p_type].start;
}
void offload_timer_init()
{
memset(&timer_data, 0, sizeof(OffloadTargetTimerData));
}
void offload_timer_fill_target_data(
void *buf
)
{
uint64_t *data = (uint64_t*) buf;
timer_data.frequency = mic_frequency;
memcpy(data++, &(timer_data.frequency), sizeof(uint64_t));
for (int i = 0; i < c_offload_target_max_phase; i++) {
memcpy(data++, &(timer_data.phases[i].total), sizeof(uint64_t));
}
}
#endif // TIMING_SUPPORT
+309
View File
@@ -0,0 +1,309 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_trace.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#include <sstream>
#include "liboffload_error_codes.h"
extern const char *prefix;
#if !HOST_LIBRARY
extern int mic_index;
#endif
// The debug routines
static const char * offload_stage(std::stringstream &ss,
int offload_number,
const char *tag,
const char *text,
bool print_tag)
{
ss << "[" << report_get_message_str(c_report_offload) << "]";
#if HOST_LIBRARY
ss << " [" << prefix << "]";
if (print_tag) {
ss << " [" << report_get_message_str(c_report_tag);
ss << " " << offload_number << "]";
}
else {
ss << " ";
}
ss << " [" << tag << "]";
ss << " " << text;
#else
ss << " [" << prefix << " " << mic_index << "]";
if (print_tag) {
ss << " [" << report_get_message_str(c_report_tag);
ss << " " << offload_number << "]";
}
ss << " [" << tag << "]";
ss << " " << text;
#endif
return 0;
}
static const char * offload_signal(std::stringstream &ss,
int offload_number,
const char *tag,
const char *text)
{
ss << "[" << report_get_message_str(c_report_offload) << "]";
ss << " [" << prefix << "]";
ss << " [" << report_get_message_str(c_report_tag);
ss << " " << offload_number << "]";
ss << " [" << tag << "]";
ss << " " << text;
return 0;
}
void offload_stage_print(int stage, int offload_number, ...)
{
std::string buf;
std::stringstream ss;
char const *str1;
char const *str2;
va_list va_args;
va_start(va_args, offload_number);
va_arg(va_args, char*);
switch (stage) {
case c_offload_start:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_start);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_init:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_init);
offload_stage(ss, offload_number, str1, str2, false);
ss << " " << report_get_message_str(c_report_logical_card);
ss << " " << va_arg(va_args, int);
ss << " = " << report_get_message_str(c_report_physical_card);
ss << " " << va_arg(va_args, int);
break;
case c_offload_register:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_register);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_init_func:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_init_func);
offload_stage(ss, offload_number, str1, str2, true);
ss << ": " << va_arg(va_args, char*);
break;
case c_offload_create_buf_host:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_create_buf_host);
offload_stage(ss, offload_number, str1, str2, true);
ss << ": base=0x" << std::hex << va_arg(va_args, uint64_t);
ss << " length=" << std::dec << va_arg(va_args, uint64_t);
break;
case c_offload_create_buf_mic:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_create_buf_mic);
offload_stage(ss, offload_number, str1, str2, true);
ss << ": size=" << va_arg(va_args, uint64_t);
ss << " offset=" << va_arg(va_args, int);
if (va_arg(va_args,int))
ss << " (2M page)";
break;
case c_offload_send_pointer_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_send_pointer_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_sent_pointer_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_sent_pointer_data);
offload_stage(ss, offload_number, str1, str2, true);
ss << " " << va_arg(va_args, uint64_t);
break;
case c_offload_gather_copyin_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_gather_copyin_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_copyin_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_copyin_data);
offload_stage(ss, offload_number, str1, str2, true);
ss << " " << va_arg(va_args, uint64_t) << " ";
break;
case c_offload_compute:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_compute);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_receive_pointer_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_receive_pointer_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_received_pointer_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_received_pointer_data);
offload_stage(ss, offload_number, str1, str2, true);
ss << " " << va_arg(va_args, uint64_t);
break;
case c_offload_start_target_func:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_start_target_func);
offload_stage(ss, offload_number, str1, str2, true);
ss << ": " << va_arg(va_args, char*);
break;
case c_offload_var:
str1 = report_get_message_str(c_report_var);
offload_stage(ss, offload_number, str1, " ", true);
va_arg(va_args, int);
ss << va_arg(va_args, char*);
ss << " " << " " << va_arg(va_args, char*);
break;
case c_offload_scatter_copyin_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_scatter_copyin_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_gather_copyout_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_gather_copyout_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_scatter_copyout_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_scatter_copyout_data);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_copyout_data:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_copyout_data);
offload_stage(ss, offload_number, str1, str2, true);
ss << " " << va_arg(va_args, uint64_t);
break;
case c_offload_signal:
{
uint64_t *signal;
str1 = report_get_message_str(c_report_state_signal);
str2 = report_get_message_str(c_report_signal);
offload_signal(ss, offload_number, str1, str2);
signal = va_arg(va_args, uint64_t*);
if (signal)
ss << " 0x" << std::hex << *signal;
else
ss << " none";
}
break;
case c_offload_wait:
{
int count;
uint64_t **signal;
str1 = report_get_message_str(c_report_state_signal);
str2 = report_get_message_str(c_report_wait);
offload_signal(ss, offload_number, str1, str2);
count = va_arg(va_args, int);
signal = va_arg(va_args, uint64_t**);
if (count) {
while (count) {
ss << " " << std::hex << signal[count-1];
count--;
}
}
else
ss << " none";
}
break;
case c_offload_unregister:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_unregister);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_destroy:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_destroy);
offload_stage(ss, offload_number, str1, str2, true);
break;
case c_offload_myoinit:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myoinit);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_myoregister:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myoregister);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_myofini:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myofini);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_mic_myo_shared:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_mic_myo_shared);
offload_stage(ss, offload_number, str1, str2, false);
ss << " " << va_arg(va_args, char*);
break;
case c_offload_mic_myo_fptr:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_mic_myo_fptr);
offload_stage(ss, offload_number, str1, str2, false);
ss << " " << va_arg(va_args, char*);
break;
case c_offload_myosharedmalloc:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myosharedmalloc);
offload_stage(ss, offload_number, str1, str2, false);
va_arg(va_args, char*);
ss << " " << va_arg(va_args, size_t);
break;
case c_offload_myosharedfree:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myosharedfree);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_myosharedalignedmalloc:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myosharedalignedmalloc);
offload_stage(ss, offload_number, str1, str2, false);
va_arg(va_args, char*);
ss << " " << va_arg(va_args, size_t);
ss << " " << va_arg(va_args, size_t);
break;
case c_offload_myosharedalignedfree:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myosharedalignedfree);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_myoacquire:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myoacquire);
offload_stage(ss, offload_number, str1, str2, false);
break;
case c_offload_myorelease:
str1 = report_get_message_str(c_report_state);
str2 = report_get_message_str(c_report_myorelease);
offload_stage(ss, offload_number, str1, str2, false);
break;
default:
LIBOFFLOAD_ERROR(c_report_unknown_trace_node);
abort();
}
ss << "\n";
buf = ss.str();
fprintf(stdout, buf.data());
fflush(stdout);
va_end(va_args);
return;
}
+52
View File
@@ -0,0 +1,52 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
// The parts of the offload library common to host and target
void offload_stage_print(int stage, int offload_number, ...);
enum OffloadTraceStage {
// Total time spent on the target
c_offload_start = 0,
c_offload_init,
c_offload_register,
c_offload_init_func,
c_offload_create_buf_host,
c_offload_create_buf_mic,
c_offload_send_pointer_data,
c_offload_sent_pointer_data,
c_offload_gather_copyin_data,
c_offload_copyin_data,
c_offload_compute,
c_offload_receive_pointer_data,
c_offload_received_pointer_data,
c_offload_start_target_func,
c_offload_var,
c_offload_scatter_copyin_data,
c_offload_gather_copyout_data,
c_offload_scatter_copyout_data,
c_offload_copyout_data,
c_offload_signal,
c_offload_wait,
c_offload_unregister,
c_offload_destroy,
c_offload_finish,
c_offload_myoinit,
c_offload_myoregister,
c_offload_mic_myo_shared,
c_offload_mic_myo_fptr,
c_offload_myosharedmalloc,
c_offload_myosharedfree,
c_offload_myosharedalignedmalloc,
c_offload_myosharedalignedfree,
c_offload_myoacquire,
c_offload_myorelease,
c_offload_myofini
};
+206
View File
@@ -0,0 +1,206 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include "offload_util.h"
#include <errno.h>
#include "liboffload_error_codes.h"
#ifdef TARGET_WINNT
void *thread_getspecific(pthread_key_t key)
{
if (key == 0) {
return NULL;
}
else {
return TlsGetValue(key);
}
}
int thread_setspecific(pthread_key_t key, const void *value)
{
return (TlsSetValue(key, (LPVOID)value)) ? 0 : GetLastError();
}
#endif // TARGET_WINNT
bool __offload_parse_size_string(const char *str, uint64_t &new_size)
{
uint64_t val;
char *suffix;
errno = 0;
#ifdef TARGET_WINNT
val = strtoul(str, &suffix, 10);
#else // TARGET_WINNT
val = strtoull(str, &suffix, 10);
#endif // TARGET_WINNT
if (errno != 0 || suffix == str) {
return false;
}
if (suffix[0] == '\0') {
// default is Kilobytes
new_size = val * 1024;
return true;
}
else if (suffix[1] == '\0') {
// Optional suffixes: B (bytes), K (Kilobytes), M (Megabytes),
// G (Gigabytes), or T (Terabytes) specify the units.
switch (suffix[0]) {
case 'b':
case 'B':
new_size = val;
break;
case 'k':
case 'K':
new_size = val * 1024;
break;
case 'm':
case 'M':
new_size = val * 1024 * 1024;
break;
case 'g':
case 'G':
new_size = val * 1024 * 1024 * 1024;
break;
case 't':
case 'T':
new_size = val * 1024 * 1024 * 1024 * 1024;
break;
default:
return false;
}
return true;
}
return false;
}
bool __offload_parse_int_string(const char *str, int64_t &value)
{
int64_t val;
char *suffix;
errno = 0;
#ifdef TARGET_WINNT
val = strtol(str, &suffix, 0);
#else
val = strtoll(str, &suffix, 0);
#endif
if (errno == 0 && suffix != str && *suffix == '\0') {
value = val;
return true;
}
return false;
}
#ifdef TARGET_WINNT
extern void* DL_open(const char *path)
{
void *handle;
int error_mode;
/*
* do not display message box with error if it the call below fails to
* load dynamic library.
*/
error_mode = SetErrorMode(SEM_FAILCRITICALERRORS | SEM_NOOPENFILEERRORBOX);
/* load dynamic library */
handle = (void*) LoadLibrary(path);
/* restore error mode */
SetErrorMode(error_mode);
return handle;
}
extern int DL_addr(const void *addr, Dl_info *dl_info)
{
MEMORY_BASIC_INFORMATION mem_info;
char mod_name[MAX_PATH];
HMODULE mod_handle;
/* Fill MEMORY_BASIC_INFORMATION struct */
if (!VirtualQuery(addr, &mem_info, sizeof(mem_info))) {
return 0;
}
mod_handle = (HMODULE)mem_info.AllocationBase;
/* ANSI file name for module */
if (!GetModuleFileNameA(mod_handle, (char*) mod_name, sizeof(mod_name))) {
return 0;
}
strcpy(dl_info->dli_fname, mod_name);
dl_info->dli_fbase = mem_info.BaseAddress;
dl_info->dli_saddr = addr;
strcpy(dl_info->dli_sname, mod_name);
return 1;
}
// Run once
static BOOL CALLBACK __offload_run_once_wrapper(
PINIT_ONCE initOnce,
PVOID parameter,
PVOID *context
)
{
void (*init_routine)(void) = (void(*)(void)) parameter;
init_routine();
return true;
}
void __offload_run_once(OffloadOnceControl *ctrl, void (*func)(void))
{
InitOnceExecuteOnce(ctrl, __offload_run_once_wrapper, (void*) func, 0);
}
#endif // TARGET_WINNT
/* ARGSUSED */ // version is not used on windows
void* DL_sym(void *handle, const char *name, const char *version)
{
#ifdef TARGET_WINNT
return GetProcAddress((HMODULE) handle, name);
#else // TARGET_WINNT
if (version == 0) {
return dlsym(handle, name);
}
else {
return dlvsym(handle, name, version);
}
#endif // TARGET_WINNT
}
int64_t get_el_value(
char *base,
int64_t offset,
int64_t size)
{
int64_t val = 0;
switch (size) {
case 1:
val = static_cast<int64_t>(*((char *)(base + offset)));
break;
case 2:
val = static_cast<int64_t>(*((short *)(base + offset)));
break;
case 4:
val = static_cast<int64_t>(*((int *)(base + offset)));
break;
default:
val = *((int64_t *)(base + offset));
break;
}
return val;
}
+153
View File
@@ -0,0 +1,153 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef OFFLOAD_UTIL_H_INCLUDED
#define OFFLOAD_UTIL_H_INCLUDED
#include <stdio.h>
#include <stdlib.h>
#include <stdint.h>
#ifdef TARGET_WINNT
#include <windows.h>
#include <process.h>
#else // TARGET_WINNT
#include <dlfcn.h>
#include <pthread.h>
#endif // TARGET_WINNT
#ifdef TARGET_WINNT
typedef unsigned pthread_key_t;
typedef int pid_t;
#define __func__ __FUNCTION__
#define strtok_r(s,d,p) strtok_s(s,d,p)
#define strcasecmp(a,b) stricmp(a,b)
#define thread_key_create(key, destructor) \
(((*key = TlsAlloc()) > 0) ? 0 : GetLastError())
#define thread_key_delete(key) TlsFree(key)
#ifndef S_ISREG
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
#endif
void* thread_getspecific(pthread_key_t key);
int thread_setspecific(pthread_key_t key, const void *value);
#else
#define thread_key_create(key, destructor) \
pthread_key_create((key), (destructor))
#define thread_key_delete(key) pthread_key_delete(key)
#define thread_getspecific(key) pthread_getspecific(key)
#define thread_setspecific(key, value) pthread_setspecific(key, value)
#endif // TARGET_WINNT
// Mutex implementation
struct mutex_t {
mutex_t() {
#ifdef TARGET_WINNT
InitializeCriticalSection(&m_lock);
#else // TARGET_WINNT
pthread_mutex_init(&m_lock, 0);
#endif // TARGET_WINNT
}
~mutex_t() {
#ifdef TARGET_WINNT
DeleteCriticalSection(&m_lock);
#else // TARGET_WINNT
pthread_mutex_destroy(&m_lock);
#endif // TARGET_WINNT
}
void lock() {
#ifdef TARGET_WINNT
EnterCriticalSection(&m_lock);
#else // TARGET_WINNT
pthread_mutex_lock(&m_lock);
#endif // TARGET_WINNT
}
void unlock() {
#ifdef TARGET_WINNT
LeaveCriticalSection(&m_lock);
#else // TARGET_WINNT
pthread_mutex_unlock(&m_lock);
#endif // TARGET_WINNT
}
private:
#ifdef TARGET_WINNT
CRITICAL_SECTION m_lock;
#else
pthread_mutex_t m_lock;
#endif
};
struct mutex_locker_t {
mutex_locker_t(mutex_t &mutex) : m_mutex(mutex) {
m_mutex.lock();
}
~mutex_locker_t() {
m_mutex.unlock();
}
private:
mutex_t &m_mutex;
};
// Dynamic loader interface
#ifdef TARGET_WINNT
struct Dl_info
{
char dli_fname[MAX_PATH];
void *dli_fbase;
char dli_sname[MAX_PATH];
const void *dli_saddr;
};
void* DL_open(const char *path);
#define DL_close(handle) FreeLibrary((HMODULE) (handle))
int DL_addr(const void *addr, Dl_info *info);
#else
#define DL_open(path) dlopen((path), RTLD_NOW)
#define DL_close(handle) dlclose(handle)
#define DL_addr(addr, info) dladdr((addr), (info))
#endif // TARGET_WINNT
extern void* DL_sym(void *handle, const char *name, const char *version);
// One-time initialization API
#ifdef TARGET_WINNT
typedef INIT_ONCE OffloadOnceControl;
#define OFFLOAD_ONCE_CONTROL_INIT INIT_ONCE_STATIC_INIT
extern void __offload_run_once(OffloadOnceControl *ctrl, void (*func)(void));
#else
typedef pthread_once_t OffloadOnceControl;
#define OFFLOAD_ONCE_CONTROL_INIT PTHREAD_ONCE_INIT
#define __offload_run_once(ctrl, func) pthread_once(ctrl, func)
#endif // TARGET_WINNT
// Parses size specification string.
extern bool __offload_parse_size_string(const char *str, uint64_t &new_size);
// Parses string with integer value
extern bool __offload_parse_int_string(const char *str, int64_t &value);
// get value by its base, offset and size
int64_t get_el_value(
char *base,
int64_t offset,
int64_t size
);
#endif // OFFLOAD_UTIL_H_INCLUDED
+164
View File
@@ -0,0 +1,164 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#if HOST_LIBRARY
#include "offload_host.h"
#include "offload_myo_host.h"
#else
#include "compiler_if_target.h"
#include "offload_target.h"
#include "offload_myo_target.h"
#endif
#ifdef TARGET_WINNT
#define ALLOCATE(name) __declspec(allocate(name))
#define DLL_LOCAL
#else // TARGET_WINNT
#define ALLOCATE(name) __attribute__((section(name)))
#define DLL_LOCAL __attribute__((visibility("hidden")))
#endif // TARGET_WINNT
#if HOST_LIBRARY
// the host program/shared library should always have __offload_target_image
// symbol defined. This symbol specifies the beginning of the target program
// image.
extern "C" DLL_LOCAL const void* __offload_target_image;
#else // HOST_LIBRARY
// Define a weak main which would be used on target side in case usere's
// source file containing main does not have offload code.
#pragma weak main
int main(void)
{
OFFLOAD_TARGET_MAIN();
return 0;
}
#pragma weak MAIN__
extern "C" int MAIN__(void)
{
OFFLOAD_TARGET_MAIN();
return 0;
}
#endif // HOST_LIBRARY
// offload section prolog
ALLOCATE(OFFLOAD_ENTRY_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FuncTable::Entry)))
#endif // TARGET_WINNT
static FuncTable::Entry __offload_entry_table_start = { 0 };
// list element for the current module
static FuncList::Node __offload_entry_node = {
{ &__offload_entry_table_start + 1, -1 },
0, 0
};
// offload fp section prolog
ALLOCATE(OFFLOAD_FUNC_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FuncTable::Entry)))
#endif // TARGET_WINNT
static FuncTable::Entry __offload_func_table_start = { 0 };
// list element for the current module
static FuncList::Node __offload_func_node = {
{ &__offload_func_table_start + 1, -1 },
0, 0
};
// offload fp section prolog
ALLOCATE(OFFLOAD_VAR_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(VarTable::Entry)))
#endif // TARGET_WINNT
static VarTable::Entry __offload_var_table_start = { 0 };
// list element for the current module
static VarList::Node __offload_var_node = {
{ &__offload_var_table_start + 1 },
0, 0
};
#ifdef MYO_SUPPORT
// offload myo shared var section prolog
ALLOCATE(OFFLOAD_MYO_SHARED_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(SharedTableEntry)))
#endif // TARGET_WINNT
static SharedTableEntry __offload_myo_shared_table_start = { 0 };
#if HOST_LIBRARY
// offload myo shared var init section prolog
ALLOCATE(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(InitTableEntry)))
#endif // TARGET_WINNT
static InitTableEntry __offload_myo_shared_init_table_start = { 0 };
#endif
// offload myo fptr section prolog
ALLOCATE(OFFLOAD_MYO_FPTR_TABLE_SECTION_START)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FptrTableEntry)))
#endif // TARGET_WINNT
static FptrTableEntry __offload_myo_fptr_table_start = { 0 };
#endif // MYO_SUPPORT
// init/fini code which adds/removes local lookup data to/from the global list
static void offload_fini();
#ifndef TARGET_WINNT
static void offload_init() __attribute__((constructor(101)));
#else // TARGET_WINNT
static void offload_init();
// Place offload initialization before user constructors
ALLOCATE(OFFLOAD_CRTINIT_SECTION_START)
static void (*addressof_offload_init)() = offload_init;
#endif // TARGET_WINNT
static void offload_init()
{
// register offload tables
__offload_register_tables(&__offload_entry_node,
&__offload_func_node,
&__offload_var_node);
#if HOST_LIBRARY
__offload_register_image(&__offload_target_image);
atexit(offload_fini);
#endif // HOST_LIBRARY
#ifdef MYO_SUPPORT
__offload_myoRegisterTables(
#if HOST_LIBRARY
&__offload_myo_shared_init_table_start + 1,
#endif // HOST_LIBRARY
&__offload_myo_shared_table_start + 1,
&__offload_myo_fptr_table_start + 1
);
#endif // MYO_SUPPORT
}
static void offload_fini()
{
#if HOST_LIBRARY
__offload_unregister_image(&__offload_target_image);
#endif // HOST_LIBRARY
// unregister offload tables
__offload_unregister_tables(&__offload_entry_node,
&__offload_func_node,
&__offload_var_node);
}
+77
View File
@@ -0,0 +1,77 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#if HOST_LIBRARY
#include "offload_host.h"
#include "offload_myo_host.h"
#else
#include "offload_target.h"
#include "offload_myo_target.h"
#endif
#ifdef TARGET_WINNT
#define ALLOCATE(name) __declspec(allocate(name))
#else // TARGET_WINNT
#define ALLOCATE(name) __attribute__((section(name)))
#endif // TARGET_WINNT
// offload entry table
ALLOCATE(OFFLOAD_ENTRY_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FuncTable::Entry)))
#endif // TARGET_WINNT
static FuncTable::Entry __offload_entry_table_end = { (const char*)-1 };
// offload function table
ALLOCATE(OFFLOAD_FUNC_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FuncTable::Entry)))
#endif // TARGET_WINNT
static FuncTable::Entry __offload_func_table_end = { (const char*)-1 };
// data table
ALLOCATE(OFFLOAD_VAR_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(VarTable::Entry)))
#endif // TARGET_WINNT
static VarTable::Entry __offload_var_table_end = { (const char*)-1 };
#ifdef MYO_SUPPORT
// offload myo shared var section epilog
ALLOCATE(OFFLOAD_MYO_SHARED_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(SharedTableEntry)))
static SharedTableEntry __offload_myo_shared_table_end = { (const char*)-1, 0 };
#else // TARGET_WINNT
static SharedTableEntry __offload_myo_shared_table_end = { 0 };
#endif // TARGET_WINNT
#if HOST_LIBRARY
// offload myo shared var init section epilog
ALLOCATE(OFFLOAD_MYO_SHARED_INIT_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(InitTableEntry)))
static InitTableEntry __offload_myo_shared_init_table_end = { (const char*)-1, 0 };
#else // TARGET_WINNT
static InitTableEntry __offload_myo_shared_init_table_end = { 0 };
#endif // TARGET_WINNT
#endif // HOST_LIBRARY
// offload myo fptr section epilog
ALLOCATE(OFFLOAD_MYO_FPTR_TABLE_SECTION_END)
#ifdef TARGET_WINNT
__declspec(align(sizeof(FptrTableEntry)))
static FptrTableEntry __offload_myo_fptr_table_end = { (const char*)-1, 0, 0 };
#else // TARGET_WINNT
static FptrTableEntry __offload_myo_fptr_table_end = { 0 };
#endif // TARGET_WINNT
#endif // MYO_SUPPORT
@@ -0,0 +1,221 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#ifndef _ORSL_LITE_H_
#define _ORSL_LITE_H_
#ifndef TARGET_WINNT
#include <sched.h>
#else
#define cpu_set_t int
#endif
#ifdef __cplusplus
extern "C" {
#endif
/** Type of a ORSLBusySet */
typedef enum ORSLBusySetType {
BUSY_SET_EMPTY = 0, /**< Empty set */
BUSY_SET_PARTIAL = 1, /**< Non-empty set that omits some threads */
BUSY_SET_FULL = 2 /**< A set that includes all threads on the card */
} BusySetType;
/** ORSLBusySet encapsulation */
typedef struct ORSLBusySet {
BusySetType type; /**< Set type */
#ifdef __linux__
cpu_set_t cpu_set; /**< CPU mask (unused for BUSY_SET_EMPTY and
BUSY_SET_PARTIAL sets) represented by the standard
Linux CPU set type -- cpu_set_t. Threads are numbered
starting from 0. The maximal possible thread number
is system-specific. See CPU_SET(3) family of macros
for more details. Unused in ORSL Lite. */
#endif
} ORSLBusySet;
/** Client tag */
typedef char* ORSLTag;
/** Maximal length of tag in characters */
#define ORSL_MAX_TAG_LEN 128
/** Maximal number of cards that can be managed by ORSL */
#define ORSL_MAX_CARDS 32
/** Reserves computational resources on a set of cards. Blocks.
*
* If any of the resources cannot be reserved, this function will block until
* they become available. Reservation can be recursive if performed by the
* same tag. A recursively reserved resource must be released the same number
* of times it was reserved.
*
* @see ORSLTryReserve
*
* @param[in] n Number of cards to reserve resources on. Cannot be < 0
* or > ORSL_MAX_CARDS.
*
* @param[in] inds Indices of the cards: an integer array with n elements.
* Cannot be NULL if n > 0. Valid card indices are from 0
* to ORSL_MAX_CARDS-1. Cannot contain duplicate elements.
*
* @param[in] bsets Requested resources on each of the card. Cannot be NULL
* if n > 0.
*
* @param[in] tag ORSLTag of the calling client. Cannot be NULL. Length
* must not exeed ORSL_MAX_TAG_LEN.
*
* @returns 0 if the resources were successfully reserved
*
* @returns EINVAL if any of the arguments is invalid
*
* @returns EAGAIN limit of recursive reservations reached
* (not in ORSL Lite)
*
* @returns ENOSYS (in ORSL Lite) if type of any of the busy sets is
* equal to BUSY_SET_PARTIAL
*/
int ORSLReserve(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag);
/** Reserves computational resources on a set of cards. Does not block.
*
* If any of the resources cannot be reserved, this function will return
* immediately. Reservation can be recursive if performed by the same tag.
* A recursively reserved resource must be released the same number of times
* it was reserved.
*
* @see ORSLReserve
*
* @param[in] n Number of cards to reserve resources on. Cannot be < 0
* or > ORSL_MAX_CARDS.
*
* @param[in] inds Indices of the cards: an integer array with n elements.
* Cannot be NULL if n > 0. Valid card indices are from 0
* to ORSL_MAX_CARDS-1. Cannot contain duplicate elements.
*
* @param[inout] bsets Requested resources on each of the card. Cannot be
* NULL if n > 0.
*
* @param[in] tag ORSLTag of the calling client. Cannot be NULL. Length
* must not exceed ORSL_MAX_TAG_LEN.
*
* @returns 0 if the resources were successfully reserved
*
* @returns EBUSY if some of the requested resources are busy
*
* @returns EINVAL if any of the arguments is invalid
*
* @returns EAGAIN limit of recursive reservations reached
* (not in ORSL Lite)
*
* @returns ENOSYS (in ORSL Lite) if type of any of the busy sets is
* equal to BUSY_SET_PARTIAL
*/
int ORSLTryReserve(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag);
/** Granularify of partial reservation */
typedef enum ORSLPartialGranularity {
GRAN_CARD = 0, /**< Card granularity */
GRAN_THREAD = 1 /**< Thread granularity */
} ORSLPartialGranularity;
/** Requests reservation of some of computational resources on a set of cards.
* Does not block. Updates user-provided bsets to indicate which resources
* were reserved.
*
* If any of the resources cannot be reserved, this function will update busy
* sets provided by the caller to reflect what resources were actually
* reserved. This function supports two granularity modes: 'card' and
* 'thread'. When granularity is set to 'card', a failure to reserve a thread
* on the card will imply that reservation has failed for the whole card. When
* granularity is set to 'thread', reservation on a card will be considered
* successful as long as at least one thread on the card was successfully
* reserved. Reservation can be recursive if performed by the same tag. A
* recursively reserved resource must be released the same number of times it
* was reserved.
*
* @param[in] gran Reservation granularity
*
* @param[in] n Number of cards to reserve resources on. Cannot be < 0
* or > ORSL_MAX_CARDS.
*
* @param[in] inds Indices of the cards: an integer array with n elements.
* Cannot be NULL if n > 0. Valid card indices are from 0
* to ORSL_MAX_CARDS-1. Cannot contain duplicate elements.
*
* @param[in] bsets Requested resources on each of the card. Cannot be NULL
* if n > 0.
*
* @param[in] tag ORSLTag of the calling client. Cannot be NULL. Length
* must not exceed ORSL_MAX_TAG_LEN.
*
* @returns 0 if at least some of the resources were successfully
* reserved
*
* @returns EBUSY if all of the requested resources are busy
*
* @returns EINVAL if any of the arguments is invalid
*
* @returns EAGAIN limit of recursive reservations reached
* (not in ORSL Lite)
*
* @returns ENOSYS (in ORSL Lite) if type of any of the busy sets is
* equal to BUSY_SET_PARTIAL
*/
int ORSLReservePartial(const ORSLPartialGranularity gran, const int n,
const int *__restrict inds,
ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag);
/** Releases previously reserved computational resources on a set of cards.
*
* This function will fail if any of the resources to be released were not
* reserved by the calling client.
*
* @see ORSLReserve
* @see ORSLTryReserve
* @see ORSLReservePartial
*
* @param[in] n Number of cards to reserve resources on. Cannot be < 0
* or > ORSL_MAX_CARDS.
*
* @param[in] inds Indices of the cards: an integer array with n elements.
* Cannot be NULL if n > 0. Valid card indices are from 0
* to ORSL_MAX_CARDS-1. Cannot contain duplicate elements.
*
* @param[in] bsets Requested resources on each of the card. Cannot be NULL
* if n > 0.
*
* @param[in] tag ORSLTag of the calling client. Cannot be NULL. Length
* must not exceed ORSL_MAX_TAG_LEN.
*
* @returns 0 if the resources were successfully released
*
* @returns EINVAL if any of the arguments is invalid
*
* @returns EPERM the calling client did not reserve some of the
* resources it is trying to release.
*
* @returns ENOSYS (in ORSL Lite) if type of any of the busy sets is
* equal to BUSY_SET_PARTIAL
*/
int ORSLRelease(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag);
#ifdef __cplusplus
}
#endif
#endif
+337
View File
@@ -0,0 +1,337 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <errno.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "orsl-lite/include/orsl-lite.h"
#define DISABLE_SYMBOL_VERSIONING
#if defined(__linux__) && !defined(DISABLE_SYMBOL_VERSIONING)
#define symver(src, tgt, verstr) __asm__(".symver " #src "," #tgt verstr)
symver(ORSLReserve0, ORSLReserve, "@@ORSL_0.0");
symver(ORSLTryReserve0, ORSLTryReserve, "@@ORSL_0.0");
symver(ORSLReservePartial0, ORSLReservePartial, "@@ORSL_0.0");
symver(ORSLRelease0, ORSLRelease, "@@ORSL_0.0");
#else
#define ORSLReserve0 ORSLReserve
#define ORSLTryReserve0 ORSLTryReserve
#define ORSLReservePartial0 ORSLReservePartial
#define ORSLRelease0 ORSLRelease
#endif
#ifdef __linux__
#include <pthread.h>
static pthread_mutex_t global_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t release_cond = PTHREAD_COND_INITIALIZER;
#endif
#ifdef _WIN32
#include <windows.h>
#pragma intrinsic(_ReadWriteBarrier)
static SRWLOCK global_mutex = SRWLOCK_INIT;
static volatile int release_cond_initialized = 0;
static CONDITION_VARIABLE release_cond;
static void state_lazy_init_sync()
{
if (!release_cond_initialized) {
AcquireSRWLockExclusive(&global_mutex);
_ReadWriteBarrier();
if (!release_cond_initialized) {
InitializeConditionVariable(&release_cond);
release_cond_initialized = 1;
}
ReleaseSRWLockExclusive(&global_mutex);
}
}
#endif
static int state_lock()
{
#ifdef __linux__
return pthread_mutex_lock(&global_mutex);
#endif
#ifdef _WIN32
AcquireSRWLockExclusive(&global_mutex);
return 0;
#endif
}
static int state_unlock()
{
#ifdef __linux__
return pthread_mutex_unlock(&global_mutex);
#endif
#ifdef _WIN32
ReleaseSRWLockExclusive(&global_mutex);
return 0;
#endif
}
static int state_wait_for_release()
{
#ifdef __linux__
return pthread_cond_wait(&release_cond, &global_mutex);
#endif
#ifdef _WIN32
return SleepConditionVariableSRW(&release_cond,
&global_mutex, INFINITE, 0) == 0 ? 1 : 0;
#endif
}
static int state_signal_release()
{
#ifdef __linux__
return pthread_cond_signal(&release_cond);
#endif
#ifdef _WIN32
WakeConditionVariable(&release_cond);
return 0;
#endif
}
static struct {
char owner[ORSL_MAX_TAG_LEN + 1];
unsigned long rsrv_cnt;
} rsrv_data[ORSL_MAX_CARDS];
static int check_args(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i;
int card_specified[ORSL_MAX_CARDS];
if (tag == NULL) return -1;
if (strlen((char *)tag) > ORSL_MAX_TAG_LEN) return -1;
if (n < 0 || n >= ORSL_MAX_CARDS) return -1;
if (n != 0 && (inds == NULL || bsets == NULL)) return -1;
for (i = 0; i < ORSL_MAX_CARDS; i++)
card_specified[i] = 0;
for (i = 0; i < n; i++) {
int ind = inds[i];
if (ind < 0 || ind >= ORSL_MAX_CARDS) return -1;
if (card_specified[ind]) return -1;
card_specified[ind] = 1;
}
return 0;
}
static int check_bsets(const int n, const ORSLBusySet *bsets)
{
int i;
for (i = 0; i < n; i++)
if (bsets[i].type == BUSY_SET_PARTIAL) return -1;
return 0;
}
static int can_reserve_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
return (bset->type == BUSY_SET_EMPTY ||
((rsrv_data[card].rsrv_cnt == 0 ||
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0) &&
rsrv_data[card].rsrv_cnt < ULONG_MAX)) ? 0 : - 1;
}
static void reserve_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
if (bset->type == BUSY_SET_EMPTY)
return;
assert(rsrv_data[card].rsrv_cnt == 0 ||
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
assert(rsrv_data[card].rsrv_cnt < ULONG_MAX);
if (rsrv_data[card].rsrv_cnt == 0)
strncpy(rsrv_data[card].owner, (char *)tag, ORSL_MAX_TAG_LEN);
rsrv_data[card].owner[ORSL_MAX_TAG_LEN] = '\0';
rsrv_data[card].rsrv_cnt++;
}
static int can_release_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
return (bset->type == BUSY_SET_EMPTY || (rsrv_data[card].rsrv_cnt > 0 &&
strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0)) ? 0 : 1;
}
static void release_card(int card, const ORSLBusySet *__restrict bset,
const ORSLTag __restrict tag)
{
assert(tag != NULL);
assert(bset != NULL);
assert(strlen((char *)tag) < ORSL_MAX_TAG_LEN);
assert(bset->type != BUSY_SET_PARTIAL);
if (bset->type == BUSY_SET_EMPTY)
return;
assert(strncmp((char *)tag,
rsrv_data[card].owner, ORSL_MAX_TAG_LEN) == 0);
assert(rsrv_data[card].rsrv_cnt > 0);
rsrv_data[card].rsrv_cnt--;
}
int ORSLReserve0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, ok;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Loop until we find that all the resources we want are available */
do {
ok = 1;
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
ok = 0;
/* Wait for someone to release some resources */
state_wait_for_release();
break;
}
} while (!ok);
/* At this point we are good to reserve_card the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
state_unlock();
return 0;
}
int ORSLTryReserve0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, rc = EBUSY;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check resource availability once */
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0)
goto bail_out;
/* At this point we are good to reserve the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
rc = 0;
bail_out:
state_unlock();
return rc;
}
int ORSLReservePartial0(const ORSLPartialGranularity gran, const int n,
const int *__restrict inds, ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int rc = EBUSY;
int i, num_avail = n;
if (n == 0) return 0;
if (gran != GRAN_CARD && gran != GRAN_THREAD) return EINVAL;
if (gran != GRAN_CARD) return EINVAL;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check resource availability once; remove unavailable resources from the
* user-provided list */
for (i = 0; i < n; i++)
if (can_reserve_card(inds[i], &bsets[i], tag) != 0) {
num_avail--;
bsets[i].type = BUSY_SET_EMPTY;
}
if (num_avail == 0)
goto bail_out;
/* At this point we are good to reserve the resources we want */
for (i = 0; i < n; i++)
reserve_card(inds[i], &bsets[i], tag);
rc = 0;
bail_out:
state_unlock();
return rc;
}
int ORSLRelease0(const int n, const int *__restrict inds,
const ORSLBusySet *__restrict bsets,
const ORSLTag __restrict tag)
{
int i, rc = EPERM;
if (n == 0) return 0;
if (check_args(n, inds, bsets, tag) != 0) return EINVAL;
if (check_bsets(n, bsets) != 0) return ENOSYS;
state_lock();
/* Check that we can release all the resources */
for (i = 0; i < n; i++)
if (can_release_card(inds[i], &bsets[i], tag) != 0)
goto bail_out;
/* At this point we are good to release the resources we want */
for (i = 0; i < n; i++)
release_card(inds[i], &bsets[i], tag);
state_signal_release();
rc = 0;
bail_out:
state_unlock();
return rc;
}
/* vim:set et: */
+1
View File
@@ -0,0 +1 @@
ORSL-lite 0.7
+17
View File
@@ -0,0 +1,17 @@
//===----------------------------------------------------------------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is dual licensed under the MIT and the University of Illinois Open
// Source Licenses. See LICENSE.txt for details.
//
//===----------------------------------------------------------------------===//
#include <stdint.h>
uint64_t _rdtsc()
{
uint32_t eax, edx;
asm volatile ("rdtsc" : "=a" (eax), "=d" (edx));
return ((uint64_t)edx << 32) | eax;
}
+1
View File
@@ -0,0 +1 @@
2.1.6720-13
+1
View File
@@ -0,0 +1 @@
2.1.6720-13
+91
View File
@@ -0,0 +1,91 @@
---
BasedOnStyle: LLVM
AlignTrailingComments: false
SortIncludes: false
---
# Language: Cpp
# AccessModifierOffset: -2
# AlignAfterOpenBracket: Align
# AlignConsecutiveAssignments: false
# AlignConsecutiveDeclarations: false
# AlignEscapedNewlinesLeft: false
# AlignOperands: false
# AlignTrailingComments: false
# AllowAllParametersOfDeclarationOnNextLine: true
# AllowShortBlocksOnASingleLine: false
# AllowShortCaseLabelsOnASingleLine: false
# AllowShortFunctionsOnASingleLine: All
# AllowShortIfStatementsOnASingleLine: false
# AllowShortLoopsOnASingleLine: false
# AlwaysBreakAfterDefinitionReturnType: None
# AlwaysBreakAfterReturnType: None
# AlwaysBreakBeforeMultilineStrings: false
# AlwaysBreakTemplateDeclarations: false
# BinPackArguments: true
# BinPackParameters: true
# BraceWrapping:
# AfterClass: false
# AfterControlStatement: false
# AfterEnum: false
# AfterFunction: false
# AfterNamespace: false
# AfterObjCDeclaration: false
# AfterStruct: false
# AfterUnion: false
# BeforeCatch: false
# BeforeElse: false
# IndentBraces: false
# # BreakBeforeBinaryOperators: None
# BreakBeforeBraces: Attach
# BreakBeforeTernaryOperators: true
# BreakConstructorInitializersBeforeComma: false
# ColumnLimit: 80
# CommentPragmas: '^ IWYU pragma:'
# ConstructorInitializerAllOnOneLineOrOnePerLine: false
# ConstructorInitializerIndentWidth: 4
# ContinuationIndentWidth: 4
# Cpp11BracedListStyle: true
# DerivePointerAlignment: false
# DisableFormat: true
# ExperimentalAutoDetectBinPacking: false
# ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
# IncludeCategories:
# - Regex: '^"(llvm|llvm-c|clang|clang-c)/'
# Priority: 2
# - Regex: '^(<|"(gtest|isl|json)/)'
# Priority: 3
# - Regex: '.*'
# Priority: 1
# IndentCaseLabels: false
# IndentWidth: 2
# IndentWrappedFunctionNames: false
# KeepEmptyLinesAtTheStartOfBlocks: false
# MacroBlockBegin: ''
# MacroBlockEnd: ''
# MaxEmptyLinesToKeep: 2
# NamespaceIndentation: None
# ObjCBlockIndentWidth: 2
# ObjCSpaceAfterProperty: false
# ObjCSpaceBeforeProtocolList: true
# PenaltyBreakBeforeFirstCallParameter: 19
# PenaltyBreakComment: 300
# PenaltyBreakFirstLessLess: 120
# PenaltyBreakString: 1000
# PenaltyExcessCharacter: 1000000
# PenaltyReturnTypeOnItsOwnLine: 60
# PointerAlignment: Right
# ReflowComments: true
# SpaceAfterCStyleCast: false
# SpaceBeforeAssignmentOperators: true
# SpaceBeforeParens: ControlStatements
# SpaceInEmptyParentheses: false
# SpacesBeforeTrailingComments: 1
# SpacesInAngles: false
# SpacesInContainerLiterals: true
# SpacesInCStyleCastParentheses: false
# SpacesInParentheses: false
# SpacesInSquareBrackets: false
# Standard: Cpp11
# TabWidth: 8
# UseTab: Never
...
+229
View File
@@ -0,0 +1,229 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
==========================================================
How to Build the LLVM* OpenMP* Runtime Library using CMake
==========================================================
==== Version of CMake required: v2.8.0 or above ====
============================================
How to call cmake initially, then repeatedly
============================================
- When calling cmake for the first time, all needed compiler options
must be specified on the command line. After this initial call to
cmake, the compiler definitions must not be included for further calls
to cmake. Other options can be specified on the command line multiple
times including all definitions in the Build options section below.
- Example of configuring, building, reconfiguring, rebuilding:
$ mkdir build
$ cd build
$ cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLIBOMP_ARCH=i386 .. # Initial configuration
$ make
...
$ make clean
$ cmake -DLIBOMP_ARCH=x86_64 -DCMAKE_BUILD_TYPE=Debug .. # Second configuration
$ make
...
$ rm -rf *
$ cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLIBOMP_ARCH=x86_64 .. # Third configuration
$ make
- Notice in the example how the compiler definitions are only specified
for an empty build directory, but other Build options are used at any time.
- The file CMakeCache.txt which is created after the first call to cmake
is a configuration file which holds all the values for the Build options.
These configuration values can be changed using a text editor to modify
CMakeCache.txt as opposed to using definitions on the command line.
- To have cmake create a particular type of build generator file simply
inlude the -G <Generator name> option:
$ cmake -G "Unix Makefiles" ...
You can see a list of generators cmake supports by executing cmake with
no arguments and a list will be printed.
=====================
Instructions to Build
=====================
$ cd libomp_top_level/ [ directory with src/ , exports/ , tools/ , etc. ]
$ mkdir build
$ cd build
[ Unix* Libraries ]
$ cmake -DCMAKE_C_COMPILER=<C Compiler> -DCMAKE_CXX_COMPILER=<C++ Compiler> ..
[ Intel(R) Many Integrated Core Library (Intel(R) MIC Library) ]
$ cmake -DCMAKE_C_COMPILER=<C Compiler> -DCMAKE_CXX_COMPILER=<C++ Compiler> -DLIBOMP_ARCH=mic ..
[ Windows Libraries ]
$ cmake -G <Generator Type> -DCMAKE_C_COMPILER=<C Compiler> -DCMAKE_CXX_COMPILER=<C++ Compiler> -DCMAKE_ASM_MASM_COMPILER=[ml | ml64] -DCMAKE_BUILD_TYPE=Release ..
$ make
$ make install
==================
Mac* Fat Libraries
==================
On OS X* machines, it is possible to build universal (or fat) libraries which
include both i386 and x86_64 architecture objects in a
single archive.
$ cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DCMAKE_OSX_ARCHITECTURES='i386;x86_64' ..
$ make
There is also an option -DLIBOMP_OSX_ARCHITECTURES which can be set in case
this is an LLVM source tree build which will only set the libomp library
to a universal fat library and prevent having the entire llvm/clang build
produce universal binaries.
===========
Micro tests
===========
After the library has been built, there are five optional microtests that
can be performed. Some will be skipped based upon the platform.
To run the tests,
$ make libomp-micro-tests
=============
CMake options
=============
-DCMAKE_C_COMPILER=<C compiler name>
Specify the C compiler
-DCMAKE_CXX_COMPILER=<C++ compiler name>
Specify the C++ compiler
-DCMAKE_Fortran_COMPILER=<Fortran compiler name>
This option is only needed when -DLIBOMP_FORTRAN_MODULES is on.
So typically, a Fortran compiler is not needed during the build.
Specify the Fortran compiler
-DCMAKE_ASM_MASM_COMPILER=[ml | ml64 ]
This option is Windows* Only
-DLIBOMP_ARCH=i386|x86_64|arm|ppc64|ppc64le|aarch64|mic
The default for the option is chosen based on the probing the compiler for
architecture macros (e.g., is __x86_64__ predefined by compiler?).
==== First values listed are the default value ====
-DLIBOMP_LIB_TYPE=normal|profile|stubs
Library type can be normal, profile, or stubs.
-DCMAKE_BUILD_TYPE=Release|Debug|RelWithDebInfo
Build type can be Release, Debug, or RelWithDebInfo.
-DLIBOMP_OMP_VERSION=50|45|40|30
OpenMP version can be either 50, 45, 40 or 30.
-DLIBOMP_MIC_ARCH=knc|knf
This value is ignored if LIBOMP_ARCH != mic
Intel(R) MIC Architecture, can be knf or knc.
-DLIBOMP_FORTRAN_MODULES=off|on
Should the Fortran modules be created (requires Fortran compiler)
-DLIBOMP_USE_ADAPTIVE_LOCKS=on|off
Should adaptive (TSX-based) locks be included?
These are x86 specific. This feature is turned on by default
for i386 and x86_64. Otherwise, it is turned off.
-DLIBOMP_USE_INTERNODE_ALIGNMENT=off|on
Should 4096-byte alignment be used for certain data structures?
This option is useful on multinode systems where a small CACHE_LINE
setting leads to false sharing. This option is off by default.
-DLIBOMP_USE_VERSION_SYMBOLS=on|off
Should versioned symbols be used for building the library?
This option only makes sense for ELF based libraries where version
symbols are supported (Linux, some BSD* variants). It is off
by default for Windows and Mac, but on for other Unix based operating
systems.
-DLIBOMP_ENABLE_SHARED=on|off
Shared library instead of static library? (Note: static libraries are not
supported on Windows). If LIBOMP_ENABLE_SHARED is off, then static OpenMP
libraries will be built instead of dynamic ones.
-DLIBOMP_OMPT_SUPPORT=off|on
Should OMPT support be included in the build? (Not supported on Windows)
If LIBOMP_OMPT_SUPPORT is off, then both ompt_blame and ompt_trace are ignored.
-DLIBOMP_OMPT_BLAME=on|off
Should OMPT blame functionality be included in the build?
-DLIBOMP_OMPT_TRACE=on|off
Should OMPT trace functionality be included in the build?
-DLIBOMP_STATS=off|on
Should include stats-gathering code be included in the build?
-DLIBOMP_USE_DEBUGGER=off|on
Should the friendly debugger interface be included in the build?
-DLIBOMP_USE_HWLOC=off|on
Should the Hwloc library be used for affinity?
This option is not supported on Windows.
http://www.open-mpi.org/projects/hwloc
-DLIBOMP_HWLOC_INSTALL_DIR=/path/to/hwloc/install/dir
Default: /usr/local
This option is only used if LIBOMP_USE_HWLOC is on.
Specifies install location of Hwloc. The configuration system will look for
hwloc.h in ${LIBOMP_HWLOC_INSTALL_DIR}/include and the library in
${LIBOMP_HWLOC_INSTALL_DIR}/lib.
-DLIBOMP_LLVM_LIT_EXECUTABLE=/path/to/llvm-lit
Default: search in PATH
Specifiy full path to llvm-lit executable for running tests.
-DOPENMP_LLVM_TOOLS_DIR=/path/to/built/llvm/tools
Default: search for tools in path
Additional path to search for LLVM tools needed by tests.
================================
How to append flags to the build
================================
- These flags are *appended*. They do not
overwrite any of the preset flags.
-DLIBOMP_CPPFLAGS=<space-separated flags> -- Additional C preprocessor flags
-DLIBOMP_CFLAGS=<space-separated flags> -- Additional C compiler flags
-DLIBOMP_CXXFLAGS=<space-separated flags> -- Additional C++ compiler flags
-DLIBOMP_ASMFLAGS=<space-separated flags> -- Additional assembly flags
-DLIBOMP_LDFLAGS=<space-separated flags> -- Additional linker flags
-DLIBOMP_LIBFLAGS=<space-separated flags> -- Additional libraries to link
-DLIBOMP_FFLAGS=<space-separated flags> -- Additional Fortran compiler flags
=======================
Example usages of CMake
=======================
---- Typical usage ----
cmake -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc ..
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ ..
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ ..
---- With Various Options ----
- Build the i386 Linux library using GCC*
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLIBOMP_ARCH=i386 ..
- Build the x86_64 debug Mac library using Clang*
cmake -DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++ -DLIBOMP_ARCH=x86_64 -DCMAKE_BUILD_TYPE=Debug ..
- Build the library (architecture determined by probing compiler) using the
Intel(R) C Compiler and the Intel(R) C++ Compiler. Also, create the fortran modules using
the Intel(R) Fortran Compiler.
cmake -DCMAKE_C_COMPILER=icc -DCMAKE_CXX_COMPILER=icpc -DCMAKE_Fortran_COMPILER=ifort -DLIBOMP_FORTRAN_MODULES=on ..
- Have CMake Find the C/C++ compiler, and specify additional flags for the C compiler, preprocessor, and C++ compiler.
cmake -DLIBOMP_CFLAGS='-specific-flag' -DLIBOMP_CPPFLAGS='-DNEW_FEATURE=1 -DOLD_FEATURE=0' -DLIBOMP_CXXFLAGS='--one-specific-flag --two-specific-flag' ..
---- Build the stubs library ----
cmake -DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++ -DLIBOMP_LIB_TYPE=stubs ..
=========
Footnotes
=========
[*] Other names and brands may be claimed as the property of others.
+400
View File
@@ -0,0 +1,400 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# CMAKE libomp
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
# Add cmake directory to search for custom cmake functions
set(CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR}/cmake ${CMAKE_MODULE_PATH})
# Standalone build or part of LLVM?
set(LIBOMP_STANDALONE_BUILD FALSE)
if(OPENMP_STANDALONE_BUILD OR
"${CMAKE_SOURCE_DIR}" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}" OR
"${CMAKE_SOURCE_DIR}/runtime" STREQUAL "${CMAKE_CURRENT_SOURCE_DIR}")
project(libomp C CXX)
set(LIBOMP_STANDALONE_BUILD TRUE)
endif()
# Set libomp version
set(LIBOMP_VERSION_MAJOR 5)
set(LIBOMP_VERSION_MINOR 0)
# These include files are in the cmake/ subdirectory
include(LibompUtils)
include(LibompGetArchitecture)
include(LibompHandleFlags)
include(LibompDefinitions)
# Determine the target architecture
if(${LIBOMP_STANDALONE_BUILD})
# If adding a new architecture, take a look at cmake/LibompGetArchitecture.cmake
libomp_get_architecture(LIBOMP_DETECTED_ARCH)
set(LIBOMP_ARCH ${LIBOMP_DETECTED_ARCH} CACHE STRING
"The architecture to build for (x86_64/i386/arm/ppc64/ppc64le/aarch64/mic/mips/mips64).")
# Allow user to choose a suffix for the installation directory.
set(LIBOMP_LIBDIR_SUFFIX "" CACHE STRING
"suffix of lib installation directory e.g., 64 => lib64")
# Should assertions be enabled? They are on by default.
set(LIBOMP_ENABLE_ASSERTIONS TRUE CACHE BOOL
"enable assertions?")
set(LIBOMP_ENABLE_WERROR FALSE CACHE BOOL
"Enable -Werror flags to turn warnings into errors for supporting compilers.")
# CMAKE_BUILD_TYPE was not defined, set default to Release
if(NOT CMAKE_BUILD_TYPE)
set(CMAKE_BUILD_TYPE Release)
endif()
else() # Part of LLVM build
# Determine the native architecture from LLVM.
string(TOLOWER "${LLVM_TARGET_ARCH}" LIBOMP_NATIVE_ARCH)
if( LIBOMP_NATIVE_ARCH STREQUAL "host" )
string(REGEX MATCH "^[^-]*" LIBOMP_NATIVE_ARCH ${LLVM_HOST_TRIPLE})
endif ()
if(LIBOMP_NATIVE_ARCH MATCHES "i[2-6]86")
set(LIBOMP_ARCH i386)
elseif(LIBOMP_NATIVE_ARCH STREQUAL "x86")
set(LIBOMP_ARCH i386)
elseif(LIBOMP_NATIVE_ARCH STREQUAL "amd64")
set(LIBOMP_ARCH x86_64)
elseif(LIBOMP_NATIVE_ARCH STREQUAL "x86_64")
set(LIBOMP_ARCH x86_64)
elseif(LIBOMP_NATIVE_ARCH MATCHES "powerpc64le")
set(LIBOMP_ARCH ppc64le)
elseif(LIBOMP_NATIVE_ARCH MATCHES "powerpc")
set(LIBOMP_ARCH ppc64)
elseif(LIBOMP_NATIVE_ARCH MATCHES "aarch64")
set(LIBOMP_ARCH aarch64)
elseif(LIBOMP_NATIVE_ARCH MATCHES "arm64")
set(LIBOMP_ARCH aarch64)
elseif(LIBOMP_NATIVE_ARCH MATCHES "arm")
set(LIBOMP_ARCH arm)
else()
# last ditch effort
libomp_get_architecture(LIBOMP_ARCH)
endif ()
set(LIBOMP_LIBDIR_SUFFIX ${LLVM_LIBDIR_SUFFIX})
set(LIBOMP_ENABLE_ASSERTIONS ${LLVM_ENABLE_ASSERTIONS})
set(LIBOMP_ENABLE_WERROR ${LLVM_ENABLE_WERROR})
endif()
libomp_check_variable(LIBOMP_ARCH 32e x86_64 32 i386 arm ppc64 ppc64le aarch64 mic mips mips64)
set(LIBOMP_LIB_TYPE normal CACHE STRING
"Performance,Profiling,Stubs library (normal/profile/stubs)")
libomp_check_variable(LIBOMP_LIB_TYPE normal profile stubs)
set(LIBOMP_OMP_VERSION 50 CACHE STRING
"The OpenMP version (50/45/40/30)")
libomp_check_variable(LIBOMP_OMP_VERSION 50 45 40 30)
# Set the OpenMP Year and Month assiociated with version
if(${LIBOMP_OMP_VERSION} GREATER 50 OR ${LIBOMP_OMP_VERSION} EQUAL 50)
set(LIBOMP_OMP_YEAR_MONTH 201611)
elseif(${LIBOMP_OMP_VERSION} GREATER 45 OR ${LIBOMP_OMP_VERSION} EQUAL 45)
set(LIBOMP_OMP_YEAR_MONTH 201511)
elseif(${LIBOMP_OMP_VERSION} GREATER 40 OR ${LIBOMP_OMP_VERSION} EQUAL 40)
set(LIBOMP_OMP_YEAR_MONTH 201307)
elseif(${LIBOMP_OMP_VERSION} GREATER 30 OR ${LIBOMP_OMP_VERSION} EQUAL 30)
set(LIBOMP_OMP_YEAR_MONTH 201107)
else()
set(LIBOMP_OMP_YEAR_MONTH 200505)
endif()
set(LIBOMP_MIC_ARCH knc CACHE STRING
"Intel(R) Many Integrated Core Architecture (Intel(R) MIC Architecture) (knf/knc). Ignored if not Intel(R) MIC Architecture build.")
if("${LIBOMP_ARCH}" STREQUAL "mic")
libomp_check_variable(LIBOMP_MIC_ARCH knf knc)
endif()
set(LIBOMP_FORTRAN_MODULES FALSE CACHE BOOL
"Create Fortran module files? (requires fortran compiler)")
# - Support for universal fat binary builds on Mac
# - Having this extra variable allows people to build this library as a universal library
# without forcing a universal build of the llvm/clang compiler.
set(LIBOMP_OSX_ARCHITECTURES "${CMAKE_OSX_ARCHITECTURES}" CACHE STRING
"For Mac builds, semicolon separated list of architectures to build for universal fat binary.")
set(CMAKE_OSX_ARCHITECTURES ${LIBOMP_OSX_ARCHITECTURES})
# Should @rpath be used for dynamic libraries on Mac?
# The if(NOT DEFINED) is there to guard a cached value of the variable if one
# exists so there is no interference with what the user wants. Also, no cache entry
# is created so there are no inadvertant effects on other parts of LLVM.
if(NOT DEFINED CMAKE_MACOSX_RPATH)
set(CMAKE_MACOSX_RPATH TRUE)
endif()
# User specified flags. These are appended to the configured flags.
set(LIBOMP_CFLAGS "" CACHE STRING
"Appended user specified C compiler flags.")
set(LIBOMP_CXXFLAGS "" CACHE STRING
"Appended user specified C++ compiler flags.")
set(LIBOMP_CPPFLAGS "" CACHE STRING
"Appended user specified C preprocessor flags.")
set(LIBOMP_ASMFLAGS "" CACHE STRING
"Appended user specified assembler flags.")
set(LIBOMP_LDFLAGS "" CACHE STRING
"Appended user specified linker flags.")
set(LIBOMP_LIBFLAGS "" CACHE STRING
"Appended user specified linked libs flags. (e.g., -lm)")
set(LIBOMP_FFLAGS "" CACHE STRING
"Appended user specified Fortran compiler flags. These are only used if LIBOMP_FORTRAN_MODULES==TRUE.")
# Should the libomp library and generated headers be copied into the original source exports/ directory
# Turning this to FALSE aids parallel builds to not interfere with each other.
# Currently, the testsuite module expects the just built OpenMP library to be located inside the exports/
# directory. TODO: have testsuite run under llvm-lit directly. We can then get rid of copying to exports/
set(LIBOMP_COPY_EXPORTS TRUE CACHE STRING
"Should exports be copied into source exports/ directory?")
# HWLOC-support
set(LIBOMP_USE_HWLOC FALSE CACHE BOOL
"Use Hwloc (http://www.open-mpi.org/projects/hwloc/) library for affinity?")
set(LIBOMP_HWLOC_INSTALL_DIR /usr/local CACHE PATH
"Install path for hwloc library")
# Get the build number from kmp_version.cpp
libomp_get_build_number("${CMAKE_CURRENT_SOURCE_DIR}" LIBOMP_VERSION_BUILD)
math(EXPR LIBOMP_VERSION_BUILD_YEAR "${LIBOMP_VERSION_BUILD}/10000")
math(EXPR LIBOMP_VERSION_BUILD_MONTH_DAY "${LIBOMP_VERSION_BUILD}%10000")
# Currently don't record any timestamps
set(LIBOMP_BUILD_DATE "No_Timestamp")
# Architecture
set(IA32 FALSE)
set(INTEL64 FALSE)
set(ARM FALSE)
set(AARCH64 FALSE)
set(PPC64BE FALSE)
set(PPC64LE FALSE)
set(PPC64 FALSE)
set(MIC FALSE)
set(MIPS64 FALSE)
set(MIPS FALSE)
if("${LIBOMP_ARCH}" STREQUAL "i386" OR "${LIBOMP_ARCH}" STREQUAL "32") # IA-32 architecture
set(IA32 TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "x86_64" OR "${LIBOMP_ARCH}" STREQUAL "32e") # Intel(R) 64 architecture
set(INTEL64 TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "arm") # ARM architecture
set(ARM TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "ppc64") # PPC64BE architecture
set(PPC64BE TRUE)
set(PPC64 TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "ppc64le") # PPC64LE architecture
set(PPC64LE TRUE)
set(PPC64 TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "aarch64") # AARCH64 architecture
set(AARCH64 TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "mic") # Intel(R) Many Integrated Core Architecture
set(MIC TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "mips") # MIPS architecture
set(MIPS TRUE)
elseif("${LIBOMP_ARCH}" STREQUAL "mips64") # MIPS64 architecture
set(MIPS64 TRUE)
endif()
# Set some flags based on build_type
set(RELEASE_BUILD FALSE)
set(DEBUG_BUILD FALSE)
set(RELWITHDEBINFO_BUILD FALSE)
set(MINSIZEREL_BUILD FALSE)
string(TOLOWER "${CMAKE_BUILD_TYPE}" libomp_build_type_lowercase)
if("${libomp_build_type_lowercase}" STREQUAL "release")
set(RELEASE_BUILD TRUE)
elseif("${libomp_build_type_lowercase}" STREQUAL "debug")
set(DEBUG_BUILD TRUE)
elseif("${libomp_build_type_lowercase}" STREQUAL "relwithdebinfo")
set(RELWITHDEBINFO_BUILD TRUE)
elseif("${libomp_build_type_lowercase}" STREQUAL "minsizerel")
set(MINSIZEREL_BUILD TRUE)
endif()
# Include itt notify interface?
set(LIBOMP_USE_ITT_NOTIFY TRUE CACHE BOOL
"Enable ITT notify?")
# normal, profile, stubs library.
set(NORMAL_LIBRARY FALSE)
set(STUBS_LIBRARY FALSE)
set(PROFILE_LIBRARY FALSE)
if("${LIBOMP_LIB_TYPE}" STREQUAL "normal")
set(NORMAL_LIBRARY TRUE)
elseif("${LIBOMP_LIB_TYPE}" STREQUAL "profile")
set(PROFILE_LIBRARY TRUE)
elseif("${LIBOMP_LIB_TYPE}" STREQUAL "stubs")
set(STUBS_LIBRARY TRUE)
endif()
# Setting directory names
set(LIBOMP_BASE_DIR ${CMAKE_CURRENT_SOURCE_DIR})
set(LIBOMP_SRC_DIR ${LIBOMP_BASE_DIR}/src)
set(LIBOMP_TOOLS_DIR ${LIBOMP_BASE_DIR}/tools)
set(LIBOMP_INC_DIR ${LIBOMP_SRC_DIR}/include/${LIBOMP_OMP_VERSION})
set(LIBOMP_BINARY_DIR ${CMAKE_CURRENT_BINARY_DIR})
# Enabling Fortran if it is needed
if(${LIBOMP_FORTRAN_MODULES})
enable_language(Fortran)
endif()
# Enable MASM Compiler if it is needed (Windows only)
if(WIN32)
enable_language(ASM_MASM)
endif()
# Getting legal type/arch
libomp_get_legal_type(LIBOMP_LEGAL_TYPE)
libomp_get_legal_arch(LIBOMP_LEGAL_ARCH)
# Compiler flag checks, library checks, threading check, etc.
include(config-ix)
# Is there a quad precision data type available?
# TODO: Make this a real feature check
set(LIBOMP_USE_QUAD_PRECISION "${LIBOMP_HAVE_QUAD_PRECISION}" CACHE BOOL
"Should 128-bit precision entry points be built?")
if(LIBOMP_USE_QUAD_PRECISION AND (NOT LIBOMP_HAVE_QUAD_PRECISION))
libomp_error_say("128-bit quad precision functionality requested but not available")
endif()
# libgomp drop-in compatibility requires versioned symbols
set(LIBOMP_USE_VERSION_SYMBOLS "${LIBOMP_HAVE_VERSION_SYMBOLS}" CACHE BOOL
"Should version symbols be used? These provide binary compatibility with libgomp.")
if(LIBOMP_USE_VERSION_SYMBOLS AND (NOT LIBOMP_HAVE_VERSION_SYMBOLS))
libomp_error_say("Version symbols functionality requested but not available")
endif()
# On multinode systems, larger alignment is desired to avoid false sharing
set(LIBOMP_USE_INTERNODE_ALIGNMENT FALSE CACHE BOOL
"Should larger alignment (4096 bytes) be used for some locks and data structures?")
# Build code that allows the OpenMP library to conveniently interface with debuggers
set(LIBOMP_USE_DEBUGGER FALSE CACHE BOOL
"Enable debugger interface code?")
# Should we link to C++ library?
set(LIBOMP_USE_STDCPPLIB FALSE CACHE BOOL
"Should we link to C++ library?")
# TSX (x86) based locks have __asm code which can be troublesome for some compilers.
# TODO: Make this a real feature check
set(LIBOMP_USE_ADAPTIVE_LOCKS "${LIBOMP_HAVE_ADAPTIVE_LOCKS}" CACHE BOOL
"Should TSX-based lock be compiled (adaptive lock in kmp_lock.cpp). These are x86 specific.")
if(LIBOMP_USE_ADAPTIVE_LOCKS AND (NOT LIBOMP_HAVE_ADAPTIVE_LOCKS))
libomp_error_say("Adaptive locks (TSX) functionality requested but not available")
endif()
# - stats-gathering enables OpenMP stats where things like the number of
# parallel regions, clock ticks spent in particular openmp regions are recorded.
set(LIBOMP_STATS FALSE CACHE BOOL
"Stats-Gathering functionality?")
if(LIBOMP_STATS AND (NOT LIBOMP_HAVE_STATS))
libomp_error_say("Stats-gathering functionality requested but not available")
endif()
# The stats functionality requires the std c++ library
if(LIBOMP_STATS)
set(LIBOMP_USE_STDCPPLIB TRUE)
endif()
# Shared library can be switched to a static library
set(LIBOMP_ENABLE_SHARED TRUE CACHE BOOL
"Shared library instead of static library?")
if(WIN32 AND NOT LIBOMP_ENABLE_SHARED)
libomp_error_say("Static libraries requested but not available on Windows")
endif()
if(LIBOMP_USE_ITT_NOTIFY AND NOT LIBOMP_ENABLE_SHARED)
message(STATUS "ITT Notify not supported for static libraries - forcing ITT Notify off")
set(LIBOMP_USE_ITT_NOTIFY FALSE)
endif()
# OMPT-support
set(LIBOMP_OMPT_DEBUG FALSE CACHE BOOL
"Trace OMPT initialization?")
set(LIBOMP_OMPT_SUPPORT FALSE CACHE BOOL
"OMPT-support?")
set(LIBOMP_OMPT_BLAME TRUE CACHE BOOL
"OMPT-blame?")
set(LIBOMP_OMPT_TRACE TRUE CACHE BOOL
"OMPT-trace?")
if(LIBOMP_OMPT_SUPPORT AND (NOT LIBOMP_HAVE_OMPT_SUPPORT))
libomp_error_say("OpenMP Tools Interface requested but not available")
endif()
# TSAN-support
set(LIBOMP_TSAN_SUPPORT FALSE CACHE BOOL
"TSAN-support?")
if(LIBOMP_TSAN_SUPPORT AND (NOT LIBOMP_HAVE_TSAN_SUPPORT))
libomp_error_say("TSAN functionality requested but not available")
endif()
# Error check hwloc support after config-ix has run
if(LIBOMP_USE_HWLOC AND (NOT LIBOMP_HAVE_HWLOC))
libomp_error_say("Hwloc requested but not available")
endif()
# Setting final library name
set(LIBOMP_DEFAULT_LIB_NAME libomp)
if(${PROFILE_LIBRARY})
set(LIBOMP_DEFAULT_LIB_NAME ${LIBOMP_DEFAULT_LIB_NAME}prof)
endif()
if(${STUBS_LIBRARY})
set(LIBOMP_DEFAULT_LIB_NAME ${LIBOMP_DEFAULT_LIB_NAME}stubs)
endif()
set(LIBOMP_LIB_NAME ${LIBOMP_DEFAULT_LIB_NAME} CACHE STRING "Base OMP library name")
if(${LIBOMP_ENABLE_SHARED})
set(LIBOMP_LIBRARY_SUFFIX ${CMAKE_SHARED_LIBRARY_SUFFIX})
set(LIBOMP_LIBRARY_KIND SHARED)
set(LIBOMP_INSTALL_KIND LIBRARY)
else()
set(LIBOMP_LIBRARY_SUFFIX ${CMAKE_STATIC_LIBRARY_SUFFIX})
set(LIBOMP_LIBRARY_KIND STATIC)
set(LIBOMP_INSTALL_KIND ARCHIVE)
endif()
set(LIBOMP_LIB_FILE ${LIBOMP_LIB_NAME}${LIBOMP_LIBRARY_SUFFIX})
# Optional backwards compatibility aliases.
set(LIBOMP_INSTALL_ALIASES TRUE CACHE BOOL
"Install libgomp and libiomp5 library aliases for backwards compatibility")
# Print configuration after all variables are set.
if(${LIBOMP_STANDALONE_BUILD})
libomp_say("Operating System -- ${CMAKE_SYSTEM_NAME}")
libomp_say("Target Architecture -- ${LIBOMP_ARCH}")
if(${MIC})
libomp_say("Intel(R) MIC Architecture -- ${LIBOMP_MIC_ARCH}")
endif()
libomp_say("Build Type -- ${CMAKE_BUILD_TYPE}")
libomp_say("OpenMP Version -- ${LIBOMP_OMP_VERSION}")
libomp_say("Library Kind -- ${LIBOMP_LIBRARY_KIND}")
libomp_say("Library Type -- ${LIBOMP_LIB_TYPE}")
libomp_say("Fortran Modules -- ${LIBOMP_FORTRAN_MODULES}")
# will say development if all zeros
if(${LIBOMP_VERSION_BUILD} STREQUAL 00000000)
set(LIBOMP_BUILD Development)
else()
set(LIBOMP_BUILD ${LIBOMP_VERSION_BUILD})
endif()
libomp_say("Build -- ${LIBOMP_BUILD}")
libomp_say("Use Stats-gathering -- ${LIBOMP_STATS}")
libomp_say("Use Debugger-support -- ${LIBOMP_USE_DEBUGGER}")
libomp_say("Use ITT notify -- ${LIBOMP_USE_ITT_NOTIFY}")
libomp_say("Use OMPT-support -- ${LIBOMP_OMPT_SUPPORT}")
if(${LIBOMP_OMPT_SUPPORT})
libomp_say("Use OMPT-blame -- ${LIBOMP_OMPT_BLAME}")
libomp_say("Use OMPT-trace -- ${LIBOMP_OMPT_TRACE}")
endif()
libomp_say("Use Adaptive locks -- ${LIBOMP_USE_ADAPTIVE_LOCKS}")
libomp_say("Use quad precision -- ${LIBOMP_USE_QUAD_PRECISION}")
libomp_say("Use TSAN-support -- ${LIBOMP_TSAN_SUPPORT}")
libomp_say("Use Hwloc library -- ${LIBOMP_USE_HWLOC}")
endif()
add_subdirectory(src)
add_subdirectory(test)
+116
View File
@@ -0,0 +1,116 @@
README for the LLVM* OpenMP* Runtime Library
============================================
How to Build Documentation
==========================
The main documentation is in Doxygen* format, and this distribution
should come with pre-built PDF documentation in doc/Reference.pdf.
However, an HTML version can be built by executing:
% doxygen doc/doxygen/config
in the runtime directory.
That will produce HTML documentation in the doc/doxygen/generated
directory, which can be accessed by pointing a web browser at the
index.html file there.
If you don't have Doxygen installed, you can download it from
www.doxygen.org.
How to Build the LLVM* OpenMP* Runtime Library
==============================================
In-tree build:
$ cd where-you-want-to-live
Check out openmp into llvm/projects
$ cd where-you-want-to-build
$ mkdir build && cd build
$ cmake path/to/llvm -DCMAKE_C_COMPILER=<C compiler> -DCMAKE_CXX_COMPILER=<C++ compiler>
$ make omp
Out-of-tree build:
$ cd where-you-want-to-live
Check out openmp
$ cd where-you-want-to-live/openmp/runtime
$ mkdir build && cd build
$ cmake path/to/openmp -DCMAKE_C_COMPILER=<C compiler> -DCMAKE_CXX_COMPILER=<C++ compiler>
$ make
For details about building, please look at Build_With_CMake.txt
Architectures Supported
=======================
* IA-32 architecture
* Intel(R) 64 architecture
* Intel(R) Many Integrated Core Architecture
* ARM* architecture
* Aarch64 (64-bit ARM) architecture
* IBM(R) Power architecture (big endian)
* IBM(R) Power architecture (little endian)
* MIPS and MIPS64 architecture
Supported RTL Build Configurations
==================================
Supported Architectures: IA-32 architecture, Intel(R) 64, and
Intel(R) Many Integrated Core Architecture
----------------------------------------------
| icc/icl | gcc | clang |
--------------|---------------|----------------------------|
| Linux* OS | Yes(1,5) | Yes(2,4) | Yes(4,6,7) |
| FreeBSD* | No | No | Yes(4,6,7,8) |
| OS X* | Yes(1,3,4) | No | Yes(4,6,7) |
| Windows* OS | Yes(1,4) | No | No |
------------------------------------------------------------
(1) On IA-32 architecture and Intel(R) 64, icc/icl versions 12.x are
supported (12.1 is recommended).
(2) GCC* version 4.7 is supported.
(3) For icc on OS X*, OS X* version 10.5.8 is supported.
(4) Intel(R) Many Integrated Core Architecture not supported.
(5) On Intel(R) Many Integrated Core Architecture, icc/icl versions 13.0
or later are required.
(6) Clang* version 3.3 is supported.
(7) Clang* currently does not offer a software-implemented 128 bit extended
precision type. Thus, all entry points reliant on this type are removed
from the library and cannot be called in the user program. The following
functions are not available:
__kmpc_atomic_cmplx16_*
__kmpc_atomic_float16_*
__kmpc_atomic_*_fp
(8) Community contribution provided AS IS, not tested by Intel.
Supported Architectures: IBM(R) Power 7 and Power 8
-----------------------------
| gcc | clang |
--------------|------------|--------------|
| Linux* OS | Yes(1,2) | Yes(3,4) |
-------------------------------------------
(1) On Power 7, gcc version 4.8.2 is supported.
(2) On Power 8, gcc version 4.8.2 is supported.
(3) On Power 7, clang version 3.7 is supported.
(4) On Power 8, clang version 3.7 is supported.
Front-end Compilers that work with this RTL
===========================================
The following compilers are known to do compatible code generation for
this RTL: clang (from the OpenMP development branch at
http://clang-omp.github.io/ ), Intel compilers, GCC. See the documentation
for more details.
-----------------------------------------------------------------------
Notices
=======
*Other names and brands may be claimed as the property of others.
@@ -0,0 +1,73 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# Checking a fortran compiler flag
# There is no real trivial way to do this in CMake, so we implement it here
# this will have ${boolean} = TRUE if the flag succeeds, otherwise false.
function(libomp_check_fortran_flag flag boolean)
if(NOT DEFINED "${boolean}")
set(retval TRUE)
set(fortran_source
" program hello
print *, \"Hello World!\"
end program hello")
set(failed_regexes "[Ee]rror;[Uu]nknown;[Ss]kipping")
if(CMAKE_VERSION VERSION_GREATER 3.1 OR CMAKE_VERSION VERSION_EQUAL 3.1)
include(CheckFortranSourceCompiles)
check_fortran_source_compiles("${fortran_source}" ${boolean} FAIL_REGEX "${failed_regexes}")
set(${boolean} ${${boolean}} PARENT_SCOPE)
return()
else()
# Our manual check for cmake versions that don't have CheckFortranSourceCompiles
set(base_dir ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/fortran_flag_check)
file(MAKE_DIRECTORY ${base_dir})
file(WRITE ${base_dir}/fortran_source.f "${fortran_source}")
message(STATUS "Performing Test ${boolean}")
execute_process(
COMMAND ${CMAKE_Fortran_COMPILER} "${flag}" ${base_dir}/fortran_source.f
WORKING_DIRECTORY ${base_dir}
RESULT_VARIABLE exit_code
OUTPUT_VARIABLE OUTPUT
ERROR_VARIABLE OUTPUT
)
if(${exit_code} EQUAL 0)
foreach(regex IN LISTS failed_regexes)
if("${OUTPUT}" MATCHES ${regex})
set(retval FALSE)
endif()
endforeach()
else()
set(retval FALSE)
endif()
if(${retval})
set(${boolean} 1 CACHE INTERNAL "Test ${boolean}")
message(STATUS "Performing Test ${boolean} - Success")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Performing Fortran Compiler Flag test ${boolean} succeeded with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${fortran_source}\n")
else()
set(${boolean} "" CACHE INTERNAL "Test ${boolean}")
message(STATUS "Performing Test ${boolean} - Failed")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Performing Fortran Compiler Flag test ${boolean} failed with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${fortran_source}\n")
endif()
endif()
set(${boolean} ${retval} PARENT_SCOPE)
endif()
endfunction()
@@ -0,0 +1,68 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# Checking a linker flag to build a shared library
# There is no real trivial way to do this in CMake, so we implement it here
# this will have ${boolean} = TRUE if the flag succeeds, otherwise FALSE.
function(libomp_check_linker_flag flag boolean)
if(NOT DEFINED "${boolean}")
set(retval TRUE)
set(library_source
"int foo(int a) { return a*a; }")
set(cmake_source
"cmake_minimum_required(VERSION 2.8)
project(foo C)
set(CMAKE_SHARED_LINKER_FLAGS \"${flag}\")
add_library(foo SHARED src_to_link.c)")
set(failed_regexes "[Ee]rror;[Uu]nknown;[Ss]kipping;LINK : warning")
set(base_dir ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeTmp/link_flag_check_${boolean})
file(MAKE_DIRECTORY ${base_dir})
file(MAKE_DIRECTORY ${base_dir}/build)
file(WRITE ${base_dir}/src_to_link.c "${library_source}")
file(WRITE ${base_dir}/CMakeLists.txt "${cmake_source}")
message(STATUS "Performing Test ${boolean}")
try_compile(
try_compile_result
${base_dir}/build
${base_dir}
foo
OUTPUT_VARIABLE OUTPUT)
if(try_compile_result)
foreach(regex IN LISTS failed_regexes)
if("${OUTPUT}" MATCHES ${regex})
set(retval FALSE)
endif()
endforeach()
else()
set(retval FALSE)
endif()
if(${retval})
set(${boolean} 1 CACHE INTERNAL "Test ${boolean}")
message(STATUS "Performing Test ${boolean} - Success")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeOutput.log
"Performing C Linker Flag test ${boolean} succeeded with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${library_source}\n")
else()
set(${boolean} "" CACHE INTERNAL "Test ${boolean}")
message(STATUS "Performing Test ${boolean} - Failed")
file(APPEND ${CMAKE_BINARY_DIR}${CMAKE_FILES_DIRECTORY}/CMakeError.log
"Performing C Linker Flag test ${boolean} failed with the following output:\n"
"${OUTPUT}\n"
"Source file was:\n${library_source}\n")
endif()
set(${boolean} ${retval} PARENT_SCOPE)
endif()
endfunction()
@@ -0,0 +1,32 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
function(libomp_get_definitions_flags cppflags)
set(cppflags_local)
if(WIN32)
libomp_append(cppflags_local "-D _CRT_SECURE_NO_WARNINGS")
libomp_append(cppflags_local "-D _CRT_SECURE_NO_DEPRECATE")
libomp_append(cppflags_local "-D _WINDOWS")
libomp_append(cppflags_local "-D _WINNT")
libomp_append(cppflags_local "-D _WIN32_WINNT=0x0501")
libomp_append(cppflags_local "-D _USRDLL")
libomp_append(cppflags_local "-D _ITERATOR_DEBUG_LEVEL=0" IF_TRUE DEBUG_BUILD)
libomp_append(cppflags_local "-D _DEBUG" IF_TRUE DEBUG_BUILD)
else()
libomp_append(cppflags_local "-D _GNU_SOURCE")
libomp_append(cppflags_local "-D _REENTRANT")
endif()
# CMake doesn't include CPPFLAGS from environment, but we will.
set(${cppflags} ${cppflags_local} ${LIBOMP_CPPFLAGS} $ENV{CPPFLAGS} PARENT_SCOPE)
endfunction()
+100
View File
@@ -0,0 +1,100 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# LibompExports.cmake
# Copy library and header files into the exports/ subdirectory after library build
# Create the suffix for the export directory
# - Only add to suffix when not a default value
# - Example suffix: .deb.30.s1
# final export directory: exports/lin_32e.deb.30.s1/lib
# - These suffixes imply the build is a Debug, OpenMP 3.0, Stats-Gathering version of the library
set(libomp_suffix)
libomp_append(libomp_suffix .deb DEBUG_BUILD)
libomp_append(libomp_suffix .dia RELWITHDEBINFO_BUILD)
libomp_append(libomp_suffix .min MINSIZEREL_BUILD)
if(NOT "${LIBOMP_OMP_VERSION}" STREQUAL "45")
libomp_append(libomp_suffix .${LIBOMP_OMP_VERSION})
endif()
libomp_append(libomp_suffix .s1 LIBOMP_STATS)
libomp_append(libomp_suffix .ompt LIBOMP_OMPT_SUPPORT)
if(${LIBOMP_OMPT_SUPPORT})
libomp_append(libomp_suffix .no-ompt-blame IF_FALSE LIBOMP_OMPT_BLAME)
libomp_append(libomp_suffix .no-ompt-trace IF_FALSE LIBOMP_OMPT_TRACE)
endif()
string(REPLACE ";" "" libomp_suffix "${libomp_suffix}")
# Set exports locations
if(${MIC})
set(libomp_platform "${LIBOMP_PERL_SCRIPT_OS}_${LIBOMP_MIC_ARCH}") # e.g., lin_knf, lin_knc
else()
if(${IA32})
set(libomp_platform "${LIBOMP_PERL_SCRIPT_OS}_32")
elseif(${INTEL64})
set(libomp_platform "${LIBOMP_PERL_SCRIPT_OS}_32e")
else()
set(libomp_platform "${LIBOMP_PERL_SCRIPT_OS}_${LIBOMP_ARCH}") # e.g., lin_arm, lin_ppc64
endif()
endif()
set(LIBOMP_EXPORTS_DIR "${LIBOMP_BASE_DIR}/exports")
set(LIBOMP_EXPORTS_PLATFORM_DIR "${LIBOMP_EXPORTS_DIR}/${libomp_platform}${libomp_suffix}")
set(LIBOMP_EXPORTS_CMN_DIR "${LIBOMP_EXPORTS_DIR}/common${libomp_suffix}/include")
set(LIBOMP_EXPORTS_INC_DIR "${LIBOMP_EXPORTS_PLATFORM_DIR}/include")
set(LIBOMP_EXPORTS_MOD_DIR "${LIBOMP_EXPORTS_PLATFORM_DIR}/include_compat")
set(LIBOMP_EXPORTS_LIB_DIR "${LIBOMP_EXPORTS_DIR}/${libomp_platform}${libomp_suffix}/lib")
# Put headers in exports/ directory post build
add_custom_command(TARGET omp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_CMN_DIR}
COMMAND ${CMAKE_COMMAND} -E copy omp.h ${LIBOMP_EXPORTS_CMN_DIR}
)
if(${LIBOMP_OMPT_SUPPORT})
add_custom_command(TARGET omp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy ompt.h ${LIBOMP_EXPORTS_CMN_DIR}
)
endif()
if(${LIBOMP_FORTRAN_MODULES})
add_custom_command(TARGET libomp-mod POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_MOD_DIR}
COMMAND ${CMAKE_COMMAND} -E copy omp_lib.mod ${LIBOMP_EXPORTS_MOD_DIR}
COMMAND ${CMAKE_COMMAND} -E copy omp_lib_kinds.mod ${LIBOMP_EXPORTS_MOD_DIR}
)
add_custom_command(TARGET omp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E copy omp_lib.h ${LIBOMP_EXPORTS_CMN_DIR}
)
endif()
# Copy OpenMP library into exports/ directory post build
if(WIN32)
get_target_property(LIBOMP_OUTPUT_DIRECTORY omp RUNTIME_OUTPUT_DIRECTORY)
else()
get_target_property(LIBOMP_OUTPUT_DIRECTORY omp LIBRARY_OUTPUT_DIRECTORY)
endif()
if(NOT LIBOMP_OUTPUT_DIRECTORY)
set(LIBOMP_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_command(TARGET omp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_LIB_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE} ${LIBOMP_EXPORTS_LIB_DIR}
)
# Copy Windows import library into exports/ directory post build
if(WIN32)
get_target_property(LIBOMPIMP_OUTPUT_DIRECTORY ompimp ARCHIVE_OUTPUT_DIRECTORY)
if(NOT LIBOMPIMP_OUTPUT_DIRECTORY)
set(LIBOMPIMP_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
add_custom_command(TARGET ompimp POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${LIBOMP_EXPORTS_LIB_DIR}
COMMAND ${CMAKE_COMMAND} -E copy ${LIBOMPIMP_OUTPUT_DIRECTORY}/${LIBOMP_IMP_LIB_FILE} ${LIBOMP_EXPORTS_LIB_DIR}
)
endif()
@@ -0,0 +1,70 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# Determine the architecture from predefined compiler macros
# The architecture name can only contain alphanumeric characters and underscores (i.e., C identifier)
# void get_architecture(string* return_arch)
# - Returns the architecture in return_arch
function(libomp_get_architecture return_arch)
set(detect_arch_src_txt "
#if defined(__KNC__)
#error ARCHITECTURE=mic
#elif defined(__amd64__) || defined(__amd64) || defined(__x86_64__) || defined(__x86_64) || defined(_M_X64) || defined(_M_AMD64)
#error ARCHITECTURE=x86_64
#elif defined(__i386) || defined(__i386__) || defined(__IA32__) || defined(_M_I86) || defined(_M_IX86) || defined(__X86__) || defined(_X86_)
#error ARCHITECTURE=i386
#elif defined(__ARM_ARCH_7__) || defined(__ARM_ARCH_7R__) || defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7M__) || defined(__ARM_ARCH_7S__)
#error ARCHITECTURE=arm
#elif defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || defined(__ARM_ARCH_6T2__) || defined(__ARM_ARCH_6ZK__)
#error ARCHITECTURE=arm
#elif defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) || defined(__ARM_ARCH_5TEJ__)
#error ARCHITECTURE=arm
#elif defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__)
#error ARCHITECTURE=arm
#elif defined(__ARM_ARCH_3__) || defined(__ARM_ARCH_3M__)
#error ARCHITECTURE=arm
#elif defined(__ARM_ARCH_2__)
#error ARCHITECTURE=arm
#elif defined(__arm__) || defined(_M_ARM) || defined(_ARM)
#error ARCHITECTURE=arm
#elif defined(__aarch64__)
#error ARCHITECTURE=aarch64
#elif defined(__powerpc64__) && defined(__LITTLE_ENDIAN__)
#error ARCHITECTURE=ppc64le
#elif defined(__powerpc64__)
#error ARCHITECTURE=ppc64
#elif defined(__mips__) && defined(__mips64)
#error ARCHITECTURE=mips64
#elif defined(__mips__) && !defined(__mips64)
#error ARCHITECTURE=mips
#else
#error ARCHITECTURE=UnknownArchitecture
#endif
")
# Write out ${detect_arch_src_txt} to a file within the cmake/ subdirectory
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/libomp_detect_arch.c" ${detect_arch_src_txt})
# Try to compile using the C Compiler. It will always error out with an #error directive, so store error output to ${local_architecture}
try_run(run_dummy compile_dummy "${CMAKE_CURRENT_BINARY_DIR}" "${CMAKE_CURRENT_BINARY_DIR}/libomp_detect_arch.c" COMPILE_OUTPUT_VARIABLE local_architecture)
# Match the important architecture line and store only that matching string in ${local_architecture}
string(REGEX MATCH "ARCHITECTURE=([a-zA-Z0-9_]+)" local_architecture "${local_architecture}")
# Get rid of the ARCHITECTURE= part of the string
string(REPLACE "ARCHITECTURE=" "" local_architecture "${local_architecture}")
# set the return value to the architecture detected (e.g., 32e, 32, arm, ppc64, etc.)
set(${return_arch} "${local_architecture}" PARENT_SCOPE)
# Remove ${detect_arch_src_txt} from cmake/ subdirectory
file(REMOVE "${CMAKE_CURRENT_BINARY_DIR}/libomp_detect_arch.c")
endfunction()
+211
View File
@@ -0,0 +1,211 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# Setup the flags correctly for cmake (covert to string)
# Pretty them up (STRIP any beginning and trailing whitespace,
# remove duplicates, remove empty entries)
macro(libomp_setup_flags flags)
if(NOT "${${flags}}" STREQUAL "") # if flags are empty, don't do anything
set(flags_local)
list(REMOVE_DUPLICATES ${flags}) # remove duplicates
list(REMOVE_ITEM ${flags} "") # remove empty items
libomp_list_to_string("${${flags}}" flags_local)
string(STRIP "${flags_local}" flags_local)
set(${flags} "${flags_local}")
endif()
endmacro()
# Gets flags common to both the C and C++ compiler
function(libomp_get_c_and_cxxflags_common flags)
set(flags_local)
libomp_append(flags_local -std=c++11 LIBOMP_HAVE_STD_CPP11_FLAG)
libomp_append(flags_local -fno-exceptions LIBOMP_HAVE_FNO_EXCEPTIONS_FLAG)
libomp_append(flags_local -fno-rtti LIBOMP_HAVE_FNO_RTTI_FLAG)
if(${LIBOMP_ENABLE_WERROR})
libomp_append(flags_local -Werror LIBOMP_HAVE_WERROR_FLAG)
endif()
libomp_append(flags_local -Wno-sign-compare LIBOMP_HAVE_WNO_SIGN_COMPARE_FLAG)
libomp_append(flags_local -Wno-unused-function LIBOMP_HAVE_WNO_UNUSED_FUNCTION_FLAG)
libomp_append(flags_local -Wno-unused-local-typedef LIBOMP_HAVE_WNO_UNUSED_LOCAL_TYPEDEF_FLAG)
libomp_append(flags_local -Wno-unused-value LIBOMP_HAVE_WNO_UNUSED_VALUE_FLAG)
libomp_append(flags_local -Wno-unused-variable LIBOMP_HAVE_WNO_UNUSED_VARIABLE_FLAG)
libomp_append(flags_local -Wno-switch LIBOMP_HAVE_WNO_SWITCH_FLAG)
libomp_append(flags_local -Wno-covered-switch-default LIBOMP_HAVE_WNO_COVERED_SWITCH_DEFAULT_FLAG)
libomp_append(flags_local -Wno-deprecated-register LIBOMP_HAVE_WNO_DEPRECATED_REGISTER_FLAG)
libomp_append(flags_local -Wno-gnu-anonymous-struct LIBOMP_HAVE_WNO_GNU_ANONYMOUS_STRUCT_FLAG)
libomp_append(flags_local -Wno-unknown-pragmas LIBOMP_HAVE_WNO_UNKNOWN_PRAGMAS_FLAG)
libomp_append(flags_local -Wno-missing-field-initializers LIBOMP_HAVE_WNO_MISSING_FIELD_INITIALIZERS_FLAG)
libomp_append(flags_local -Wno-missing-braces LIBOMP_HAVE_WNO_MISSING_BRACES_FLAG)
libomp_append(flags_local -Wno-comment LIBOMP_HAVE_WNO_COMMENT_FLAG)
libomp_append(flags_local -Wno-self-assign LIBOMP_HAVE_WNO_SELF_ASSIGN_FLAG)
libomp_append(flags_local -Wno-vla-extension LIBOMP_HAVE_WNO_VLA_EXTENSION_FLAG)
libomp_append(flags_local -Wno-format-pedantic LIBOMP_HAVE_WNO_FORMAT_PEDANTIC_FLAG)
libomp_append(flags_local /GS LIBOMP_HAVE_GS_FLAG)
libomp_append(flags_local /EHsc LIBOMP_HAVE_EHSC_FLAG)
libomp_append(flags_local /Oy- LIBOMP_HAVE_OY__FLAG)
# Intel(R) C Compiler flags
libomp_append(flags_local /Qsafeseh LIBOMP_HAVE_QSAFESEH_FLAG)
libomp_append(flags_local -Qoption,cpp,--extended_float_types LIBOMP_HAVE_EXTENDED_FLOAT_TYPES_FLAG)
libomp_append(flags_local -Qlong_double LIBOMP_HAVE_LONG_DOUBLE_FLAG)
libomp_append(flags_local -Qdiag-disable:177 LIBOMP_HAVE_DIAG_DISABLE_177_FLAG)
if(${RELEASE_BUILD} OR ${RELWITHDEBINFO_BUILD})
libomp_append(flags_local -Qinline-min-size=1 LIBOMP_HAVE_INLINE_MIN_SIZE_FLAG)
endif()
# Architectural C and C++ flags
if(${IA32})
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
libomp_append(flags_local -m32 LIBOMP_HAVE_M32_FLAG)
endif()
libomp_append(flags_local /arch:SSE2 LIBOMP_HAVE_ARCH_SSE2_FLAG)
libomp_append(flags_local -msse2 LIBOMP_HAVE_MSSE2_FLAG)
libomp_append(flags_local -falign-stack=maintain-16-byte LIBOMP_HAVE_FALIGN_STACK_FLAG)
elseif(${MIC})
libomp_append(flags_local -mmic LIBOMP_HAVE_MMIC_FLAG)
libomp_append(flags_local -ftls-model=initial-exec LIBOMP_HAVE_FTLS_MODEL_FLAG)
libomp_append(flags_local "-opt-streaming-stores never" LIBOMP_HAVE_OPT_STREAMING_STORES_FLAG)
endif()
set(${flags} ${flags_local} PARENT_SCOPE)
endfunction()
# C compiler flags
function(libomp_get_cflags cflags)
set(cflags_local)
libomp_get_c_and_cxxflags_common(cflags_local)
# flags only for the C Compiler
libomp_append(cflags_local /TP LIBOMP_HAVE_TP_FLAG)
libomp_append(cflags_local "-x c++" LIBOMP_HAVE_X_CPP_FLAG)
set(cflags_local ${cflags_local} ${LIBOMP_CFLAGS})
libomp_setup_flags(cflags_local)
set(${cflags} ${cflags_local} PARENT_SCOPE)
endfunction()
# C++ compiler flags
function(libomp_get_cxxflags cxxflags)
set(cxxflags_local)
libomp_get_c_and_cxxflags_common(cxxflags_local)
set(cxxflags_local ${cxxflags_local} ${LIBOMP_CXXFLAGS})
libomp_setup_flags(cxxflags_local)
set(${cxxflags} ${cxxflags_local} PARENT_SCOPE)
endfunction()
# Assembler flags
function(libomp_get_asmflags asmflags)
set(asmflags_local)
libomp_append(asmflags_local "-x assembler-with-cpp" LIBOMP_HAVE_X_ASSEMBLER_WITH_CPP_FLAG)
# Architectural assembler flags
if(${IA32})
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
libomp_append(asmflags_local -m32 LIBOMP_HAVE_M32_FLAG)
endif()
libomp_append(asmflags_local /safeseh LIBOMP_HAVE_SAFESEH_MASM_FLAG)
libomp_append(asmflags_local /coff LIBOMP_HAVE_COFF_MASM_FLAG)
elseif(${MIC})
libomp_append(asmflags_local -mmic LIBOMP_HAVE_MMIC_FLAG)
endif()
set(asmflags_local ${asmflags_local} ${LIBOMP_ASMFLAGS})
libomp_setup_flags(asmflags_local)
set(${asmflags} ${asmflags_local} PARENT_SCOPE)
endfunction()
# Linker flags
function(libomp_get_ldflags ldflags)
set(ldflags_local)
libomp_append(ldflags_local "${CMAKE_LINK_DEF_FILE_FLAG}${CMAKE_CURRENT_BINARY_DIR}/${LIBOMP_LIB_NAME}.def"
IF_DEFINED CMAKE_LINK_DEF_FILE_FLAG)
libomp_append(ldflags_local "${CMAKE_C_OSX_CURRENT_VERSION_FLAG}${LIBOMP_VERSION_MAJOR}.${LIBOMP_VERSION_MINOR}"
IF_DEFINED CMAKE_C_OSX_CURRENT_VERSION_FLAG)
libomp_append(ldflags_local "${CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG}${LIBOMP_VERSION_MAJOR}.${LIBOMP_VERSION_MINOR}"
IF_DEFINED CMAKE_C_OSX_COMPATIBILITY_VERSION_FLAG)
libomp_append(ldflags_local -Wl,--warn-shared-textrel LIBOMP_HAVE_WARN_SHARED_TEXTREL_FLAG)
libomp_append(ldflags_local -Wl,--as-needed LIBOMP_HAVE_AS_NEEDED_FLAG)
libomp_append(ldflags_local "-Wl,--version-script=${LIBOMP_SRC_DIR}/exports_so.txt" LIBOMP_HAVE_VERSION_SCRIPT_FLAG)
libomp_append(ldflags_local -static-libgcc LIBOMP_HAVE_STATIC_LIBGCC_FLAG)
libomp_append(ldflags_local -Wl,-z,noexecstack LIBOMP_HAVE_Z_NOEXECSTACK_FLAG)
libomp_append(ldflags_local -Wl,-fini=__kmp_internal_end_fini LIBOMP_HAVE_FINI_FLAG)
libomp_append(ldflags_local -no-intel-extensions LIBOMP_HAVE_NO_INTEL_EXTENSIONS_FLAG)
libomp_append(ldflags_local -static-intel LIBOMP_HAVE_STATIC_INTEL_FLAG)
libomp_append(ldflags_local /SAFESEH LIBOMP_HAVE_SAFESEH_FLAG)
# Architectural linker flags
if(${IA32})
if(CMAKE_SIZEOF_VOID_P EQUAL 8)
libomp_append(ldflags_local -m32 LIBOMP_HAVE_M32_FLAG)
endif()
libomp_append(ldflags_local -msse2 LIBOMP_HAVE_MSSE2_FLAG)
elseif(${MIC})
libomp_append(ldflags_local -mmic LIBOMP_HAVE_MMIC_FLAG)
libomp_append(ldflags_local -Wl,-x LIBOMP_HAVE_X_FLAG)
endif()
set(ldflags_local ${ldflags_local} ${LIBOMP_LDFLAGS})
libomp_setup_flags(ldflags_local)
set(${ldflags} ${ldflags_local} PARENT_SCOPE)
endfunction()
# Library flags
function(libomp_get_libflags libflags)
set(libflags_local)
libomp_append(libflags_local "${CMAKE_THREAD_LIBS_INIT}")
libomp_append(libflags_local "${LIBOMP_HWLOC_LIBRARY}" LIBOMP_USE_HWLOC)
if(${IA32})
libomp_append(libflags_local -lirc_pic LIBOMP_HAVE_IRC_PIC_LIBRARY)
endif()
IF(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
libomp_append(libflags_local -lm)
ENDIF(${CMAKE_SYSTEM_NAME} MATCHES "NetBSD")
set(libflags_local ${libflags_local} ${LIBOMP_LIBFLAGS})
libomp_setup_flags(libflags_local)
set(${libflags} ${libflags_local} PARENT_SCOPE)
endfunction()
# Fortran flags
function(libomp_get_fflags fflags)
set(fflags_local)
if(${IA32})
libomp_append(fflags_local -m32 LIBOMP_HAVE_M32_FORTRAN_FLAG)
endif()
set(fflags_local ${fflags_local} ${LIBOMP_FFLAGS})
libomp_setup_flags(fflags_local)
set(${fflags} ${fflags_local} PARENT_SCOPE)
endfunction()
# Perl generate-defs.pl flags (For Windows only)
function(libomp_get_gdflags gdflags)
set(gdflags_local)
if(${IA32})
set(libomp_gdflag_arch arch_32)
elseif(${INTEL64})
set(libomp_gdflag_arch arch_32e)
else()
set(libomp_gdflag_arch arch_${LIBOMP_ARCH})
endif()
libomp_append(gdflags_local "-D ${libomp_gdflag_arch}")
libomp_append(gdflags_local "-D msvc_compat")
libomp_append(gdflags_local "-D norm" NORMAL_LIBRARY)
libomp_append(gdflags_local "-D prof" PROFILE_LIBRARY)
libomp_append(gdflags_local "-D stub" STUBS_LIBRARY)
libomp_append(gdflags_local "-D HAVE_QUAD" LIBOMP_USE_QUAD_PRECISION)
libomp_append(gdflags_local "-D USE_DEBUGGER" LIBOMP_USE_DEBUGGER)
if(${LIBOMP_OMP_VERSION} GREATER 50 OR ${LIBOMP_OMP_VERSION} EQUAL 50)
libomp_append(gdflags_local "-D OMP_50")
endif()
if(${LIBOMP_OMP_VERSION} GREATER 45 OR ${LIBOMP_OMP_VERSION} EQUAL 45)
libomp_append(gdflags_local "-D OMP_45")
endif()
if(${LIBOMP_OMP_VERSION} GREATER 40 OR ${LIBOMP_OMP_VERSION} EQUAL 40)
libomp_append(gdflags_local "-D OMP_40")
endif()
if(${LIBOMP_OMP_VERSION} GREATER 30 OR ${LIBOMP_OMP_VERSION} EQUAL 30)
libomp_append(gdflags_local "-D OMP_30")
endif()
if(${DEBUG_BUILD} OR ${RELWITHDEBINFO_BUILD})
libomp_append(gdflags_local "-D KMP_DEBUG")
endif()
set(${gdflags} ${gdflags_local} PARENT_SCOPE)
endfunction()
+228
View File
@@ -0,0 +1,228 @@
#
#//===----------------------------------------------------------------------===//
#//
#// The LLVM Compiler Infrastructure
#//
#// This file is dual licensed under the MIT and the University of Illinois Open
#// Source Licenses. See LICENSE.txt for details.
#//
#//===----------------------------------------------------------------------===//
#
# The following micro-tests are small tests to perform on the library just created.
# There are currently five micro-tests:
# (1) test-touch
# - Compile and run a small program using newly created libomp library
# - Fails if test-touch.c does not compile or if test-touch.c does not run after compilation
# - Program dependencies: gcc or g++, grep, bourne shell
# - Available for all Unix,Mac,Windows builds. Not available on Intel(R) MIC Architecture builds.
# (2) test-relo
# - Tests dynamic libraries for position-dependent code (can not have any position dependent code)
# - Fails if TEXTREL is in output of readelf -d libomp.so command
# - Program dependencies: readelf, grep, bourne shell
# - Available for Unix, Intel(R) MIC Architecture dynamic library builds. Not available otherwise.
# (3) test-execstack
# - Tests if stack is executable
# - Fails if stack is executable. Should only be readable and writable. Not exectuable.
# - Program dependencies: perl, readelf
# - Available for Unix dynamic library builds. Not available otherwise.
# (4) test-instr (Intel(R) MIC Architecutre only)
# - Tests Intel(R) MIC Architecture libraries for valid instruction set
# - Fails if finds invalid instruction for Intel(R) MIC Architecture (wasn't compiled with correct flags)
# - Program dependencies: perl, objdump
# - Available for Intel(R) MIC Architecture and i386 builds. Not available otherwise.
# (5) test-deps
# - Tests newly created libomp for library dependencies
# - Fails if sees a dependence not listed in td_exp variable below
# - Program dependencies: perl, (unix)readelf, (mac)otool[64], (windows)link.exe
# - Available for Unix,Mac,Windows, Intel(R) MIC Architecture dynamic builds and Windows
# static builds. Not available otherwise.
# get library location
if(WIN32)
get_target_property(LIBOMP_OUTPUT_DIRECTORY omp RUNTIME_OUTPUT_DIRECTORY)
get_target_property(LIBOMPIMP_OUTPUT_DIRECTORY ompimp ARCHIVE_OUTPUT_DIRECTORY)
if(NOT LIBOMPIMP_OUTPUT_DIRECTORY)
set(LIBOMPIMP_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
else()
get_target_property(LIBOMP_OUTPUT_DIRECTORY omp LIBRARY_OUTPUT_DIRECTORY)
endif()
if(NOT LIBOMP_OUTPUT_DIRECTORY)
set(LIBOMP_OUTPUT_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR})
endif()
# test-touch
find_program(LIBOMP_SHELL sh)
if(WIN32)
if(LIBOMP_SHELL)
set(libomp_test_touch_targets test-touch-md/.success test-touch-mt/.success)
endif()
# pick test-touch compiler
set(libomp_test_touch_compiler ${CMAKE_C_COMPILER})
# test-touch compilation flags
libomp_append(libomp_test_touch_cflags /nologo)
libomp_append(libomp_test_touch_libs ${LIBOMPIMP_OUTPUT_DIRECTORY}/${LIBOMP_IMP_LIB_FILE})
if(${IA32})
libomp_append(libomp_test_touch_ldflags /safeseh)
endif()
else() # (Unix based systems, Intel(R) MIC Architecture, and Mac)
if(LIBOMP_SHELL)
set(libomp_test_touch_targets test-touch-rt/.success)
endif()
# pick test-touch compiler
if(${LIBOMP_USE_STDCPPLIB})
set(libomp_test_touch_compiler ${CMAKE_CXX_COMPILER})
else()
set(libomp_test_touch_compiler ${CMAKE_C_COMPILER})
endif()
# test-touch compilation flags
libomp_append(libomp_test_touch_libs "${CMAKE_THREAD_LIBS_INIT}")
if(${IA32})
libomp_append(libomp_test_touch_cflags -m32 LIBOMP_HAVE_M32_FLAG)
endif()
libomp_append(libomp_test_touch_libs ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE})
libomp_append(libomp_test_touch_libs "${LIBOMP_HWLOC_LIBRARY}" LIBOMP_USE_HWLOC)
if(APPLE)
set(libomp_test_touch_env "DYLD_LIBRARY_PATH=.:${LIBOMP_OUTPUT_DIRECTORY}:$ENV{DYLD_LIBRARY_PATH}")
libomp_append(libomp_test_touch_ldflags "-Wl,-rpath,${LIBOMP_HWLOC_LIBRARY_DIR}" LIBOMP_USE_HWLOC)
else()
set(libomp_test_touch_env "LD_LIBRARY_PATH=.:${LIBOMP_OUTPUT_DIRECTORY}:$ENV{LD_LIBRARY_PATH}")
libomp_append(libomp_test_touch_ldflags "-Wl,-rpath=${LIBOMP_HWLOC_LIBRARY_DIR}" LIBOMP_USE_HWLOC)
endif()
endif()
macro(libomp_test_touch_recipe test_touch_dir)
set(libomp_test_touch_dependencies ${LIBOMP_SRC_DIR}/test-touch.c omp)
set(libomp_test_touch_exe ${test_touch_dir}/test-touch${CMAKE_EXECUTABLE_SUFFIX})
set(libomp_test_touch_obj ${test_touch_dir}/test-touch${CMAKE_C_OUTPUT_EXTENSION})
if(WIN32)
if(${RELEASE_BUILD} OR ${RELWITHDEBINFO_BUILD})
if(${test_touch_dir} MATCHES "test-touch-mt")
libomp_append(libomp_test_touch_cflags /MT)
else()
libomp_append(libomp_test_touch_cflags /MD)
endif()
else()
if(${test_touch_dir} MATCHES "test-touch-mt")
libomp_append(libomp_test_touch_cflags /MTd)
else()
libomp_append(libomp_test_touch_cflags /MDd)
endif()
endif()
set(libomp_test_touch_out_flags -Fe${libomp_test_touch_exe} -Fo${libomp_test_touch_obj})
list(APPEND libomp_test_touch_dependencies ompimp)
else()
set(libomp_test_touch_out_flags -o ${libomp_test_touch_exe})
endif()
add_custom_command(
OUTPUT ${test_touch_dir}/.success ${libomp_test_touch_exe} ${libomp_test_touch_obj}
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/${test_touch_dir}
COMMAND ${CMAKE_COMMAND} -E remove -f ${test_touch_dir}/*
COMMAND ${libomp_test_touch_compiler} ${libomp_test_touch_out_flags} ${libomp_test_touch_cflags}
${LIBOMP_SRC_DIR}/test-touch.c ${libomp_test_touch_ldflags} ${libomp_test_touch_libs}
COMMAND ${LIBOMP_SHELL} -c \"${libomp_test_touch_env} ${libomp_test_touch_exe}\"
COMMAND ${CMAKE_COMMAND} -E touch ${test_touch_dir}/.success
DEPENDS ${libomp_test_touch_dependencies}
)
endmacro()
libomp_append(libomp_test_touch_env "KMP_VERSION=1")
add_custom_target(libomp-test-touch DEPENDS ${libomp_test_touch_targets})
if(WIN32)
libomp_test_touch_recipe(test-touch-mt)
libomp_test_touch_recipe(test-touch-md)
else()
libomp_test_touch_recipe(test-touch-rt)
endif()
# test-relo
add_custom_target(libomp-test-relo DEPENDS test-relo/.success)
add_custom_command(
OUTPUT test-relo/.success test-relo/readelf.log
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/test-relo
COMMAND readelf -d ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE} > test-relo/readelf.log
COMMAND grep -e TEXTREL test-relo/readelf.log \; test $$? -eq 1
COMMAND ${CMAKE_COMMAND} -E touch test-relo/.success
DEPENDS omp
)
# test-execstack
add_custom_target(libomp-test-execstack DEPENDS test-execstack/.success)
add_custom_command(
OUTPUT test-execstack/.success
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/test-execstack
COMMAND ${PERL_EXECUTABLE} ${LIBOMP_TOOLS_DIR}/check-execstack.pl
--arch=${LIBOMP_PERL_SCRIPT_ARCH} ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE}
COMMAND ${CMAKE_COMMAND} -E touch test-execstack/.success
DEPENDS omp
)
# test-instr
add_custom_target(libomp-test-instr DEPENDS test-instr/.success)
add_custom_command(
OUTPUT test-instr/.success
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/test-instr
COMMAND ${PERL_EXECUTABLE} ${LIBOMP_TOOLS_DIR}/check-instruction-set.pl --os=${LIBOMP_PERL_SCRIPT_OS}
--arch=${LIBOMP_PERL_SCRIPT_ARCH} --show --mic-arch=${LIBOMP_MIC_ARCH} ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE}
COMMAND ${CMAKE_COMMAND} -E touch test-instr/.success
DEPENDS omp ${LIBOMP_TOOLS_DIR}/check-instruction-set.pl
)
# test-deps
add_custom_target(libomp-test-deps DEPENDS test-deps/.success)
set(libomp_expected_library_deps)
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
set(libomp_expected_library_deps libc.so.7 libthr.so.3)
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
elseif(CMAKE_SYSTEM_NAME MATCHES "NetBSD")
set(libomp_expected_library_deps libc.so.12 libpthread.so.1 libm.so.0)
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
elseif(APPLE)
set(libomp_expected_library_deps /usr/lib/libSystem.B.dylib)
elseif(WIN32)
set(libomp_expected_library_deps kernel32.dll)
libomp_append(libomp_expected_library_deps psapi.dll LIBOMP_OMPT_SUPPORT)
else()
if(${MIC})
set(libomp_expected_library_deps libc.so.6 libpthread.so.0 libdl.so.2)
if("${LIBOMP_MIC_ARCH}" STREQUAL "knf")
libomp_append(libomp_expected_library_deps ld-linux-l1om.so.2)
libomp_append(libomp_expected_library_deps libgcc_s.so.1)
elseif("${LIBOMP_MIC_ARCH}" STREQUAL "knc")
libomp_append(libomp_expected_library_deps ld-linux-k1om.so.2)
endif()
else()
set(libomp_expected_library_deps libdl.so.2 libgcc_s.so.1)
if(${IA32})
libomp_append(libomp_expected_library_deps libc.so.6)
libomp_append(libomp_expected_library_deps ld-linux.so.2)
elseif(${INTEL64})
libomp_append(libomp_expected_library_deps libc.so.6)
libomp_append(libomp_expected_library_deps ld-linux-x86-64.so.2)
elseif(${ARM})
libomp_append(libomp_expected_library_deps libc.so.6)
libomp_append(libomp_expected_library_deps libffi.so.6)
libomp_append(libomp_expected_library_deps libffi.so.5)
libomp_append(libomp_expected_library_deps ld-linux-armhf.so.3)
elseif(${PPC64})
libomp_append(libomp_expected_library_deps libc.so.6)
libomp_append(libomp_expected_library_deps ld64.so.1)
elseif(${MIPS} OR ${MIPS64})
libomp_append(libomp_expected_library_deps libc.so.6)
libomp_append(libomp_expected_library_deps ld.so.1)
endif()
libomp_append(libomp_expected_library_deps libpthread.so.0 IF_FALSE STUBS_LIBRARY)
libomp_append(libomp_expected_library_deps libhwloc.so.5 LIBOMP_USE_HWLOC)
endif()
libomp_append(libomp_expected_library_deps libstdc++.so.6 LIBOMP_USE_STDCPPLIB)
libomp_append(libomp_expected_library_deps libm.so.6 LIBOMP_STATS)
endif()
# Perl script expects comma separated list
string(REPLACE ";" "," libomp_expected_library_deps "${libomp_expected_library_deps}")
add_custom_command(
OUTPUT test-deps/.success
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_CURRENT_BINARY_DIR}/test-deps
COMMAND ${PERL_EXECUTABLE} ${LIBOMP_TOOLS_DIR}/check-depends.pl --os=${LIBOMP_PERL_SCRIPT_OS}
--arch=${LIBOMP_PERL_SCRIPT_ARCH} --expected="${libomp_expected_library_deps}" ${LIBOMP_OUTPUT_DIRECTORY}/${LIBOMP_LIB_FILE}
COMMAND ${CMAKE_COMMAND} -E touch test-deps/.success
DEPENDS omp ${LIBOMP_TOOLS_DIR}/check-depends.pl
)

Some files were not shown because too many files have changed in this diff Show More