提交 3116e128 编写于 作者: M Megvii Engine Team

fix(ci/integration_test): fix benchmark torch version

GitOrigin-RevId: bd964ed505e8ca2a544db66a89dc109ff289aaca
上级 66f13586
#.rst:
# FindBANG
# --------
#
# Tools for building BANG C files: libraries and build dependencies.
#
# This script locates the CAMBRICON BANG C tools. It should work on linux,
# windows, and mac and should be reasonably up to date with BANG C
# releases.
#
# This script makes use of the standard find_package arguments of
# <VERSION>, REQUIRED and QUIET. BANG_FOUND will report if an
# acceptable version of BANG was found.
#
# The following variables affect the behavior of the macros in the
# script (in alphebetical order). Note that any of these flags can be
# changed multiple times in the same directory before calling
#
# BANG_CNCC_FLAGS
# -- Additional CNCC command line arguments. NOTE: multiple arguments must be
# semi-colon delimited (e.g. --bang-mlu-arch=xxx;-Wall)
#
# BANG_TARGET_CPU_ARCH
# -- Specify the name of the class of CPU architecture for which the input
# files must be compiled (e.g. specify BANG_TARGET_CPU_ARCH=armv8a,
# will append --target=armv8a to BANG_CNCC_FLAGS)
#
# This code is licensed under the MIT License. See the FindBANG.cmake script
# for the text of the license.
# The MIT License
#
# License for the specific language governing rights and limitations under
# 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.
#
# MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
#
# Copyright (c) 2014-2020 Megvii Inc. All rights reserved.
#
# Unless required by applicable law or agreed to in writing,
# software distributed under the License is distributed on an
# "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#
# This file has been modified by Megvii ("Megvii Modifications").
# All Megvii Modifications are Copyright (C) 2014-2019 Megvii Inc. All rights reserved
###############################################################################
# FindBANG.cmake
###############################################################################
# Check for required components
###############################################################################
set(BANG_FOUND TRUE)
###############################################################################
# This macro helps us find the location of helper files we will need the full path to
###############################################################################
macro(BANG_FIND_HELPER_FILE _name _extension)
set(_full_name "${_name}.${_extension}")
# CMAKE_CURRENT_LIST_FILE contains the full path to the file currently being
# processed. Using this variable, we can pull out the current path, and
# provide a way to get access to the other files we need local to here.
get_filename_component(CMAKE_CURRENT_LIST_DIR "${CMAKE_CURRENT_LIST_FILE}" PATH)
set(BANG_${_name} "${CMAKE_CURRENT_LIST_DIR}/${_full_name}")
if(NOT EXISTS "${BANG_${_name}}")
set(error_message "${_full_name} not found in ${CMAKE_CURRENT_LIST_DIR}")
if(BANG_FIND_REQUIRED)
message(FATAL_ERROR "${error_message}")
else()
if(NOT BANG_FIND_QUIETLY)
message(STATUS "${error_message}")
endif()
endif()
endif()
# Set this variable as internal, so the user isn't bugged with it.
set(BANG_${_name} ${BANG_${_name}} CACHE INTERNAL "Location of ${_full_name}" FORCE)
endmacro()
bang_find_helper_file(parse_cnbin cmake)
bang_find_helper_file(make2cmake cmake)
bang_find_helper_file(run_cncc cmake)
###############################################################################
# Add include directories to pass to the cncc command.
###############################################################################
macro(BANG_INCLUDE_DIRECTORIES)
foreach(dir ${ARGN})
list(APPEND BANG_CNCC_INCLUDE_ARGS_USER -I${dir})
endforeach()
endmacro()
##############################################################################
# Separate the OPTIONS out from the sources
##############################################################################
macro(BANG_GET_SOURCES_AND_OPTIONS _sources _cmake_options _options)
set( ${_sources} )
set( ${_cmake_options} )
set( ${_options} )
set( _found_options FALSE )
foreach(arg ${ARGN})
if("x${arg}" STREQUAL "xOPTIONS")
set( _found_options TRUE )
elseif(
"x${arg}" STREQUAL "xWIN32" OR
"x${arg}" STREQUAL "xMACOSX_BUNDLE" OR
"x${arg}" STREQUAL "xEXCLUDE_FROM_ALL" OR
"x${arg}" STREQUAL "xSTATIC" OR
"x${arg}" STREQUAL "xSHARED" OR
"x${arg}" STREQUAL "xMODULE"
)
list(APPEND ${_cmake_options} ${arg})
else()
if ( _found_options )
list(APPEND ${_options} ${arg})
else()
# Assume this is a file
list(APPEND ${_sources} ${arg})
endif()
endif()
endforeach()
endmacro()
##############################################################################
# Parse the OPTIONS from ARGN and set the variables prefixed by _option_prefix
##############################################################################
macro(BANG_PARSE_CNCC_OPTIONS _option_prefix)
set( _found_config )
foreach(arg ${ARGN})
# Determine if we are dealing with a perconfiguration flag
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
if (arg STREQUAL "${config_upper}")
set( _found_config _${arg})
# Set arg to nothing to keep it from being processed further
set( arg )
endif()
endforeach()
if ( arg )
list(APPEND ${_option_prefix}${_found_config} "${arg}")
endif()
endforeach()
endmacro()
#####################################################################
# BANG_INCLUDE_CNCC_DEPENDENCIES
# So we want to try and include the dependency file if it exists. If
# it doesn't exist then we need to create an empty one, so we can
# include it.
# If it does exist, then we need to check to see if all the files it
# depends on exist. If they don't then we should clear the dependency
# file and regenerate it later. This covers the case where a header
# file has disappeared or moved.
#####################################################################
macro(BANG_INCLUDE_CNCC_DEPENDENCIES dependency_file)
set(BANG_CNCC_DEPEND)
set(BANG_CNCC_DEPEND_REGENERATE FALSE)
# Include the dependency file. Create it first if it doesn't exist . The
# INCLUDE puts a dependency that will force CMake to rerun and bring in the
# new info when it changes. DO NOT REMOVE THIS (as I did and spent a few
# hours figuring out why it didn't work.
if(NOT EXISTS ${dependency_file})
file(WRITE ${dependency_file} "#FindBANG.cmake generated file. Do not edit.\n")
endif()
# Always include this file to force CMake to run again next
# invocation and rebuild the dependencies.
#message("including dependency_file = ${dependency_file}")
include(${dependency_file})
# Now we need to verify the existence of all the included files
# here. If they aren't there we need to just blank this variable and
# make the file regenerate again.
if(BANG_CNCC_DEPEND)
#message("BANG_CNCC_DEPEND found")
foreach(f ${BANG_CNCC_DEPEND})
# message("searching for ${f}")
if(NOT EXISTS ${f})
#message("file ${f} not found")
set(BANG_CNCC_DEPEND_REGENERATE TRUE)
endif()
endforeach()
else()
#message("BANG_CNCC_DEPEND false")
# No dependencies, so regenerate the file.
set(BANG_CNCC_DEPEND_REGENERATE TRUE)
endif()
#message("BANG_CNCC_DEPEND_REGENERATE = ${BANG_CNCC_DEPEND_REGENERATE}")
# No incoming dependencies, so we need to generate them. Make the
# output depend on the dependency file itself, which should cause the
# rule to re-run.
if(BANG_CNCC_DEPEND_REGENERATE)
set(BANG_CNCC_DEPEND ${dependency_file})
#message("Generating an empty dependency_file: ${dependency_file}")
file(WRITE ${dependency_file} "#FindBANG.cmake generated file. Do not edit.\n")
endif()
endmacro()
###############################################################################
# Helper to add the include directory for BANG only once
###############################################################################
function(BANG_ADD_BANG_INCLUDE_ONCE)
get_directory_property(_include_directories INCLUDE_DIRECTORIES)
set(_add TRUE)
if(_include_directories)
foreach(dir ${_include_directories})
if("${dir}" STREQUAL "${BANG_INCLUDE_DIRS}")
set(_add FALSE)
endif()
endforeach()
endif()
if(_add)
include_directories(${BANG_INCLUDE_DIRS})
endif()
endfunction()
##############################################################################
# Build the shared library
##############################################################################
function(BANG_BUILD_SHARED_LIBRARY shared_flag)
set(cmake_args ${ARGN})
# If SHARED, MODULE, or STATIC aren't already in the list of arguments, then
# add SHARED or STATIC based on the value of BUILD_SHARED_LIBS.
list(FIND cmake_args SHARED _bang_found_SHARED)
list(FIND cmake_args MODULE _bang_found_MODULE)
list(FIND cmake_args STATIC _bang_found_STATIC)
if( _bang_found_SHARED GREATER -1 OR
_bang_found_MODULE GREATER -1 OR
_bang_found_STATIC GREATER -1)
set(_bang_build_shared_libs)
else()
if (BUILD_SHARED_LIBS)
set(_bang_build_shared_libs SHARED)
else()
set(_bang_build_shared_libs STATIC)
endif()
endif()
set(${shared_flag} ${_bang_build_shared_libs} PARENT_SCOPE)
endfunction()
##############################################################################
# Helper to avoid clashes of files with the same basename but different paths.
# This doesn't attempt to do exactly what CMake internals do, which is to only
# add this path when there is a conflict, since by the time a second collision
# in names is detected it's already too late to fix the first one. For
# consistency sake the relative path will be added to all files.
##############################################################################
function(BANG_COMPUTE_BUILD_PATH path build_path)
#message("BANG_COMPUTE_BUILD_PATH([${path}] ${build_path})")
# Only deal with CMake style paths from here on out
file(TO_CMAKE_PATH "${path}" bpath)
if (IS_ABSOLUTE "${bpath}")
# Absolute paths are generally unnessary, especially if something like
# file(GLOB_RECURSE) is used to pick up the files.
string(FIND "${bpath}" "${CMAKE_CURRENT_BINARY_DIR}" _binary_dir_pos)
if (_binary_dir_pos EQUAL 0)
file(RELATIVE_PATH bpath "${CMAKE_CURRENT_BINARY_DIR}" "${bpath}")
else()
file(RELATIVE_PATH bpath "${CMAKE_CURRENT_SOURCE_DIR}" "${bpath}")
endif()
endif()
# This recipe is from cmLocalGenerator::CreateSafeUniqueObjectFileName in the
# CMake source.
# Remove leading /
string(REGEX REPLACE "^[/]+" "" bpath "${bpath}")
# Avoid absolute paths by removing ':'
string(REPLACE ":" "_" bpath "${bpath}")
# Avoid relative paths that go up the tree
string(REPLACE "../" "__/" bpath "${bpath}")
# Avoid spaces
string(REPLACE " " "_" bpath "${bpath}")
# Strip off the filename. I wait until here to do it, since removin the
# basename can make a path that looked like path/../basename turn into
# path/.. (notice the trailing slash).
get_filename_component(bpath "${bpath}" PATH)
set(${build_path} "${bpath}" PARENT_SCOPE)
#message("${build_path} = ${bpath}")
endfunction()
##############################################################################
# Compute the filename to be used by BANG_LINK_SEPARABLE_COMPILATION_OBJECTS
##############################################################################
function(BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME output_file_var bang_target object_files)
if (object_files)
set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION})
set(output_file "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${bang_target}.dir/${CMAKE_CFG_INTDIR}/${bang_target}_intermediate_link${generated_extension}")
else()
set(output_file)
endif()
set(${output_file_var} "${output_file}" PARENT_SCOPE)
endfunction()
##############################################################################
# Setup the build rule for the separable compilation intermediate link file.
##############################################################################
function(BANG_LINK_SEPARABLE_COMPILATION_OBJECTS output_file bang_target options object_files)
if (object_files)
set_source_files_properties("${output_file}"
PROPERTIES
EXTERNAL_OBJECT TRUE # This is an object file not to be compiled, but only
# be linked.
GENERATED TRUE # This file is generated during the build
)
# For now we are ignoring all the configuration specific flags.
set(cncc_flags)
BANG_PARSE_CNCC_OPTIONS(cncc_flags ${options})
# If -ccbin, --compiler-bindir has been specified, don't do anything. Otherwise add it here.
list( FIND cncc_flags "-ccbin" ccbin_found0 )
list( FIND cncc_flags "--compiler-bindir" ccbin_found1 )
if( ccbin_found0 LESS 0 AND ccbin_found1 LESS 0 AND BANG_HOST_COMPILER )
# Match VERBATIM check below.
if(BANG_HOST_COMPILER MATCHES "\\$\\(VCInstallDir\\)")
list(APPEND cncc_flags -ccbin "\"${BANG_HOST_COMPILER}\"")
else()
list(APPEND cncc_flags -ccbin "${BANG_HOST_COMPILER}")
endif()
endif()
# Create a list of flags specified by BANG_CNCC_FLAGS_${CONFIG} and CMAKE_${BANG_C_OR_CXX}_FLAGS*
set(config_specific_flags)
set(flags)
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
# Add config specific flags
foreach(f ${BANG_CNCC_FLAGS_${config_upper}})
list(APPEND config_specific_flags $<$<CONFIG:${config}>:${f}>)
endforeach()
set(important_host_flags)
_bang_get_important_host_flags(important_host_flags "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}")
foreach(f ${important_host_flags})
list(APPEND flags $<$<CONFIG:${config}>:-Xcompiler> $<$<CONFIG:${config}>:${f}>)
endforeach()
endforeach()
# Add CMAKE_${BANG_C_OR_CXX}_FLAGS
set(important_host_flags)
_bang_get_important_host_flags(important_host_flags "${CMAKE_${BANG_C_OR_CXX}_FLAGS}")
foreach(f ${important_host_flags})
list(APPEND flags -Xcompiler ${f})
endforeach()
# Add our general BANG_CNCC_FLAGS with the configuration specifig flags
set(cncc_flags ${BANG_CNCC_FLAGS} ${config_specific_flags} ${cncc_flags})
file(RELATIVE_PATH output_file_relative_path "${CMAKE_BINARY_DIR}" "${output_file}")
# Some generators don't handle the multiple levels of custom command
# dependencies correctly (obj1 depends on file1, obj2 depends on obj1), so
# we work around that issue by compiling the intermediate link object as a
# pre-link custom command in that situation.
set(do_obj_build_rule TRUE)
if (MSVC_VERSION GREATER 1599 AND MSVC_VERSION LESS 1800)
# VS 2010 and 2012 have this problem.
set(do_obj_build_rule FALSE)
endif()
set(_verbatim VERBATIM)
if(cncc_flags MATCHES "\\$\\(VCInstallDir\\)")
set(_verbatim "")
endif()
if (do_obj_build_rule)
add_custom_command(
OUTPUT ${output_file}
DEPENDS ${object_files}
COMMAND ${BANG_CNCC_EXECUTABLE} ${cncc_flags} -dlink ${object_files} -o ${output_file}
${flags}
COMMENT "Building CNCC intermediate link file ${output_file_relative_path}"
${_verbatim}
)
else()
get_filename_component(output_file_dir "${output_file}" DIRECTORY)
add_custom_command(
TARGET ${bang_target}
PRE_LINK
COMMAND ${CMAKE_COMMAND} -E echo "Building CNCC intermediate link file ${output_file_relative_path}"
COMMAND ${CMAKE_COMMAND} -E make_directory "${output_file_dir}"
COMMAND ${BANG_CNCC_EXECUTABLE} ${cncc_flags} ${flags} -dlink ${object_files} -o "${output_file}"
${_verbatim}
)
endif()
endif()
endfunction()
##############################################################################
# This helper macro populates the following variables and setups up custom
# commands and targets to invoke the cncc compiler to generate C or MLISA source
# dependent upon the format parameter.
# INPUT:
# bang_target - Target name
# format - MLISA, CNBIN, CNFATBIN or OBJ
# FILE1 .. FILEN - The remaining arguments are the sources to be wrapped.
# OPTIONS - Extra options to CNCC
# OUTPUT:
# generated_files - List of generated files
##############################################################################
macro(BANG_WRAP_SRCS bang_target format generated_files)
# Set up all the command line flags here, so that they can be overridden on a per target basis.
set(cncc_flags "")
set(BANG_C_OR_CXX CXX)
set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION})
if(BANG_TARGET_CPU_ARCH)
set(cncc_flags ${cncc_flags} "--target=${BANG_TARGET_CPU_ARCH}")
endif()
set( BANG_build_configuration "${CMAKE_BUILD_TYPE}")
# Get the include directories for this directory and use them for our cncc command.
# Remove duplicate entries which may be present since include_directories
# in CMake >= 2.8.8 does not remove them.
get_directory_property(BANG_CNCC_INCLUDE_DIRECTORIES INCLUDE_DIRECTORIES)
list(REMOVE_DUPLICATES BANG_CNCC_INCLUDE_DIRECTORIES)
if(BANG_CNCC_INCLUDE_DIRECTORIES)
foreach(dir ${BANG_CNCC_INCLUDE_DIRECTORIES})
list(APPEND BANG_CNCC_INCLUDE_ARGS -I${dir})
endforeach()
endif()
# Reset these variables
set(BANG_WRAP_OPTION_CNCC_FLAGS)
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
set(BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper})
endforeach()
BANG_GET_SOURCES_AND_OPTIONS(_bang_wrap_sources _bang_wrap_cmake_options _bang_wrap_options ${ARGN})
BANG_PARSE_CNCC_OPTIONS(BANG_WRAP_OPTION_CNCC_FLAGS ${_bang_wrap_options})
# Figure out if we are building a shared library. BUILD_SHARED_LIBS is
# respected in BANG_ADD_LIBRARY.
set(_bang_build_shared_libs FALSE)
# SHARED, MODULE
list(FIND _bang_wrap_cmake_options SHARED _bang_found_SHARED)
list(FIND _bang_wrap_cmake_options MODULE _bang_found_MODULE)
if(_bang_found_SHARED GREATER -1 OR _bang_found_MODULE GREATER -1)
set(_bang_build_shared_libs TRUE)
endif()
# STATIC
list(FIND _bang_wrap_cmake_options STATIC _bang_found_STATIC)
if(_bang_found_STATIC GREATER -1)
set(_bang_build_shared_libs FALSE)
endif()
# BANG_HOST_FLAGS
if(_bang_build_shared_libs)
# If we are setting up code for a shared library, then we need to add extra flags for
# compiling objects for shared libraries.
set(BANG_HOST_SHARED_FLAGS ${CMAKE_SHARED_LIBRARY_${BANG_C_OR_CXX}_FLAGS})
else()
set(BANG_HOST_SHARED_FLAGS)
endif()
# Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We
# always need to set the SHARED_FLAGS, though.
set(_bang_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${BANG_C_OR_CXX}_FLAGS} ${BANG_HOST_SHARED_FLAGS})")
set(_bang_cncc_flags_config "# Build specific configuration flags")
# Loop over all the configuration types to generate appropriate flags for run_cncc.cmake
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
# CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS
# we convert the strings to lists (like we want).
set(_bang_C_FLAGS "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}")
set(_bang_host_flags "${_bang_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_bang_C_FLAGS})")
# Note that if we ever want BANG_CNCC_FLAGS_<CONFIG> to be string (instead of a list
# like it is currently), we can remove the quotes around the
# ${BANG_CNCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_<CONFIG> variable.
set(_bang_cncc_flags_config "${_bang_cncc_flags_config}\nset(BANG_CNCC_FLAGS_${config_upper} ${BANG_CNCC_FLAGS_${config_upper}} ;; ${BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}})")
endforeach()
# Process the C++11 flag. If the host sets the flag, we need to add it to cncc and
# remove it from the host. This is because -Xcompile -std=c++ will choke cncc (it uses
# the C preprocessor). In order to get this to work correctly, we need to use cncc's
# specific c++11 flag.
if( "${_bang_host_flags}" MATCHES "-std=c\\+\\+11")
# Add the c++11 flag to cncc if it isn't already present. Note that we only look at
# the main flag instead of the configuration specific flags.
if( NOT "${BANG_CNCC_FLAGS}" MATCHES "-std;c\\+\\+11" )
list(APPEND cncc_flags -std=c++11)
endif()
string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _bang_host_flags "${_bang_host_flags}")
endif()
# Get the list of definitions from the directory property
get_directory_property(BANG_CNCC_DEFINITIONS COMPILE_DEFINITIONS)
if(BANG_CNCC_DEFINITIONS)
foreach(_definition ${BANG_CNCC_DEFINITIONS})
list(APPEND cncc_flags "-D${_definition}")
endforeach()
endif()
if(_bang_build_shared_libs)
list(APPEND cncc_flags "-D${bang_target}_EXPORTS")
endif()
# Reset the output variable
set(_bang_wrap_generated_files "")
# Iterate over the macro arguments and create custom
# commands for all the .cu files.
foreach(file ${ARGN})
# Ignore any file marked as a HEADER_FILE_ONLY
get_source_file_property(_is_header ${file} HEADER_FILE_ONLY)
# Allow per source file overrides of the format. Also allows compiling non-.cu files.
get_source_file_property(_bang_source_format ${file} BANG_SOURCE_PROPERTY_FORMAT)
if((${file} MATCHES "\\.mlu$" OR _bang_source_format) AND NOT _is_header)
if(NOT _bang_source_format)
set(_bang_source_format ${format})
endif()
if( ${_bang_source_format} MATCHES "OBJ")
set( bang_compile_to_external_module OFF )
else()
set( bang_compile_to_external_module ON )
if( ${_bang_source_format} MATCHES "MLISA" )
set( bang_compile_to_external_module_type "mlisa" )
elseif( ${_bang_source_format} MATCHES "CNBIN")
set( bang_compile_to_external_module_type "cnbin" )
elseif( ${_bang_source_format} MATCHES "CNFATBIN")
set( bang_compile_to_external_module_type "cnfatbin" )
else()
message( FATAL_ERROR "Invalid format flag passed to BANG_WRAP_SRCS or set with BANG_SOURCE_PROPERTY_FORMAT file property for file '${file}': '${_bang_source_format}'. Use OBJ, MLISA, CNBIN or CNFATBIN.")
endif()
endif()
if(bang_compile_to_external_module)
# Don't use any of the host compilation flags for MLISA targets.
set(BANG_HOST_FLAGS)
set(BANG_CNCC_FLAGS_CONFIG)
else()
set(BANG_HOST_FLAGS ${_bang_host_flags})
set(BANG_CNCC_FLAGS_CONFIG ${_bang_cncc_flags_config})
endif()
# Determine output directory
bang_compute_build_path("${file}" bang_build_path)
set(bang_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/${bang_target}.dir/${bang_build_path}")
if(BANG_GENERATED_OUTPUT_DIR)
set(bang_compile_output_dir "${BANG_GENERATED_OUTPUT_DIR}")
else()
if ( bang_compile_to_external_module )
set(bang_compile_output_dir "${CMAKE_CURRENT_BINARY_DIR}")
else()
set(bang_compile_output_dir "${bang_compile_intermediate_directory}")
endif()
endif()
# Add a custom target to generate a c or mlisa file. ######################
get_filename_component( basename ${file} NAME )
if( bang_compile_to_external_module )
set(generated_file_path "${bang_compile_output_dir}")
set(generated_file_basename "${bang_target}_generated_${basename}.${bang_compile_to_external_module_type}")
set(format_flag "-${bang_compile_to_external_module_type}")
file(MAKE_DIRECTORY "${bang_compile_output_dir}")
else()
set(generated_file_path "${bang_compile_output_dir}/${CMAKE_CFG_INTDIR}")
set(generated_file_basename "${bang_target}_generated_${basename}${generated_extension}")
set(format_flag "-c")
endif()
# Set all of our file names. Make sure that whatever filenames that have
# generated_file_path in them get passed in through as a command line
# argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time
# instead of configure time.
set(generated_file "${generated_file_path}/${generated_file_basename}")
set(cmake_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.depend")
set(CNCC_generated_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.CNCC-depend")
set(generated_cnbin_file "${generated_file_path}/${generated_file_basename}.cnbin.txt")
set(custom_target_script "${bang_compile_intermediate_directory}/${generated_file_basename}.cmake")
# Setup properties for obj files:
if( NOT bang_compile_to_external_module )
set_source_files_properties("${generated_file}"
PROPERTIES
EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked.
)
endif()
# Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path.
get_filename_component(file_path "${file}" PATH)
if(IS_ABSOLUTE "${file_path}")
set(source_file "${file}")
else()
set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
endif()
# Bring in the dependencies. Creates a variable BANG_CNCC_DEPEND #######
bang_include_cncc_dependencies(${cmake_dependency_file})
# Build the CNCC made dependency file ###################################
set(build_cnbin OFF)
if ( BANG_BUILD_CNBIN )
if ( NOT bang_compile_to_external_module )
set ( build_cnbin ON )
endif()
endif()
# Configure the build script
configure_file("${BANG_run_cncc}" "${custom_target_script}" @ONLY)
# So if a user specifies the same bang file as input more than once, you
# can have bad things happen with dependencies. Here we check an option
# to see if this is the behavior they want.
set(main_dep DEPENDS ${source_file})
if(BANG_VERBOSE_BUILD)
set(verbose_output ON)
elseif(CMAKE_GENERATOR MATCHES "Makefiles")
set(verbose_output "$(VERBOSE)")
else()
set(verbose_output OFF)
endif()
# Create up the comment string
file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}")
if(bang_compile_to_external_module)
set(bang_build_comment_string "Building CNCC ${bang_compile_to_external_module_type} file ${generated_file_relative_path}")
else()
set(bang_build_comment_string "Building CNCC object ${generated_file_relative_path}")
endif()
set(_verbatim VERBATIM)
if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)")
set(_verbatim "")
endif()
# Build the generated file and dependency file ##########################
add_custom_command(
OUTPUT ${generated_file}
# These output files depend on the source_file and the contents of cmake_dependency_file
${main_dep}
DEPENDS ${BANG_CNCC_DEPEND}
DEPENDS ${custom_target_script}
# Make sure the output directory exists before trying to write to it.
COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}"
COMMAND ${CMAKE_COMMAND} ARGS
-D verbose:BOOL=${verbose_output}
${ccbin_flags}
-D build_configuration:STRING=${BANG_build_configuration}
-D "generated_file:STRING=${generated_file}"
-D "generated_cnbin_file:STRING=${generated_cnbin_file}"
-P "${custom_target_script}"
WORKING_DIRECTORY "${bang_compile_intermediate_directory}"
COMMENT "${bang_build_comment_string}"
${_verbatim}
)
# Make sure the build system knows the file is generated.
set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE)
list(APPEND _bang_wrap_generated_files ${generated_file})
# Add the other files that we want cmake to clean on a cleanup ##########
list(APPEND BANG_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}")
list(REMOVE_DUPLICATES BANG_ADDITIONAL_CLEAN_FILES)
set(BANG_ADDITIONAL_CLEAN_FILES ${BANG_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the bang dependency scanning.")
endif()
endforeach()
# Set the return parameter
set(${generated_files} ${_bang_wrap_generated_files})
endmacro()
###############################################################################
###############################################################################
# Locate NEUWARE, Set Build Type, etc.
###############################################################################
###############################################################################
# BANG_CNCC_EXECUTABLE
find_program(BANG_CNCC_EXECUTABLE
NAMES cncc
PATHS "${NEUWARE_ROOT_DIR}"
ENV NEUWARE_PATH
ENV NEUWARE_BIN_PATH
PATH_SUFFIXES bin bin64
NO_DEFAULT_PATH
)
# Search default search paths, after we search our own set of paths.
find_program(BANG_CNCC_EXECUTABLE cncc)
mark_as_advanced(BANG_CNCC_EXECUTABLE)
###############################################################################
###############################################################################
# ADD LIBRARY
###############################################################################
###############################################################################
macro(BANG_ADD_LIBRARY bang_target)
BANG_ADD_BANG_INCLUDE_ONCE()
# Separate the sources from the options
BANG_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN})
BANG_BUILD_SHARED_LIBRARY(_bang_shared_flag ${ARGN})
# Create custom commands and targets for each file.
BANG_WRAP_SRCS( ${bang_target} OBJ _generated_files ${_sources}
${_cmake_options} ${_bang_shared_flag}
OPTIONS ${_options} )
# Compute the file name of the intermedate link file used for separable
# compilation.
BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${bang_target} "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}")
# Add the library.
add_library(${bang_target} ${_cmake_options}
${_generated_files}
${_sources}
${link_file}
)
# Add a link phase for the separable compilation if it has been enabled. If
# it has been enabled then the ${bang_target}_SEPARABLE_COMPILATION_OBJECTS
# variable will have been defined.
BANG_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${bang_target} "${_options}" "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}")
target_link_libraries(${bang_target}
${BANG_LIBRARIES}
)
# We need to set the linker language based on what the expected generated file
# would be. BANG_C_OR_CXX is computed based on BANG_HOST_COMPILATION_CPP.
set_target_properties(${bang_target}
PROPERTIES
LINKER_LANGUAGE ${BANG_C_OR_CXX}
)
endmacro()
###############################################################################
###############################################################################
# ADD EXECUTABLE
###############################################################################
###############################################################################
macro(BANG_ADD_EXECUTABLE bang_target)
BANG_ADD_BANG_INCLUDE_ONCE()
# Separate the sources from the options
BANG_GET_SOURCES_AND_OPTIONS(_sources _cmake_options _options ${ARGN})
# Create custom commands and targets for each file.
BANG_WRAP_SRCS( ${bang_target} OBJ _generated_files ${_sources} OPTIONS ${_options} )
# Compute the file name of the intermedate link file used for separable
# compilation.
BANG_COMPUTE_SEPARABLE_COMPILATION_OBJECT_FILE_NAME(link_file ${bang_target} "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}")
# Add the library.
add_executable(${bang_target} ${_cmake_options}
${_generated_files}
${_sources}
${link_file}
)
# Add a link phase for the separable compilation if it has been enabled. If
# it has been enabled then the ${bang_target}_SEPARABLE_COMPILATION_OBJECTS
# variable will have been defined.
BANG_LINK_SEPARABLE_COMPILATION_OBJECTS("${link_file}" ${bang_target} "${_options}" "${${bang_target}_SEPARABLE_COMPILATION_OBJECTS}")
target_link_libraries(${bang_target}
${BANG_LIBRARIES}
)
# We need to set the linker language based on what the expected generated file
# would be. BANG_C_OR_CXX is computed based on BANG_HOST_COMPILATION_CPP.
set_target_properties(${bang_target}
PROPERTIES
LINKER_LANGUAGE ${BANG_C_OR_CXX}
)
endmacro()
#####################################################################################
# This macro invokes the cncc compiler to compile mlu source files, and to generate
# object files.
# INPUT:
# _source_files - List of mlu source files to be compiled
# _include_directories_generator_user - List of user provided include files
# OUTPUT:
# _generated_files - List of generated files
#####################################################################################
macro(BANG_COMPILE _generated_files _source_files _include_directories_generator_user)
# Set up all the command line flags here, so that they can be overridden on a per target basis.
set(cncc_flags "")
set(BANG_C_OR_CXX CXX)
set(generated_extension ${CMAKE_${BANG_C_OR_CXX}_OUTPUT_EXTENSION})
if(BANG_TARGET_CPU_ARCH)
set(cncc_flags ${cncc_flags} "--target=${BANG_TARGET_CPU_ARCH}")
endif()
set( BANG_build_configuration "${CMAKE_BUILD_TYPE}")
set(include_directories_generator ${_include_directories_generator_user})
foreach(dir ${include_directories_generator})
if(dir)
list(APPEND BANG_CNCC_INCLUDE_ARGS -I${dir})
endif()
endforeach()
# Reset these variables
set(BANG_WRAP_OPTION_CNCC_FLAGS)
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
set(BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper})
endforeach()
BANG_GET_SOURCES_AND_OPTIONS(_bang_wrap_sources _bang_wrap_cmake_options _bang_wrap_options ${_source_files})
BANG_PARSE_CNCC_OPTIONS(BANG_WRAP_OPTION_CNCC_FLAGS ${_bang_wrap_options})
set(BANG_HOST_SHARED_FLAGS)
# Only add the CMAKE_{C,CXX}_FLAGS if we are propagating host flags. We
# always need to set the SHARED_FLAGS, though.
set(_bang_host_flags "set(CMAKE_HOST_FLAGS ${CMAKE_${BANG_C_OR_CXX}_FLAGS} ${BANG_HOST_SHARED_FLAGS})")
set(_bang_cncc_flags_config "# Build specific configuration flags")
# Loop over all the configuration types to generate appropriate flags for run_cncc.cmake
foreach(config ${BANG_configuration_types})
string(TOUPPER ${config} config_upper)
# CMAKE_FLAGS are strings and not lists. By not putting quotes around CMAKE_FLAGS
# we convert the strings to lists (like we want).
set(_bang_C_FLAGS "${CMAKE_${BANG_C_OR_CXX}_FLAGS_${config_upper}}")
set(_bang_host_flags "${_bang_host_flags}\nset(CMAKE_HOST_FLAGS_${config_upper} ${_bang_C_FLAGS})")
# Note that if we ever want BANG_CNCC_FLAGS_<CONFIG> to be string (instead of a list
# like it is currently), we can remove the quotes around the
# ${BANG_CNCC_FLAGS_${config_upper}} variable like the CMAKE_HOST_FLAGS_<CONFIG> variable.
set(_bang_cncc_flags_config "${_bang_cncc_flags_config}\nset(BANG_CNCC_FLAGS_${config_upper} ${BANG_CNCC_FLAGS_${config_upper}} ;; ${BANG_WRAP_OPTION_CNCC_FLAGS_${config_upper}})")
endforeach()
# Process the C++11 flag. If the host sets the flag, we need to add it to cncc and
# remove it from the host. This is because -Xcompile -std=c++ will choke cncc (it uses
# the C preprocessor). In order to get this to work correctly, we need to use cncc's
# specific c++11 flag.
if( "${_bang_host_flags}" MATCHES "-std=c\\+\\+11")
# Add the c++11 flag to cncc if it isn't already present. Note that we only look at
# the main flag instead of the configuration specific flags.
if( NOT "${BANG_CNCC_FLAGS}" MATCHES "-std;c\\+\\+11" )
list(APPEND cncc_flags -std=c++11)
endif()
string(REGEX REPLACE "[-]+std=c\\+\\+11" "" _bang_host_flags "${_bang_host_flags}")
endif()
# Get the list of definitions from the directory property
get_directory_property(BANG_CNCC_DEFINITIONS COMPILE_DEFINITIONS)
if(BANG_CNCC_DEFINITIONS)
foreach(_definition ${BANG_CNCC_DEFINITIONS})
list(APPEND cncc_flags "-D${_definition}")
endforeach()
endif()
# Reset the output variable
set(_bang_wrap_generated_files "")
# Iterate over the macro arguments and create custom
# commands for all the .cu files.
foreach(file ${_source_files})
# Ignore any file marked as a HEADER_FILE_ONLY
get_source_file_property(_is_header ${file} HEADER_FILE_ONLY)
# Allow per source file overrides of the format. Also allows compiling non-.cu files.
get_source_file_property(_bang_source_format ${file} BANG_SOURCE_PROPERTY_FORMAT)
if((${file} MATCHES "\\.mlu$" OR _bang_source_format) AND NOT _is_header)
set(_bang_source_format "OBJ")
set(BANG_HOST_FLAGS ${_bang_host_flags})
set(BANG_CNCC_FLAGS_CONFIG ${_bang_cncc_flags_config})
# Determine output directory
bang_compute_build_path("${file}" bang_build_path)
set(bang_compile_intermediate_directory "${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles/bang_compile.dir/${bang_build_path}")
if(BANG_GENERATED_OUTPUT_DIR)
set(bang_compile_output_dir "${BANG_GENERATED_OUTPUT_DIR}")
else()
set(bang_compile_output_dir "${bang_compile_intermediate_directory}")
endif()
# Add a custom target to generate a c or mlisa file. ######################
get_filename_component( basename ${file} NAME )
set(generated_file_path "${bang_compile_output_dir}/${CMAKE_CFG_INTDIR}")
set(generated_file_basename "bang_compile_generated_${basename}${generated_extension}")
set(format_flag "-c")
# Set all of our file names. Make sure that whatever filenames that have
# generated_file_path in them get passed in through as a command line
# argument, so that the ${CMAKE_CFG_INTDIR} gets expanded at run time
# instead of configure time.
set(generated_file "${generated_file_path}/${generated_file_basename}")
set(cmake_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.depend")
set(CNCC_generated_dependency_file "${bang_compile_intermediate_directory}/${generated_file_basename}.CNCC-depend")
set(generated_cnbin_file "${generated_file_path}/${generated_file_basename}.cnbin.txt")
set(custom_target_script "${bang_compile_intermediate_directory}/${generated_file_basename}.cmake")
set_source_files_properties("${generated_file}"
PROPERTIES
EXTERNAL_OBJECT true # This is an object file not to be compiled, but only be linked.
)
# Don't add CMAKE_CURRENT_SOURCE_DIR if the path is already an absolute path.
get_filename_component(file_path "${file}" PATH)
if(IS_ABSOLUTE "${file_path}")
set(source_file "${file}")
else()
set(source_file "${CMAKE_CURRENT_SOURCE_DIR}/${file}")
endif()
# Bring in the dependencies. Creates a variable BANG_CNCC_DEPEND #######
bang_include_cncc_dependencies(${cmake_dependency_file})
# Build the CNCC made dependency file ###################################
set(build_cnbin OFF)
# Configure the build script
configure_file("${BANG_run_cncc}" "${custom_target_script}" @ONLY)
# So if a user specifies the same bang file as input more than once, you
# can have bad things happen with dependencies. Here we check an option
# to see if this is the behavior they want.
set(main_dep DEPENDS ${source_file})
if(BANG_VERBOSE_BUILD)
set(verbose_output ON)
elseif(CMAKE_GENERATOR MATCHES "Makefiles")
set(verbose_output "$(VERBOSE)")
else()
set(verbose_output OFF)
endif()
# Create up the comment string
file(RELATIVE_PATH generated_file_relative_path "${CMAKE_BINARY_DIR}" "${generated_file}")
set(bang_build_comment_string "Building CNCC object ${generated_file_relative_path}")
set(_verbatim VERBATIM)
if(ccbin_flags MATCHES "\\$\\(VCInstallDir\\)")
set(_verbatim "")
endif()
# Build the generated file and dependency file ##########################
add_custom_command(
OUTPUT ${generated_file}
# These output files depend on the source_file and the contents of cmake_dependency_file
${main_dep}
DEPENDS ${BANG_CNCC_DEPEND}
DEPENDS ${custom_target_script}
# Make sure the output directory exists before trying to write to it.
COMMAND ${CMAKE_COMMAND} -E make_directory "${generated_file_path}"
COMMAND ${CMAKE_COMMAND} ARGS
-D verbose:BOOL=${verbose_output}
${ccbin_flags}
-D build_configuration:STRING=${BANG_build_configuration}
-D "generated_file:STRING=${generated_file}"
-D "generated_cnbin_file:STRING=${generated_cnbin_file}"
-P "${custom_target_script}"
WORKING_DIRECTORY "${bang_compile_intermediate_directory}"
COMMENT "${bang_build_comment_string}"
${_verbatim}
)
# Make sure the build system knows the file is generated.
set_source_files_properties(${generated_file} PROPERTIES GENERATED TRUE)
list(APPEND _bang_wrap_generated_files ${generated_file})
# Add the other files that we want cmake to clean on a cleanup ##########
list(APPEND BANG_ADDITIONAL_CLEAN_FILES "${cmake_dependency_file}")
list(REMOVE_DUPLICATES BANG_ADDITIONAL_CLEAN_FILES)
set(BANG_ADDITIONAL_CLEAN_FILES ${BANG_ADDITIONAL_CLEAN_FILES} CACHE INTERNAL "List of intermediate files that are part of the bang dependency scanning.")
endif()
endforeach()
# Set the return parameter
set(${_generated_files} ${_bang_wrap_generated_files})
endmacro()
# This code is licensed under the MIT License. See the FindBANG.cmake script
# for the text of the license.
# The MIT License
#
# License for the specific language governing rights and limitations under
# 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.
#
#######################################################################
# This converts a file written in makefile syntax into one that can be included
# by CMake.
file(READ ${input_file} depend_text)
if (NOT "${depend_text}" STREQUAL "")
# message("FOUND DEPENDS")
string(REPLACE "\\ " " " depend_text ${depend_text})
# This works for the cncc -M generated dependency files.
string(REGEX REPLACE "^.* : " "" depend_text ${depend_text})
string(REGEX REPLACE "[ \\\\]*\n" ";" depend_text ${depend_text})
set(dependency_list "")
foreach(file ${depend_text})
string(REGEX REPLACE "^ +" "" file ${file})
# OK, now if we had a UNC path, cncc has a tendency to only output the first '/'
# instead of '//'. Here we will test to see if the file exists, if it doesn't then
# try to prepend another '/' to the path and test again. If it still fails remove the
# path.
if(NOT EXISTS "${file}")
if (EXISTS "/${file}")
set(file "/${file}")
else()
message(WARNING " Removing non-existent dependency file: ${file}")
set(file "")
endif()
endif()
if(NOT IS_DIRECTORY "${file}")
# If softlinks start to matter, we should change this to REALPATH. For now we need
# to flatten paths, because cncc can generate stuff like /bin/../include instead of
# just /include.
get_filename_component(file_absolute "${file}" ABSOLUTE)
list(APPEND dependency_list "${file_absolute}")
endif()
endforeach()
else()
# message("FOUND NO DEPENDS")
endif()
# Remove the duplicate entries and sort them.
list(REMOVE_DUPLICATES dependency_list)
list(SORT dependency_list)
foreach(file ${dependency_list})
set(bang_cncc_depend "${bang_cncc_depend} \"${file}\"\n")
endforeach()
file(WRITE ${output_file} "# Generated by: make2cmake.cmake\nSET(BANG_CNCC_DEPEND\n ${bang_cncc_depend})\n\n")
# This code is licensed under the MIT License. See the FindBANG.cmake script
# for the text of the license.
# The MIT License
#
# License for the specific language governing rights and limitations under
# 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.
#
#######################################################################
# Parses a .cnbin file produced by cncc and reports statistics about the file.
file(READ ${input_file} file_text)
if (NOT "${file_text}" STREQUAL "")
string(REPLACE ";" "\\;" file_text ${file_text})
string(REPLACE "\ncode" ";code" file_text ${file_text})
list(LENGTH file_text len)
foreach(line ${file_text})
# Only look at "code { }" blocks.
if(line MATCHES "^code")
# Break into individual lines.
string(REGEX REPLACE "\n" ";" line ${line})
foreach(entry ${line})
# Extract kernel names.
if (${entry} MATCHES "[^g]name = ([^ ]+)")
set(entry "${CMAKE_MATCH_1}")
# Check to see if the kernel name starts with "_"
set(skip FALSE)
# if (${entry} MATCHES "^_")
# Skip the rest of this block.
# message("Skipping ${entry}")
# set(skip TRUE)
# else ()
message("Kernel: ${entry}")
# endif ()
endif()
# Skip the rest of the block if necessary
if(NOT skip)
# Registers
if (${entry} MATCHES "reg([ ]+)=([ ]+)([^ ]+)")
set(entry "${CMAKE_MATCH_3}")
message("Registers: ${entry}")
endif()
# Local memory
if (${entry} MATCHES "lmem([ ]+)=([ ]+)([^ ]+)")
set(entry "${CMAKE_MATCH_3}")
message("Local: ${entry}")
endif()
# Shared memory
if (${entry} MATCHES "smem([ ]+)=([ ]+)([^ ]+)")
set(entry "${CMAKE_MATCH_3}")
message("Shared: ${entry}")
endif()
if (${entry} MATCHES "^}")
message("")
endif()
endif()
endforeach()
endif()
endforeach()
else()
# message("FOUND NO DEPENDS")
endif()
# This code is licensed under the MIT License. See the FindBANG.cmake script
# for the text of the license.
# The MIT License
#
# License for the specific language governing rights and limitations under
# 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.
##########################################################################
# This file runs the cncc commands to produce the desired output file along with
# the dependency file needed by CMake to compute dependencies. In addition the
# file checks the output of each command and if the command fails it deletes the
# output files.
# Input variables
#
# verbose:BOOL=<> OFF: Be as quiet as possible (default)
# ON : Describe each step
#
# build_configuration:STRING=<> Typically one of Debug, MinSizeRel, Release, or
# RelWithDebInfo, but it should match one of the
# entries in BANG_HOST_FLAGS. This is the build
# configuration used when compiling the code. If
# blank or unspecified Debug is assumed as this is
# what CMake does.
#
# generated_file:STRING=<> File to generate. This argument must be passed in.
#
# generated_cnbin_file:STRING=<> File to generate. This argument must be passed
# in if build_cnbin is true.
if(NOT generated_file)
message(FATAL_ERROR "You must specify generated_file on the command line")
endif()
# Set these up as variables to make reading the generated file easier
set(CMAKE_COMMAND "@CMAKE_COMMAND@") # path
set(source_file "@source_file@") # path
set(CNCC_generated_dependency_file "@CNCC_generated_dependency_file@") # path
set(cmake_dependency_file "@cmake_dependency_file@") # path
set(BANG_make2cmake "@BANG_make2cmake@") # path
set(BANG_parse_cnbin "@BANG_parse_cnbin@") # path
set(build_cnbin @build_cnbin@) # bool
set(BANG_HOST_COMPILER "@BANG_HOST_COMPILER@") # path
# We won't actually use these variables for now, but we need to set this, in
# order to force this file to be run again if it changes.
set(generated_file_path "@generated_file_path@") # path
set(generated_file_internal "@generated_file@") # path
set(generated_cnbin_file_internal "@generated_cnbin_file@") # path
set(BANG_CNCC_EXECUTABLE "@BANG_CNCC_EXECUTABLE@") # path
set(BANG_CNCC_FLAGS @BANG_CNCC_FLAGS@ ;; @BANG_WRAP_OPTION_CNCC_FLAGS@) # list
@BANG_CNCC_FLAGS_CONFIG@
set(cncc_flags @cncc_flags@) # list
set(BANG_CNCC_INCLUDE_ARGS "@BANG_CNCC_INCLUDE_ARGS@") # list (needs to be in quotes to handle spaces properly).
set(format_flag "@format_flag@") # string
set(bang_language_flag @bang_language_flag@) # list
if(build_cnbin AND NOT generated_cnbin_file)
message(FATAL_ERROR "You must specify generated_cnbin_file on the command line")
endif()
# This is the list of host compilation flags. It C or CXX should already have
# been chosen by FindBANG.cmake.
@BANG_HOST_FLAGS@
# Take the compiler flags and package them up to be sent to the compiler via -Xcompiler
set(cncc_host_compiler_flags "")
# If we weren't given a build_configuration, use Debug.
if(NOT build_configuration)
set(build_configuration Debug)
endif()
string(TOUPPER "${build_configuration}" build_configuration)
#message("BANG_CNCC_HOST_COMPILER_FLAGS = ${BANG_CNCC_HOST_COMPILER_FLAGS}")
foreach(flag ${CMAKE_HOST_FLAGS} ${CMAKE_HOST_FLAGS_${build_configuration}})
# Extra quotes are added around each flag to help cncc parse out flags with spaces.
set(cncc_host_compiler_flags ${cncc_host_compiler_flags} ${flag})
endforeach()
# message("cncc_host_compiler_flags = ${cncc_host_compiler_flags}")
# Add the build specific configuration flags
list(APPEND BANG_CNCC_FLAGS ${BANG_CNCC_FLAGS_${build_configuration}})
# Remove the duplicated flags and including
list(REMOVE_DUPLICATES BANG_CNCC_FLAGS)
list(REMOVE_DUPLICATES BANG_CNCC_INCLUDE_ARGS)
# bang_execute_process - Executes a command with optional command echo and status message.
#
# status - Status message to print if verbose is true
# command - COMMAND argument from the usual execute_process argument structure
# ARGN - Remaining arguments are the command with arguments
#
# BANG_result - return value from running the command
#
# Make this a macro instead of a function, so that things like RESULT_VARIABLE
# and other return variables are present after executing the process.
macro(bang_execute_process status command)
set(_command ${command})
if(NOT "x${_command}" STREQUAL "xCOMMAND")
message(FATAL_ERROR "Malformed call to bang_execute_process. Missing COMMAND as second argument. (command = ${command})")
endif()
if(verbose)
execute_process(COMMAND "${CMAKE_COMMAND}" -E echo -- ${status})
# Now we need to build up our command string. We are accounting for quotes
# and spaces, anything else is left up to the user to fix if they want to
# copy and paste a runnable command line.
set(bang_execute_process_string)
foreach(arg ${ARGN})
# If there are quotes, excape them, so they come through.
string(REPLACE "\"" "\\\"" arg ${arg})
# Args with spaces need quotes around them to get them to be parsed as a single argument.
if(arg MATCHES " ")
list(APPEND bang_execute_process_string "\"${arg}\"")
else()
list(APPEND bang_execute_process_string ${arg})
endif()
endforeach()
# Echo the command
execute_process(COMMAND ${CMAKE_COMMAND} -E echo ${bang_execute_process_string})
endif()
# Run the command
execute_process(COMMAND ${ARGN} RESULT_VARIABLE BANG_result )
endmacro()
# Delete the target file
bang_execute_process(
"Removing ${generated_file}"
COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
)
# cncc ignore host flags
set(cncc_host_compiler_flags "")
# Generate the code
bang_execute_process(
"Generating ${generated_file}"
COMMAND "${BANG_CNCC_EXECUTABLE}"
"${source_file}"
${bang_language_flag}
${format_flag} -o "${generated_file}"
${cncc_flags}
${cncc_host_compiler_flags}
${BANG_CNCC_FLAGS}
-DCNCC
${BANG_CNCC_INCLUDE_ARGS}
)
if(BANG_result)
# Since cncc can sometimes leave half done files make sure that we delete the output file.
bang_execute_process(
"Removing ${generated_file}"
COMMAND "${CMAKE_COMMAND}" -E remove "${generated_file}"
)
message(FATAL_ERROR "Error generating file ${generated_file}")
else()
message(VERBOSE "Generated ${generated_file} successfully.")
endif()
# Cnbin resource report commands.
if( build_cnbin )
# Run with -cnbin to produce resource usage report.
bang_execute_process(
"Generating ${generated_cnbin_file}"
COMMAND "${BANG_CNCC_EXECUTABLE}"
"${source_file}"
${BANG_CNCC_FLAGS}
${cncc_flags}
${cncc_host_compiler_flags}
-DCNCC
-cnbin
-o "${generated_cnbin_file}"
${BANG_CNCC_INCLUDE_ARGS}
)
# Execute the parser script.
bang_execute_process(
"Executing the parser script"
COMMAND "${CMAKE_COMMAND}"
-D "input_file:STRING=${generated_cnbin_file}"
-P "${BANG_parse_cnbin}"
)
endif()
/**
* \file include/megcore_cambricon.h
*
* This file is part of MegDNN, a deep neural network run-time library
* developed by Megvii.
*
* \copyright Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*/
#pragma once
#include "megcore.h"
#include <cndev.h>
#include <cnml.h>
#include <cnrt.h>
#include "megdnn/internal/visibility_prologue.h"
namespace megcore {
megcoreStatus_t createDeviceHandleWithGlobalInitStatus(
megcoreDeviceHandle_t* devHandle, int deviceID, unsigned int flags,
bool global_initialized);
struct CambriconContext {
cnrtQueue_t queue = nullptr;
CambriconContext() = default;
CambriconContext(cnrtQueue_t q) : queue{q} {}
};
megcoreStatus_t createComputingHandleWithCambriconContext(
megcoreComputingHandle_t* compHandle, megcoreDeviceHandle_t devHandle,
unsigned int flags, const CambriconContext& ctx);
megcoreStatus_t getCambriconContext(
megcoreComputingHandle_t handle, CambriconContext* ctx);
} // namespace megcore
static inline megcoreStatus_t megcoreCreateComputingHandleWithCNRTQueue(
megcoreComputingHandle_t* compHandle, megcoreDeviceHandle_t devHandle,
unsigned int flags, cnrtQueue_t queue) {
megcore::CambriconContext ctx{queue};
return megcore::createComputingHandleWithCambriconContext(
compHandle, devHandle, flags, ctx);
}
static inline megcoreStatus_t megcoreGetCNRTQueue(
megcoreComputingHandle_t handle, cnrtQueue_t* queue) {
megcore::CambriconContext ctx;
auto ret = megcore::getCambriconContext(handle, &ctx);
*queue = ctx.queue;
return ret;
}
#include "megdnn/internal/visibility_epilogue.h"
// vim: syntax=cpp.doxygen
load("//brain/megbrain/dnn:flags.bzl", "megdnn_opts")
load("@megvii3//tools/build_rules:bangc.bzl", "bangc_library")
package(default_visibility = ["//brain/megbrain/dnn:__subpackages__"])
bangc_library(
name = "bangc_kernels",
srcs = glob([
"**/*.mlu",
]) + [
"//brain/megbrain/dnn:src/common/utils.cuh",
],
hdrs = glob([
"**/*.mlu.h",
]),
deps = [
"//brain/megbrain/dnn:public_headers",
"//brain/megbrain/sdk/build_config",
],
copts = megdnn_opts + [
"-Ibrain/megbrain/dnn",
],
)
filegroup(
name = "cambricon_backend_files",
srcs = glob([
"**/*.cpp",
"**/*.h",
"**/*.hpp",
]),
)
/**
* \file dnn/src/cambricon/checksum/checksum.mlu.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "src/cambricon/utils.mlu.h"
#ifdef __cplusplus
extern "C" {
#endif
void checksum_kernel_union1(uint32_t* dst, const uint32_t* src, int num_elems);
void checksum_kernel_union4(uint32_t* dst, const uint32_t* src, int num_elems);
#ifdef __cplusplus
}
#endif
// vim: ft=cpp syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/checksum/checksum_kernel_union1.mlu
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "checksum.mlu.h"
#include "cnsccl.h"
#include "mlu.h"
#define CLUSTER_DIM 1
#define CORE_DIM 4
#define STRIDE 1024
__mlu_entry__ void checksum_kernel_union1(uint32_t* dst, uint32_t* src,
int nr_elems) {
__nram__ uint32_t sum = 0;
__nram__ uint32_t val[STRIDE];
const uint32_t TASK_DIM = CLUSTER_DIM * CORE_DIM;
__mlu_shared__ uint32_t partial_sum[TASK_DIM];
int task_stride = STRIDE;
int start_offset = taskId * task_stride;
int global_stride = taskDim * task_stride;
for (int task_offset = start_offset; task_offset < nr_elems;
task_offset += global_stride) {
int end_offset = task_offset + task_stride;
end_offset = end_offset > nr_elems ? nr_elems : end_offset;
int copy_elems = end_offset - task_offset;
__memcpy(val, src + task_offset, copy_elems * sizeof(uint32_t),
GDRAM2NRAM);
for (int i = 0; i < copy_elems; i++) {
sum = sum + val[i] * (task_offset + i + 1);
}
}
partial_sum[taskId] = sum;
__sync_cluster();
if (taskId == 0) {
uint32_t res = 0;
for (int i = 0; i < taskDim; i++) {
res += partial_sum[i];
}
dst[0] = res;
}
}
#undef CLUSTER_DIM
#undef CORE_DIM
#undef STRIDE
// vim: ft=cpp syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/checksum/checksum_kernel_union4.mlu
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "checksum.mlu.h"
#include "cnsccl.h"
#include "mlu.h"
#define CLUSTER_DIM 4
#define CORE_DIM 4
#define STRIDE 1024
__mlu_entry__ void checksum_kernel_union4(uint32_t* dst, uint32_t* src,
int nr_elems) {
__nram__ uint32_t sum = 0;
__nram__ uint32_t val[STRIDE];
__mlu_shared__ uint32_t partial_sum_send[CORE_DIM];
__mlu_shared__ uint32_t partial_sum_recv[CLUSTER_DIM];
int task_stride = STRIDE;
int start_offset = taskId * task_stride;
int global_stride = taskDim * task_stride;
for (int task_offset = start_offset; task_offset < nr_elems;
task_offset += global_stride) {
int end_offset = task_offset + task_stride;
end_offset = end_offset > nr_elems ? nr_elems : end_offset;
int copy_elems = end_offset - task_offset;
__memcpy(val, src + task_offset, copy_elems * sizeof(uint32_t),
GDRAM2NRAM);
for (int i = 0; i < copy_elems; i++) {
sum = sum + val[i] * (task_offset + i + 1);
}
}
partial_sum_send[coreId] = sum;
__sync_cluster();
if (coreId == 0) {
for (int i = 1; i < CORE_DIM; ++i) {
partial_sum_send[0] += partial_sum_send[i];
}
}
__sync_all();
cnscclGather((void*)&partial_sum_send, (void*)&partial_sum_recv, 1,
cnscclInt, 0);
__sync_all();
if (clusterId == 0 && coreId == 0) {
uint32_t res = 0;
for (int i = 0; i < CLUSTER_DIM; ++i) {
res += partial_sum_recv[i];
}
dst[0] = res;
}
}
#undef CLUSTER_DIM
#undef CORE_DIM
#undef STRIDE
// vim: ft=cpp syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/checksum/opr_impl.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "src/cambricon/checksum/opr_impl.h"
#include "src/cambricon/checksum/checksum.mlu.h"
#include "src/cambricon/utils.h"
#include <algorithm>
using namespace megdnn;
using namespace cambricon;
namespace {
void bang_c_wrapper(
uint32_t* dst, const uint32_t* src, int nr_elems, cnrtQueue_t queue,
cnrtCoreVersion_t core_version) {
cnrtKernelParamsBuffer_t params;
cnrt_check(cnrtGetKernelParamsBuffer(&params));
cnrt_check(cnrtKernelParamsBufferAddParam(params, &dst, sizeof(uint32_t*)));
cnrt_check(cnrtKernelParamsBufferAddParam(params, &src, sizeof(uint32_t*)));
cnrt_check(cnrtKernelParamsBufferAddParam(params, &nr_elems, sizeof(int)));
if (core_version == CNRT_MLU270) {
cnrtDim3_t dim;
dim.x = 16;
dim.y = 1;
dim.z = 1;
cnrtFunctionType_t c = CNRT_FUNC_TYPE_UNION4;
cnrt_check(cnrtInvokeKernel_V2(
(void*)&checksum_kernel_union4, dim, params, c, queue));
} else if (core_version == CNRT_MLU220) {
cnrtDim3_t dim;
dim.x = 4;
dim.y = 1;
dim.z = 1;
cnrtFunctionType_t c = CNRT_FUNC_TYPE_UNION1;
cnrt_check(cnrtInvokeKernel_V2(
(void*)&checksum_kernel_union1, dim, params, c, queue));
}
after_kernel_launch();
cnrt_check(cnrtDestroyKernelParamsBuffer(params));
}
} // namespace
size_t ChecksumForwardImpl::get_workspace_in_bytes(const TensorLayout& /* data */) {
size_t ws_size = sizeof(ChecksumForward::Result::checksum);
return ws_size;
}
ChecksumForward::Result ChecksumForwardImpl::exec(
_megdnn_tensor_in data, _megdnn_workspace workspace) {
Result result;
memset(&result, 0, sizeof(result));
check_exec(data.layout, workspace.size);
auto queue = cnrt_queue(handle());
auto ptr = static_cast<uint8_t*>(data.raw_ptr());
size_t size_all = data.layout.shape[0], size_ints = size_all / sizeof(uint32_t);
auto last_val_size = std::min<size_t>(size_all, 4);
cnrt_check(cnrtMemcpyAsync(
&result.last_val, ptr + size_all - last_val_size, last_val_size, queue,
CNRT_MEM_TRANS_DIR_DEV2HOST));
if (size_ints) {
auto&& device_info = current_device_info();
bang_c_wrapper(
reinterpret_cast<uint32_t*>(workspace.raw_ptr),
static_cast<uint32_t*>(data.raw_ptr()), size_ints, queue,
device_info.core_version);
cnrt_check(cnrtMemcpyAsync(
&result.checksum, workspace.raw_ptr, sizeof(result.checksum), queue,
CNRT_MEM_TRANS_DIR_DEV2HOST));
}
cnrt_check(cnrtSyncQueue(queue));
return result;
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/checksum/opr_impl.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "megdnn/oprs.h"
#include "src/cambricon/utils.h"
namespace megdnn {
namespace cambricon {
class ChecksumForwardImpl final : public ChecksumForward {
public:
using ChecksumForward::ChecksumForward;
size_t get_workspace_in_bytes(const TensorLayout&) override;
bool is_thread_safe() const override { return true; }
Result exec(_megdnn_tensor_in data, _megdnn_workspace workspace) override;
};
} // namespace cambricon
} // namespace megdnn
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/handle.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "src/common/handle_impl.h"
#include "src/common/version_symbol.h"
#include "src/cambricon/handle.h"
#include "src/cambricon/utils.h"
#include <cnrt.h>
#include "src/cambricon/checksum/opr_impl.h"
namespace megdnn {
namespace cambricon {
HandleImpl::HandleImpl(megcoreComputingHandle_t comp_handle)
: HandleImplHelper(comp_handle, HandleType::CAMBRICON) {
// Get megcore device handle
megcoreDeviceHandle_t dev_handle;
megcoreGetDeviceHandle(comp_handle, &dev_handle);
int dev_id;
megcoreGetDeviceID(dev_handle, &dev_id);
unsigned int dev_num;
cnrt_check(cnrtGetDeviceCount(&dev_num));
MEGDNN_MARK_USED_VAR(dev_num);
// check validity of device_id
megdnn_assert(dev_id >= 0 && static_cast<unsigned int>(dev_id) < dev_num);
m_device_id = dev_id;
cnrt_check(cnrtGetDeviceInfo(&m_device_info, dev_id));
megcore::getCambriconContext(comp_handle, &m_megcore_context);
}
HandleImpl::~HandleImpl() noexcept = default;
template <typename Opr>
std::unique_ptr<Opr> HandleImpl::create_operator() {
megdnn_throw("unsupported cambricon opr");
return nullptr;
}
size_t HandleImpl::alignment_requirement() const {
return 1;
}
MEGDNN_SPECIALIZE_CREATE_OPERATOR(ChecksumForward);
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wpragmas"
#pragma GCC diagnostic ignored "-Winstantiation-after-specialization"
MEGDNN_FOREACH_OPR_CLASS(MEGDNN_INST_CREATE_OPERATOR)
#pragma GCC diagnostic pop
} // namespace cambricon
} // namespace megdnn
MEGDNN_VERSION_SYMBOL3(
CNRT, CNRT_MAJOR_VERSION, CNRT_MINOR_VERSION, CNRT_PATCH_VERSION);
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/handle.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "megcore_cambricon.h"
#include "megdnn/basic_types.h"
#include "megdnn/handle.h"
#include "megdnn/oprs/general.h"
#include "src/common/handle_impl.h"
#include "src/common/utils.h"
#include <atomic>
#include <mutex>
#include <cnrt.h>
namespace megdnn {
namespace cambricon {
class HandleImpl : public HandleImplHelper {
public:
HandleImpl(megcoreComputingHandle_t computing_handle);
~HandleImpl() noexcept;
size_t alignment_requirement() const override;
const cnrtDeviceInfo_t& device_info() const { return m_device_info; }
template <typename Opr>
std::unique_ptr<Opr> create_operator();
const megcore::CambriconContext& megcore_context() const {
return m_megcore_context;
}
int device_id() const { return m_device_id; }
cnrtQueue_t queue() const { return megcore_context().queue; }
//! global matmul opr
Checksum* checksum_opr() override final {
return get_helper_opr<Checksum, 0>(this);
}
private:
int m_device_id;
//! MegDNN handle does not manage the lifetime of cnrt queue.
megcore::CambriconContext m_megcore_context;
cnrtDeviceInfo_t m_device_info;
};
} // namespace cambricon
} // namespace megdnn
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/megcore/cambricon_computing_context.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "megcore.h"
#include "src/cambricon/utils.h"
#include "src/common/utils.h"
#include "src/cambricon/megcore/cambricon_computing_context.hpp"
using namespace megcore;
using namespace megcore::cambricon;
CambriconComputingContext::CambriconComputingContext(
megcoreDeviceHandle_t dev_handle, unsigned int flags,
const CambriconContext& ctx)
: ComputingContext(dev_handle, flags),
own_queue{ctx.queue == nullptr},
context_{ctx} {
megcorePlatform_t platform;
megcoreGetPlatform(dev_handle, &platform);
megdnn_assert(platform == megcorePlatformCambricon);
if (own_queue) {
cnrt_check(cnrtCreateQueue(&context_.queue));
}
}
CambriconComputingContext::~CambriconComputingContext() {
if (own_queue) {
cnrt_check(cnrtDestroyQueue(context_.queue));
}
}
void CambriconComputingContext::memcpy(
void* dst, const void* src, size_t size_in_bytes, megcoreMemcpyKind_t kind) {
cnrtMemTransDir_t dir;
switch (kind) {
case megcoreMemcpyDeviceToHost:
dir = CNRT_MEM_TRANS_DIR_DEV2HOST;
break;
case megcoreMemcpyHostToDevice:
dir = CNRT_MEM_TRANS_DIR_HOST2DEV;
break;
case megcoreMemcpyDeviceToDevice:
dir = CNRT_MEM_TRANS_DIR_DEV2DEV;
break;
default:
megdnn_throw("bad cnrt mem trans dir");
}
if (kind == megcoreMemcpyDeviceToDevice) {
cnrt_check(cnrtSyncQueue(context_.queue));
cnrt_check(cnrtMemcpy(dst, const_cast<void*>(src), size_in_bytes, dir));
return;
}
cnrt_check(cnrtMemcpyAsync(
dst, const_cast<void*>(src), size_in_bytes, context_.queue, dir));
}
void CambriconComputingContext::memset(void* dst, int value, size_t size_in_bytes) {
cnrt_check(cnrtSyncQueue(context_.queue));
cnrt_check(cnrtMemset(dst, value, size_in_bytes));
}
void CambriconComputingContext::synchronize() {
cnrt_check(cnrtSyncQueue(context_.queue));
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/megcore/cambricon_computing_context.hpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "megcore_cambricon.h"
#include "src/common/megcore/common/computing_context.hpp"
namespace megcore {
namespace cambricon {
class CambriconComputingContext final : public ComputingContext {
public:
CambriconComputingContext(megcoreDeviceHandle_t dev_handle,
unsigned int flags,
const CambriconContext& ctx = {});
~CambriconComputingContext();
void memcpy(void* dst, const void* src, size_t size_in_bytes,
megcoreMemcpyKind_t kind) override;
void memset(void* dst, int value, size_t size_in_bytes) override;
void synchronize() override;
const CambriconContext& context() const { return context_; }
cnrtQueue_t queue() const { return context().queue; }
private:
bool own_queue;
CambriconContext context_;
};
} // namespace cambricon
} // namespace megcore
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/megcore/cambricon_device_context.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "megcore.h"
#include "src/cambricon/utils.h"
#include "src/common/utils.h"
#include "src/cambricon/megcore/cambricon_device_context.hpp"
#define STR_HELPER(x) #x
#define STR(x) STR_HELPER(x)
#define CNRT_VERSION_STR \
STR(CNRT_MAJOR_VERSION) \
"." STR(CNRT_MINOR_VERSION) "." STR(CNRT_PATCH_VERSION)
#pragma message "compile with cnrt " CNRT_VERSION_STR " "
#undef STR_HELPER
#undef STR
using namespace megcore;
using namespace cambricon;
CambriconDeviceContext::CambriconDeviceContext(
int device_id, unsigned int flags, bool global_initialized)
: DeviceContext(megcorePlatformCambricon, device_id, flags) {
if (!global_initialized)
init_status.init();
unsigned int version;
cnrt_check(cnrtGetVersion(&version));
megdnn_assert(
version == CNRT_VERSION, "megcore compiled with cnrt %d, get %d at runtime",
CNRT_VERSION, version);
unsigned int dev_num;
cnrt_check(cnrtGetDeviceCount(&dev_num));
MEGDNN_MARK_USED_VAR(dev_num);
// check validity of device_id
megdnn_assert(device_id >= 0 && static_cast<unsigned int>(device_id) < dev_num);
cnrt_check(cnrtGetDeviceInfo(&device_info, device_id));
}
CambriconDeviceContext::~CambriconDeviceContext() noexcept = default;
size_t CambriconDeviceContext::mem_alignment_in_bytes() const noexcept {
return 1;
}
void CambriconDeviceContext::activate() {
int id = device_id();
cnrtDev_t dev;
cnrt_check(cnrtGetDeviceHandle(&dev, id));
cnrt_check(cnrtSetCurrentDevice(dev));
}
void* CambriconDeviceContext::malloc(size_t size_in_bytes) {
void* ptr;
cnrt_check(cnrtMalloc(&ptr, size_in_bytes));
return ptr;
}
void CambriconDeviceContext::free(void* ptr) {
cnrt_check(cnrtFree(ptr));
}
CambriconDeviceContext::InitStatus CambriconDeviceContext::init_status;
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/megcore/cambricon_device_context.hpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include <mutex>
#include "megcore_cambricon.h"
#include "src/common/megcore/common/device_context.hpp"
#include "src/common/utils.h"
namespace megcore {
namespace cambricon {
class CambriconDeviceContext : public DeviceContext {
public:
CambriconDeviceContext(int device_id, unsigned int flags,
bool global_initialized = false);
~CambriconDeviceContext() noexcept;
size_t mem_alignment_in_bytes() const noexcept override;
void activate() override;
void* malloc(size_t size_in_bytes) override;
void free(void* ptr) override;
struct InitStatus {
bool initialized;
std::mutex mtx;
InitStatus() : initialized{false} {}
void init() {
std::lock_guard<std::mutex> guard{mtx};
if (!initialized) {
auto cnrt_err = cnrtInit(0);
initialized = cnrt_err == CNRT_RET_SUCCESS;
megdnn_assert(initialized, "cnrt initialize failed: (cnrt:%d)",
static_cast<int>(cnrt_err));
}
}
~InitStatus() {
if (initialized) {
cnrtDestroy();
initialized = false;
}
}
};
static InitStatus init_status;
private:
cnrtDeviceInfo_t device_info;
};
} // namespace cambricon
} // namespace megcore
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/megcore/public_api/computing.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "megcore_cambricon.h"
#include "src/cambricon/megcore/cambricon_computing_context.hpp"
#include "src/cambricon/megcore/cambricon_device_context.hpp"
#include "src/common/megcore/public_api/computing.hpp"
#include "src/common/megcore/public_api/device.hpp"
#include "src/common/utils.h"
using namespace megcore;
megcoreStatus_t megcore::createDeviceHandleWithGlobalInitStatus(
megcoreDeviceHandle_t* devHandle, int deviceID, unsigned int flags,
bool global_initialized) {
auto content = megdnn::make_unique<cambricon::CambriconDeviceContext>(
deviceID, flags, global_initialized);
auto& ctx = *devHandle;
ctx = new megcoreDeviceContext;
ctx->content = std::move(content);
return megcoreSuccess;
}
megcoreStatus_t megcore::createComputingHandleWithCambriconContext(
megcoreComputingHandle_t* compHandle, megcoreDeviceHandle_t devHandle,
unsigned int flags, const CambriconContext& ctx) {
auto content = megdnn::make_unique<cambricon::CambriconComputingContext>(
devHandle, flags, ctx);
auto& H = *compHandle;
H = new megcoreComputingContext;
H->content = std::move(content);
return megcoreSuccess;
}
megcoreStatus_t megcore::getCambriconContext(
megcoreComputingHandle_t handle, CambriconContext* ctx) {
auto&& H = handle;
megdnn_assert(H);
megcoreDeviceHandle_t dev_handle = H->content->dev_handle();
megcorePlatform_t platform;
megcoreGetPlatform(dev_handle, &platform);
megdnn_assert(platform == megcorePlatformCambricon);
auto context = static_cast<megcore::cambricon::CambriconComputingContext*>(
H->content.get());
*ctx = context->context();
return megcoreSuccess;
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/utils.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "src/cambricon/utils.h"
#include "src/cambricon/utils.mlu.h"
#include "src/cambricon/handle.h"
#include "src/common/utils.h"
#include <mutex>
#include <unordered_map>
using namespace megdnn;
using namespace cambricon;
namespace {
struct DeviceInfoRecord {
bool init = false;
cnrtDeviceInfo_t device_info;
std::mutex mtx;
};
std::unordered_map<cnrtDev_t, int> dev2device_id;
std::mutex dev2device_id_mtx;
constexpr int MAX_NR_DEVICE = 64;
DeviceInfoRecord device_info_rec[MAX_NR_DEVICE];
} // namespace
void cambricon::__throw_cnrt_error__(cnrtRet_t err, const char* msg) {
auto s = ssprintf(
"cnrt return %s(%d) occurred; expr: %s", cnrtGetErrorStr(err), int(err),
msg);
megdnn_throw(s.c_str());
}
cnrtDeviceInfo_t cambricon::current_device_info() {
static bool dev2device_id_init = false;
{
std::lock_guard<std::mutex> lock(dev2device_id_mtx);
if (!dev2device_id_init) {
unsigned int dev_num = 0;
cnrt_check(cnrtGetDeviceCount(&dev_num));
for (unsigned int dev_id = 0; dev_id < dev_num; ++dev_id) {
cnrtDev_t dev;
cnrt_check(cnrtGetDeviceHandle(&dev, dev_id));
dev2device_id[dev] = dev_id;
}
dev2device_id_init = true;
}
}
cnrtDev_t dev;
cnrt_check(cnrtGetCurrentDevice(&dev));
{
std::lock_guard<std::mutex> lock(dev2device_id_mtx);
int dev_id = dev2device_id.at(dev);
auto& rec = device_info_rec[dev_id];
{
std::lock_guard<std::mutex> lock(rec.mtx);
if (!rec.init) {
cnrt_check(cnrtGetDeviceInfo(&rec.device_info, dev_id));
rec.init = true;
}
}
return rec.device_info;
}
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/utils.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "megcore_cdefs.h"
#include "megdnn/handle.h"
#include "src/cambricon/utils.mlu.h"
#include "src/common/utils.h"
#include "src/cambricon/handle.h"
#include <cnrt.h>
namespace megdnn {
namespace cambricon {
static inline HandleImpl* concrete_handle(Handle* handle) {
return static_cast<cambricon::HandleImpl*>(handle);
}
static inline cnrtQueue_t cnrt_queue(Handle* handle) {
return concrete_handle(handle)->queue();
}
//! get device info of current active device
cnrtDeviceInfo_t current_device_info();
} // namespace cambricon
} // namespace megdnn
// vim: syntax=cpp.doxygen
/**
* \file dnn/src/cambricon/utils.mlu.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include "src/common/utils.cuh"
#include <stdint.h>
#include <cnrt.h>
#define cnrt_check(_x) \
do { \
cnrtRet_t _ret = (_x); \
if (_ret != CNRT_RET_SUCCESS) { \
::megdnn::cambricon::__throw_cnrt_error__(_ret, #_x); \
} \
} while (0)
#define after_kernel_launch() \
do { \
cnrt_check(cnrtGetLastErr()); \
} while (0)
namespace megdnn {
namespace cambricon {
//! Error handling funcions
MEGDNN_NORETURN void __throw_cnrt_error__(cnrtRet_t err, const char* msg);
} // namespace cambricon
} // namespace megdnn
// vim: syntax=cpp.doxygen
/**
* \file dnn/test/cambricon/checksum.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "megdnn/oprs.h"
#include "test/cambricon/fixture.h"
#include "test/common/checker.h"
using namespace megdnn;
using namespace test;
TEST_F(CAMBRICON, CHECKSUM_FORWARD) {
auto cambricon_opr = handle_cambricon()->create_operator<megdnn::Checksum>(),
naive_opr = handle_naive()->create_operator<megdnn::Checksum>();
std::mt19937 rng(std::random_device{}());
for (size_t size : {3, 8, 4 * 4 * 1024, 12345, 1024 * 1024, 1024 * 1024 * 10}) {
auto aligned_size = size + ((512 - size % 512) % 512);
auto run = [&](megdnn::Checksum* opr, void* ptr, bool log_size) {
TensorND tensor;
tensor.reset_ptr(ptr);
tensor.layout.init_contiguous_stride({size});
tensor.layout.dtype = dtype::Byte();
WorkspaceWrapper workspace(
handle_cambricon(), opr->get_workspace_in_bytes(tensor.layout));
if (log_size) {
printf("checksum(%zu): workspace=%zu\n", size,
workspace.workspace().size);
}
return opr->exec(tensor, workspace.workspace());
};
std::vector<uint8_t> buf(aligned_size);
for (size_t i = 0; i < size; ++i)
buf[i] = 1;
auto run_offsset = [&](size_t offset) {
void* dev_ptr = megdnn_malloc(handle_cambricon(), buf.size() + offset);
void* dev_buf = static_cast<char*>(dev_ptr) + offset;
Checksum::Result res_cambricon[2], res_naive[2];
for (int change_last = 0; change_last < 2; ++change_last) {
if (change_last)
++buf[size - 1];
megdnn_memcpy_H2D(handle_cambricon(), dev_buf, buf.data(), size);
res_cambricon[change_last] =
run(cambricon_opr.get(), dev_buf, !change_last);
res_naive[change_last] = run(naive_opr.get(), buf.data(), false);
}
megdnn_free(handle_cambricon(), dev_ptr);
ASSERT_EQ(res_naive[0], res_cambricon[0]) << "failed for size " << size;
ASSERT_EQ(res_naive[1], res_cambricon[1]);
ASSERT_NE(res_cambricon[0], res_cambricon[1]);
};
for (size_t i = 0; i < 8; ++i) {
run_offsset(i);
}
}
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/test/cambricon/fixture.cpp
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#include "test/cambricon/fixture.h"
#include "src/cambricon/handle.h"
#include "src/cambricon/utils.h"
#include "test/common/memory_manager.h"
#include "test/common/random_state.h"
#include "test/common/utils.h"
#include <cnrt.h>
#include <cstdlib>
using namespace megdnn;
using namespace test;
void CAMBRICON::SetUp() {
RandomState::reset();
megcoreDeviceHandle_t dev_handle;
// use card 0
megcore_check(megcoreCreateDeviceHandle(&dev_handle, megcorePlatformCambricon, 0));
megcoreComputingHandle_t comp_handle;
megcore_check(megcoreCreateComputingHandle(&comp_handle, dev_handle));
m_handle_cambricon = Handle::make(comp_handle);
megdnn_assert(m_handle_cambricon);
}
Handle* CAMBRICON::handle_naive() {
if (!m_handle_naive)
m_handle_naive = create_cpu_handle(2);
return m_handle_naive.get();
}
void CAMBRICON::TearDown() {
m_handle_naive.reset();
m_handle_cambricon.reset();
MemoryManagerHolder::instance()->clear();
}
// vim: syntax=cpp.doxygen
/**
* \file dnn/test/cambricon/fixture.h
* MegEngine is Licensed under the Apache License, Version 2.0 (the "License")
*
* Copyright (c) 2014-2021 Megvii Inc. All rights reserved.
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT ARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*/
#pragma once
#include <gtest/gtest.h>
#include "test/common/fix_gtest_on_platforms_without_exception.inl"
#include "megcore_cdefs.h"
#include "megdnn/handle.h"
#include <memory>
namespace megdnn {
namespace test {
class CAMBRICON : public ::testing::Test {
public:
void SetUp() override;
void TearDown() override;
Handle* handle_cambricon() { return m_handle_cambricon.get(); }
Handle* handle_naive();
private:
std::unique_ptr<Handle> m_handle_naive;
std::unique_ptr<Handle> m_handle_cambricon;
};
} // namespace test
} // namespace megdnn
// vim: syntax=cpp.doxygen
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册