kfdtest: Add kfdtest source code
The code is a snapshot up to this commit around July 31 2018. commit b00fadff36a3 Author: xinhui pan <xinhui.pan@amd.com> Date: Mon Jul 30 09:53:03 2018 +0800 kfdtest: skip MMapLarge test on apu Change-Id: I40e9a5a18e5c8f075e5290bb80532f1a3f689058 Signed-off-by: Yong Zhao <yong.zhao@amd.com>
This commit is contained in:
@@ -0,0 +1,108 @@
|
||||
#
|
||||
# Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
# If environment variable DRM_DIR or THUNK_LIB_OUT is set, the script
|
||||
# will pick up the corresponding libraries from those pathes.
|
||||
|
||||
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
|
||||
|
||||
project(KFDTest)
|
||||
|
||||
#set ( CMAKE_VERBOSE_MAKEFILE on )
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
if( DEFINED ENV{DRM_DIR} )
|
||||
#assume header files and libraries are under the same path
|
||||
set ( DRM_DIR $ENV{DRM_DIR} )
|
||||
set ( DRM_INCLUDE_DIRS ${DRM_DIR}/include )
|
||||
link_directories(${DRM_DIR}/lib64)
|
||||
set ( DRM_LIBRARIES drm )
|
||||
set ( DRM_AMDGPU_LIBRARIES drm_amdgpu )
|
||||
else()
|
||||
# The module name passed to pkg_check_modules() is determined by the
|
||||
# name of file *.pc
|
||||
pkg_check_modules(DRM REQUIRED libdrm)
|
||||
pkg_check_modules(DRM_AMDGPU REQUIRED libdrm_amdgpu)
|
||||
include_directories(${DRM_AMDGPU_INCLUDE_DIRS})
|
||||
endif()
|
||||
|
||||
|
||||
if( DEFINED ENV{THUNK_LIB_OUT} )
|
||||
set ( THUNK_LIB_OUT $ENV{THUNK_LIB_OUT} )
|
||||
message ( " THUNK_LIB_OUT environment variable is set" )
|
||||
else()
|
||||
set ( ENV{PKG_CONFIG_PATH} /opt/rocm/libhsakmt/ )
|
||||
pkg_check_modules(HSAKMT libhsakmt)
|
||||
if( NOT HSAKMT_FOUND )
|
||||
set ( THUNK_LIB_OUT $ENV{OUT_DIR} )
|
||||
endif()
|
||||
endif()
|
||||
|
||||
if( DEFINED THUNK_LIB_OUT )
|
||||
set ( HSAKMT_INCLUDE_DIRS ${THUNK_LIB_OUT}/include )
|
||||
set ( HSAKMT_LIBRARY_DIRS ${THUNK_LIB_OUT}/lib )
|
||||
set ( HSAKMT_LIBRARIES hsakmt )
|
||||
endif()
|
||||
|
||||
message ( "Find thunk lib at ${HSAKMT_LIBRARY_DIRS}" )
|
||||
|
||||
set ( SP3_DIR ${PROJECT_SOURCE_DIR}/sp3 )
|
||||
|
||||
include_directories(${PROJECT_SOURCE_DIR}/gtest-1.6.0)
|
||||
include_directories(${PROJECT_SOURCE_DIR}/include)
|
||||
include_directories(${SP3_DIR})
|
||||
|
||||
include_directories(${HSAKMT_INCLUDE_DIRS})
|
||||
include_directories(${DRM_INCLUDE_DIRS})
|
||||
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/gtest-1.6.0 SRC_FILES)
|
||||
aux_source_directory(${PROJECT_SOURCE_DIR}/src SRC_FILES)
|
||||
|
||||
message( STATUS "PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR} )
|
||||
#message( STATUS "SRC_FILES: ")
|
||||
#foreach(file ${SRC_FILES})
|
||||
# message(STATUS "${file}")
|
||||
#endforeach()
|
||||
|
||||
#add_definitions(-Wall -std=c++11)
|
||||
|
||||
if ( "${CMAKE_C_COMPILER_VERSION}" STRGREATER "4.8.0")
|
||||
set ( CMAKE_CXX_FLAGS "-std=gnu++11" )
|
||||
endif()
|
||||
if ( "${CMAKE_BUILD_TYPE}" STREQUAL Release )
|
||||
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O2" )
|
||||
else ()
|
||||
set ( CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g" )
|
||||
endif ()
|
||||
|
||||
# link_directories() has to be put before add_executable()
|
||||
# The modules found by pkg_check_modules() in the default pkg config
|
||||
# path do not need to use link_directories() here.
|
||||
link_directories(${HSAKMT_LIBRARY_DIRS})
|
||||
link_directories(${SP3_DIR})
|
||||
|
||||
add_executable(kfdtest ${SRC_FILES})
|
||||
|
||||
target_link_libraries(kfdtest ${HSAKMT_LIBRARIES} ${DRM_LIBRARIES} ${DRM_AMDGPU_LIBRARIES} pthread m stdc++ rt amdsp3)
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
KFDTest - KFD unit tests LICENSE
|
||||
/* The following license applies to all parts of kfdtest except the
|
||||
* SP3 shader assembler. See separate license terms below.
|
||||
*/
|
||||
|
||||
Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
|
||||
MIT LICENSE:
|
||||
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.
|
||||
|
||||
-----------------------------------------------
|
||||
|
||||
libamdsp3 - AMD SP3 shader assembler library LICENSE
|
||||
/* The following license applies to the SP3 shader assembler, which is
|
||||
* named as libamdsp3.a and will be built into the kfdtest binary.
|
||||
*/
|
||||
|
||||
Copyright (C) 2018 Advanced Micro Devices, Inc. All rights reserved.
|
||||
|
||||
REDISTRIBUTION: Permission is hereby granted, free of any license fees,
|
||||
to any person obtaining a copy of this program (the "Software"), to
|
||||
install, reproduce, copy and distribute copies, in binary form only, of
|
||||
the Software and to permit persons to whom the Software is provided to
|
||||
do the same, provided that the following conditions are met:
|
||||
|
||||
No reverse engineering, decompilation, or disassembly of this Software
|
||||
is permitted.
|
||||
|
||||
Redistributions must reproduce the above copyright notice, this
|
||||
permission notice, and the following disclaimers and notices in the
|
||||
Software documentation and/or other materials provided with the
|
||||
Software.
|
||||
|
||||
DISCLAIMER: THE USE OF THE SOFTWARE IS AT YOUR SOLE RISK. THE SOFTWARE
|
||||
IS PROVIDED "AS IS" AND WITHOUT WARRANTY OF ANY KIND AND COPYRIGHT
|
||||
HOLDER AND ITS LICENSORS EXPRESSLY DISCLAIM ALL WARRANTIES, EXPRESS AND
|
||||
IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
||||
COPYRIGHT HOLDER AND ITS LICENSORS DO NOT WARRANT THAT THE SOFTWARE WILL
|
||||
MEET YOUR REQUIREMENTS, OR THAT THE OPERATION OF THE SOFTWARE WILL BE
|
||||
UNINTERRUPTED OR ERROR-FREE. THE ENTIRE RISK ASSOCIATED WITH THE USE OF
|
||||
THE SOFTWARE IS ASSUMED BY YOU. FURTHERMORE, COPYRIGHT HOLDER AND ITS
|
||||
LICENSORS DO NOT WARRANT OR MAKE ANY REPRESENTATIONS REGARDING THE USE
|
||||
OR THE RESULTS OF THE USE OF THE SOFTWARE IN TERMS OF ITS CORRECTNESS,
|
||||
ACCURACY, RELIABILITY, CURRENTNESS, OR OTHERWISE.
|
||||
|
||||
DISCLAIMER: UNDER NO CIRCUMSTANCES INCLUDING NEGLIGENCE, SHALL COPYRIGHT
|
||||
HOLDER AND ITS LICENSORS OR ITS DIRECTORS, OFFICERS, EMPLOYEES OR AGENTS
|
||||
("AUTHORIZED REPRESENTATIVES") BE LIABLE FOR ANY INCIDENTAL, INDIRECT,
|
||||
SPECIAL OR CONSEQUENTIAL DAMAGES (INCLUDING DAMAGES FOR LOSS OF BUSINESS
|
||||
PROFITS, BUSINESS INTERRUPTION, LOSS OF BUSINESS INFORMATION, AND THE
|
||||
LIKE) ARISING OUT OF THE USE, MISUSE OR INABILITY TO USE THE SOFTWARE,
|
||||
BREACH OR DEFAULT, INCLUDING THOSE ARISING FROM INFRINGEMENT OR ALLEGED
|
||||
INFRINGEMENT OF ANY PATENT, TRADEMARK, COPYRIGHT OR OTHER INTELLECTUAL
|
||||
PROPERTY RIGHT EVEN IF COPYRIGHT HOLDER AND ITS AUTHORIZED
|
||||
REPRESENTATIVES HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. IN
|
||||
NO EVENT SHALL COPYRIGHT HOLDER OR ITS AUTHORIZED REPRESENTATIVES TOTAL
|
||||
LIABILITY FOR ALL DAMAGES, LOSSES, AND CAUSES OF ACTION (WHETHER IN
|
||||
CONTRACT, TORT (INCLUDING NEGLIGENCE) OR OTHERWISE) EXCEED THE AMOUNT OF
|
||||
US$10.
|
||||
|
||||
Notice: The Software is subject to United States export laws and
|
||||
regulations. You agree to comply with all domestic and international
|
||||
export laws and regulations that apply to the Software, including but
|
||||
not limited to the Export Administration Regulations administered by the
|
||||
U.S. Department of Commerce and International Traffic in Arm Regulations
|
||||
administered by the U.S. Department of State. These laws include
|
||||
restrictions on destinations, end users and end use.
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,76 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
#ifndef AMDP2PTEST_H_
|
||||
#define AMDP2PTEST_H_
|
||||
|
||||
#include <linux/ioctl.h>
|
||||
|
||||
#define AMDP2PTEST_IOCTL_MAGIC 'A'
|
||||
|
||||
|
||||
#define AMDP2PTEST_DEVICE_NAME "amdp2ptest"
|
||||
#define AMDP2PTEST_DEVICE_PATH "/dev/amdp2ptest"
|
||||
|
||||
struct AMDRDMA_IOCTL_GET_PAGE_SIZE_PARAM {
|
||||
/* Input parameters */
|
||||
uint64_t addr;
|
||||
uint64_t length;
|
||||
|
||||
/* Output parameters */
|
||||
uint64_t page_size;
|
||||
};
|
||||
|
||||
struct AMDRDMA_IOCTL_GET_PAGES_PARAM {
|
||||
/* Input parameters */
|
||||
uint64_t addr;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
|
||||
struct AMDRDMA_IOCTL_PUT_PAGES_PARAM {
|
||||
/* Input parameters */
|
||||
uint64_t addr;
|
||||
uint64_t length;
|
||||
};
|
||||
|
||||
struct AMDRDMA_IOCTL_IS_GPU_ADDRESS_PARAM {
|
||||
/* Input parameters */
|
||||
uint64_t addr;
|
||||
uint64_t ret_value;
|
||||
};
|
||||
|
||||
|
||||
#define AMD2P2PTEST_IOCTL_GET_PAGE_SIZE \
|
||||
_IOWR(AMDP2PTEST_IOCTL_MAGIC, 1, struct AMDRDMA_IOCTL_GET_PAGE_SIZE_PARAM *)
|
||||
|
||||
#define AMD2P2PTEST_IOCTL_GET_PAGES \
|
||||
_IOWR(AMDP2PTEST_IOCTL_MAGIC, 2, struct AMDRDMA_IOCTL_GET_PAGES_PARAM *)
|
||||
|
||||
#define AMD2P2PTEST_IOCTL_PUT_PAGES \
|
||||
_IOW(AMDP2PTEST_IOCTL_MAGIC, 3, struct AMDRDMA_IOCTL_PUT_PAGES_PARAM *)
|
||||
|
||||
#define AMD2P2PTEST_IOCTL_IS_GPU_ADDRESS \
|
||||
_IOW(AMDP2PTEST_IOCTL_MAGIC, 4, struct AMDRDMA_IOCTL_IS_GPU_ADDRESS *)
|
||||
|
||||
|
||||
#endif /* AMDP2PTEST_H */
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,107 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
|
||||
#ifndef KFD_PM4_OPCODES_H
|
||||
#define KFD_PM4_OPCODES_H
|
||||
|
||||
enum it_opcode_type {
|
||||
IT_NOP = 0x10,
|
||||
IT_SET_BASE = 0x11,
|
||||
IT_CLEAR_STATE = 0x12,
|
||||
IT_INDEX_BUFFER_SIZE = 0x13,
|
||||
IT_DISPATCH_DIRECT = 0x15,
|
||||
IT_DISPATCH_INDIRECT = 0x16,
|
||||
IT_ATOMIC_GDS = 0x1D,
|
||||
IT_OCCLUSION_QUERY = 0x1F,
|
||||
IT_SET_PREDICATION = 0x20,
|
||||
IT_REG_RMW = 0x21,
|
||||
IT_COND_EXEC = 0x22,
|
||||
IT_PRED_EXEC = 0x23,
|
||||
IT_DRAW_INDIRECT = 0x24,
|
||||
IT_DRAW_INDEX_INDIRECT = 0x25,
|
||||
IT_INDEX_BASE = 0x26,
|
||||
IT_DRAW_INDEX_2 = 0x27,
|
||||
IT_CONTEXT_CONTROL = 0x28,
|
||||
IT_INDEX_TYPE = 0x2A,
|
||||
IT_DRAW_INDIRECT_MULTI = 0x2C,
|
||||
IT_DRAW_INDEX_AUTO = 0x2D,
|
||||
IT_NUM_INSTANCES = 0x2F,
|
||||
IT_DRAW_INDEX_MULTI_AUTO = 0x30,
|
||||
IT_INDIRECT_BUFFER_CNST = 0x33,
|
||||
IT_STRMOUT_BUFFER_UPDATE = 0x34,
|
||||
IT_DRAW_INDEX_OFFSET_2 = 0x35,
|
||||
IT_DRAW_PREAMBLE = 0x36,
|
||||
IT_WRITE_DATA = 0x37,
|
||||
IT_DRAW_INDEX_INDIRECT_MULTI = 0x38,
|
||||
IT_MEM_SEMAPHORE = 0x39,
|
||||
IT_COPY_DW = 0x3B,
|
||||
IT_WAIT_REG_MEM = 0x3C,
|
||||
IT_INDIRECT_BUFFER = 0x3F,
|
||||
IT_COPY_DATA = 0x40,
|
||||
IT_PFP_SYNC_ME = 0x42,
|
||||
IT_SURFACE_SYNC = 0x43,
|
||||
IT_COND_WRITE = 0x45,
|
||||
IT_EVENT_WRITE = 0x46,
|
||||
IT_EVENT_WRITE_EOP = 0x47,
|
||||
IT_EVENT_WRITE_EOS = 0x48,
|
||||
IT_RELEASE_MEM = 0x49,
|
||||
IT_PREAMBLE_CNTL = 0x4A,
|
||||
IT_DMA_DATA = 0x50,
|
||||
IT_ACQUIRE_MEM = 0x58,
|
||||
IT_REWIND = 0x59,
|
||||
IT_LOAD_UCONFIG_REG = 0x5E,
|
||||
IT_LOAD_SH_REG = 0x5F,
|
||||
IT_LOAD_CONFIG_REG = 0x60,
|
||||
IT_LOAD_CONTEXT_REG = 0x61,
|
||||
IT_SET_CONFIG_REG = 0x68,
|
||||
IT_SET_CONTEXT_REG = 0x69,
|
||||
IT_SET_CONTEXT_REG_INDIRECT = 0x73,
|
||||
IT_SET_SH_REG = 0x76,
|
||||
IT_SET_SH_REG_OFFSET = 0x77,
|
||||
IT_SET_QUEUE_REG = 0x78,
|
||||
IT_SET_UCONFIG_REG = 0x79,
|
||||
IT_SCRATCH_RAM_WRITE = 0x7D,
|
||||
IT_SCRATCH_RAM_READ = 0x7E,
|
||||
IT_LOAD_CONST_RAM = 0x80,
|
||||
IT_WRITE_CONST_RAM = 0x81,
|
||||
IT_DUMP_CONST_RAM = 0x83,
|
||||
IT_INCREMENT_CE_COUNTER = 0x84,
|
||||
IT_INCREMENT_DE_COUNTER = 0x85,
|
||||
IT_WAIT_ON_CE_COUNTER = 0x86,
|
||||
IT_WAIT_ON_DE_COUNTER_DIFF = 0x88,
|
||||
IT_SWITCH_BUFFER = 0x8B,
|
||||
IT_SET_RESOURCES = 0xA0,
|
||||
IT_MAP_PROCESS = 0xA1,
|
||||
IT_MAP_QUEUES = 0xA2,
|
||||
IT_UNMAP_QUEUES = 0xA3,
|
||||
IT_QUERY_STATUS = 0xA4,
|
||||
IT_RUN_LIST = 0xA5,
|
||||
};
|
||||
|
||||
#define PM4_TYPE_0 0
|
||||
#define PM4_TYPE_2 2
|
||||
#define PM4_TYPE_3 3
|
||||
|
||||
#endif /* KFD_PM4_OPCODES_H */
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PM4_PKT_STRUCT_AI_H__
|
||||
#define __PM4_PKT_STRUCT_AI_H__
|
||||
|
||||
#ifndef PM4_MEC_RELEASE_MEM_AI_DEFINED
|
||||
#define PM4_MEC_RELEASE_MEM_AI_DEFINED
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_event_index_enum {
|
||||
event_index__mec_release_mem__end_of_pipe = 5,
|
||||
event_index__mec_release_mem__shader_done = 6 };
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_cache_policy_enum {
|
||||
cache_policy__mec_release_mem__lru = 0,
|
||||
cache_policy__mec_release_mem__stream = 1 };
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_pq_exe_status_enum {
|
||||
pq_exe_status__mec_release_mem__default = 0,
|
||||
pq_exe_status__mec_release_mem__phase_update = 1 };
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_dst_sel_enum {
|
||||
dst_sel__mec_release_mem__memory_controller = 0,
|
||||
dst_sel__mec_release_mem__tc_l2 = 1,
|
||||
dst_sel__mec_release_mem__queue_write_pointer_register = 2,
|
||||
dst_sel__mec_release_mem__queue_write_pointer_poll_mask_bit = 3 };
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_int_sel_enum {
|
||||
int_sel__mec_release_mem__none = 0,
|
||||
int_sel__mec_release_mem__send_interrupt_only = 1,
|
||||
int_sel__mec_release_mem__send_interrupt_after_write_confirm = 2,
|
||||
int_sel__mec_release_mem__send_data_after_write_confirm = 3,
|
||||
int_sel__mec_release_mem__unconditionally_send_int_ctxid = 4,
|
||||
int_sel__mec_release_mem__conditionally_send_int_ctxid_based_on_32_bit_compare = 5,
|
||||
int_sel__mec_release_mem__conditionally_send_int_ctxid_based_on_64_bit_compare = 6 };
|
||||
|
||||
enum AI_MEC_RELEASE_MEM_data_sel_enum {
|
||||
data_sel__mec_release_mem__none = 0,
|
||||
data_sel__mec_release_mem__send_32_bit_low = 1,
|
||||
data_sel__mec_release_mem__send_64_bit_data = 2,
|
||||
data_sel__mec_release_mem__send_gpu_clock_counter = 3,
|
||||
data_sel__mec_release_mem__send_cp_perfcounter_hi_lo = 4,
|
||||
data_sel__mec_release_mem__store_gds_data_to_memory = 5 };
|
||||
|
||||
|
||||
typedef struct PM4_MEC_RELEASE_MEM_AI {
|
||||
union {
|
||||
PM4_TYPE_3_HEADER header;
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int event_type:6;
|
||||
unsigned int reserved1:2;
|
||||
AI_MEC_RELEASE_MEM_event_index_enum event_index:4;
|
||||
unsigned int tcl1_vol_action_ena:1;
|
||||
unsigned int tc_vol_action_ena:1;
|
||||
unsigned int reserved2:1;
|
||||
unsigned int tc_wb_action_ena:1;
|
||||
unsigned int tcl1_action_ena:1;
|
||||
unsigned int tc_action_ena:1;
|
||||
unsigned int reserved3:1;
|
||||
unsigned int tc_nc_action_ena:1;
|
||||
unsigned int tc_wc_action_ena:1;
|
||||
unsigned int tc_md_action_ena:1;
|
||||
unsigned int reserved4:3;
|
||||
AI_MEC_RELEASE_MEM_cache_policy_enum cache_policy:2;
|
||||
unsigned int reserved5:2;
|
||||
AI_MEC_RELEASE_MEM_pq_exe_status_enum pq_exe_status:1;
|
||||
unsigned int reserved6:2;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved7:16;
|
||||
AI_MEC_RELEASE_MEM_dst_sel_enum dst_sel:2;
|
||||
unsigned int reserved8:6;
|
||||
AI_MEC_RELEASE_MEM_int_sel_enum int_sel:3;
|
||||
unsigned int reserved9:2;
|
||||
AI_MEC_RELEASE_MEM_data_sel_enum data_sel:3;
|
||||
} bitfields3;
|
||||
unsigned int ordinal3;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved10:2;
|
||||
unsigned int address_lo_32b:30;
|
||||
} bitfields4a;
|
||||
struct {
|
||||
unsigned int reserved11:3;
|
||||
unsigned int address_lo_64b:29;
|
||||
} bitfields4b;
|
||||
unsigned int reserved12;
|
||||
|
||||
unsigned int ordinal4;
|
||||
};
|
||||
|
||||
union {
|
||||
unsigned int address_hi;
|
||||
|
||||
unsigned int reserved13;
|
||||
|
||||
unsigned int ordinal5;
|
||||
};
|
||||
|
||||
union {
|
||||
unsigned int data_lo;
|
||||
|
||||
unsigned int cmp_data_lo;
|
||||
|
||||
struct {
|
||||
unsigned int dw_offset:16;
|
||||
unsigned int num_dwords:16;
|
||||
} bitfields6c;
|
||||
unsigned int reserved14;
|
||||
|
||||
unsigned int ordinal6;
|
||||
};
|
||||
|
||||
union {
|
||||
unsigned int data_hi;
|
||||
|
||||
unsigned int cmp_data_hi;
|
||||
|
||||
unsigned int reserved15;
|
||||
|
||||
unsigned int reserved16;
|
||||
|
||||
unsigned int ordinal7;
|
||||
};
|
||||
|
||||
unsigned int int_ctxid;
|
||||
} PM4MEC_RELEASE_MEM_AI, *PPM4MEC_RELEASE_MEM_AI;
|
||||
|
||||
#endif // PM4_MEC_RELEASE_MEM_AI_DEFINED
|
||||
#endif // __PM4_PKT_STRUCT_AI_H__
|
||||
@@ -0,0 +1,129 @@
|
||||
/*
|
||||
* Copyright (C) 2012-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PM4_PKT_STRUCT_CI_H__
|
||||
#define __PM4_PKT_STRUCT_CI_H__
|
||||
|
||||
|
||||
enum WRITE_DATA_CI_atc_enum { atc_write_data_NOT_USE_ATC_0 = 0, atc_write_data_USE_ATC_1 = 1 };
|
||||
enum WRITE_DATA_CI_engine_sel { engine_sel_write_data_ci_MICRO_ENGINE_0 = 0, engine_sel_write_data_ci_PREFETCH_PARSER_1 = 1, engine_sel_write_data_ci_CONST_ENG_2 = 2 };
|
||||
|
||||
typedef struct _PM4WRITE_DATA_CI {
|
||||
union {
|
||||
PM4_TYPE_3_HEADER header;
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved1:8;
|
||||
MEC_WRITE_DATA_dst_sel_enum dst_sel:4;
|
||||
unsigned int reserved2:4;
|
||||
MEC_WRITE_DATA_addr_incr_enum addr_incr:1;
|
||||
unsigned int reserved3:3;
|
||||
MEC_WRITE_DATA_wr_confirm_enum wr_confirm:1;
|
||||
unsigned int reserved4:3;
|
||||
WRITE_DATA_CI_atc_enum atc:1;
|
||||
MEC_WRITE_DATA_cache_policy_enum cache_policy:2;
|
||||
unsigned int volatile_setting:1;
|
||||
unsigned int reserved5:2;
|
||||
WRITE_DATA_CI_engine_sel engine_sel:2;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
unsigned int dst_addr_lo;
|
||||
|
||||
unsigned int dst_address_hi;
|
||||
|
||||
unsigned int data[1]; // 1..N of these fields
|
||||
} PM4WRITE_DATA_CI, *PPM4WRITE_DATA_CI;
|
||||
|
||||
|
||||
enum MEC_RELEASE_MEM_CI_atc_enum { atc_mec_release_mem_ci_NOT_USE_ATC_0 = 0, atc_mec_release_mem_ci_USE_ATC_1 = 1 };
|
||||
|
||||
typedef struct _PM4_RELEASE_MEM_CI {
|
||||
union {
|
||||
PM4_TYPE_3_HEADER header;
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int event_type:6;
|
||||
unsigned int reserved1:2;
|
||||
MEC_RELEASE_MEM_event_index_enum event_index:4;
|
||||
unsigned int l1_vol:1;
|
||||
unsigned int l2_vol:1;
|
||||
unsigned int reserved:1;
|
||||
unsigned int l2_wb:1;
|
||||
unsigned int l1_inv:1;
|
||||
unsigned int l2_inv:1;
|
||||
unsigned int reserved2:6;
|
||||
MEC_RELEASE_MEM_CI_atc_enum atc:1;
|
||||
MEC_RELEASE_MEM_cache_policy_enum cache_policy:2;
|
||||
unsigned int volatile_setting:1;
|
||||
unsigned int reserved3:4;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved4:16;
|
||||
MEC_RELEASE_MEM_dst_sel_enum dst_sel:2;
|
||||
unsigned int reserved5:6;
|
||||
MEC_RELEASE_MEM_int_sel_enum int_sel:3;
|
||||
unsigned int reserved6:2;
|
||||
MEC_RELEASE_MEM_data_sel_enum data_sel:3;
|
||||
} bitfields3;
|
||||
unsigned int ordinal3;
|
||||
};
|
||||
|
||||
union {
|
||||
struct {
|
||||
unsigned int reserved7:2;
|
||||
unsigned int address_lo_dword_aligned:30;
|
||||
} bitfields4a;
|
||||
struct {
|
||||
unsigned int reserved8:3;
|
||||
unsigned int address_lo_qword_aligned:29;
|
||||
} bitfields4b;
|
||||
unsigned int ordinal4;
|
||||
};
|
||||
|
||||
unsigned int addr_hi;
|
||||
|
||||
union {
|
||||
unsigned int data_lo;
|
||||
struct {
|
||||
unsigned int offset:16;
|
||||
unsigned int num_dwords:16;
|
||||
} bitfields5b;
|
||||
unsigned int ordinal6;
|
||||
};
|
||||
|
||||
unsigned int data_hi;
|
||||
} PM4_RELEASE_MEM_CI, *PPM4_RELEASE_MEM_CI;
|
||||
|
||||
#endif // __PM4_PKT_STRUCT_CI_H__
|
||||
@@ -0,0 +1,275 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __PM4_PKT_STRUCT_COMMON_H__
|
||||
#define __PM4_PKT_STRUCT_COMMON_H__
|
||||
|
||||
#ifndef PM4_HEADER_DEFINED
|
||||
#define PM4_HEADER_DEFINED
|
||||
typedef union PM4_TYPE_3_HEADER
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int predicate : 1; ///< predicated version of packet when set
|
||||
unsigned int shaderType: 1; ///< 0: Graphics, 1: Compute Shader
|
||||
unsigned int reserved1 : 6; ///< reserved
|
||||
unsigned int opcode : 8; ///< IT opcode
|
||||
unsigned int count : 14;///< number of DWORDs - 1 in the information body.
|
||||
unsigned int type : 2; ///< packet identifier. It should be 3 for type 3 packets
|
||||
};
|
||||
unsigned int u32All;
|
||||
} PM4_TYPE_3_HEADER;
|
||||
#endif // PM4_HEADER_DEFINED
|
||||
|
||||
//--------------------DISPATCH_DIRECT--------------------
|
||||
|
||||
|
||||
typedef struct _PM4_DISPATCH_DIRECT
|
||||
{
|
||||
union
|
||||
{
|
||||
PM4_TYPE_3_HEADER header; ///header
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
unsigned int dim_x;
|
||||
|
||||
|
||||
unsigned int dim_y;
|
||||
|
||||
|
||||
unsigned int dim_z;
|
||||
|
||||
|
||||
unsigned int dispatch_initiator;
|
||||
|
||||
|
||||
} PM4DISPATCH_DIRECT, *PPM4DISPATCH_DIRECT;
|
||||
|
||||
//--------------------INDIRECT_BUFFER--------------------
|
||||
|
||||
enum INDIRECT_BUFFER_cache_policy_enum { cache_policy_indirect_buffer_LRU_0 = 0, cache_policy_indirect_buffer_STREAM_1 = 1, cache_policy_indirect_buffer_BYPASS_2 = 2 };
|
||||
|
||||
|
||||
//--------------------EVENT_WRITE--------------------
|
||||
|
||||
enum EVENT_WRITE_event_index_enum { event_index_event_write_OTHER_0 = 0, event_index_event_write_ZPASS_DONE_1 = 1, event_index_event_write_SAMPLE_PIPELINESTAT_2 = 2, event_index_event_write_SAMPLE_STREAMOUTSTAT_3 = 3, event_index_event_write_CS_VS_PS_PARTIAL_FLUSH_4 = 4, event_index_event_write_RESERVED_EOP_5 = 5, event_index_event_write_RESERVED_EOS_6 = 6, event_index_event_write_CACHE_FLUSH_7 = 7 };
|
||||
|
||||
typedef struct _PM4_EVENT_WRITE
|
||||
{
|
||||
union
|
||||
{
|
||||
PM4_TYPE_3_HEADER header; ///header
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int event_type:6;
|
||||
unsigned int reserved1:2;
|
||||
EVENT_WRITE_event_index_enum event_index:4;
|
||||
unsigned int reserved2:20;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int reserved3:3;
|
||||
unsigned int address_lo:29;
|
||||
} bitfields3;
|
||||
unsigned int ordinal3;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int address_hi:16;
|
||||
unsigned int reserved4:16;
|
||||
} bitfields4;
|
||||
unsigned int ordinal4;
|
||||
};
|
||||
|
||||
} PM4EVENT_WRITE, *PPM4EVENT_WRITE;
|
||||
|
||||
|
||||
//--------------------SET_SH_REG--------------------
|
||||
|
||||
|
||||
typedef struct _PM4_SET_SH_REG
|
||||
{
|
||||
union
|
||||
{
|
||||
PM4_TYPE_3_HEADER header; ///header
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int reg_offset:16;
|
||||
unsigned int reserved1:16;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
unsigned int reg_data[1]; //1..N of these fields
|
||||
|
||||
|
||||
} PM4SET_SH_REG, *PPM4SET_SH_REG;
|
||||
|
||||
|
||||
//--------------------ACQUIRE_MEM--------------------
|
||||
|
||||
enum ACQUIRE_MEM_engine_enum { engine_acquire_mem_PFP_0 = 0, engine_acquire_mem_ME_1 = 1 };
|
||||
|
||||
|
||||
typedef struct _PM4_ACQUIRE_MEM
|
||||
{
|
||||
union
|
||||
{
|
||||
PM4_TYPE_3_HEADER header; ///header
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int coher_cntl:31;
|
||||
ACQUIRE_MEM_engine_enum engine:1;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
unsigned int coher_size;
|
||||
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int coher_size_hi:8;
|
||||
unsigned int reserved1:24;
|
||||
} bitfields3;
|
||||
unsigned int ordinal4;
|
||||
};
|
||||
|
||||
unsigned int coher_base_lo;
|
||||
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int coher_base_hi:25;
|
||||
unsigned int reserved2:7;
|
||||
} bitfields4;
|
||||
unsigned int ordinal6;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int poll_interval:16;
|
||||
unsigned int reserved3:16;
|
||||
} bitfields5;
|
||||
unsigned int ordinal7;
|
||||
};
|
||||
|
||||
} PM4ACQUIRE_MEM, *PPM4ACQUIRE_MEM;
|
||||
|
||||
|
||||
//--------------------MEC_INDIRECT_BUFFER--------------------
|
||||
|
||||
typedef struct _PM4_MEC_INDIRECT_BUFFER
|
||||
{
|
||||
union
|
||||
{
|
||||
PM4_TYPE_3_HEADER header; ///header
|
||||
unsigned int ordinal1;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int swap_function:2;
|
||||
unsigned int ib_base_lo:30;
|
||||
} bitfields2;
|
||||
unsigned int ordinal2;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int ib_base_hi:16;
|
||||
unsigned int reserved1:16;
|
||||
} bitfields3;
|
||||
unsigned int ordinal3;
|
||||
};
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int ib_size:20;
|
||||
unsigned int chain:1;
|
||||
unsigned int offload_polling:1;
|
||||
unsigned int volatile_setting:1;
|
||||
unsigned int valid:1;
|
||||
unsigned int vmid:4;
|
||||
INDIRECT_BUFFER_cache_policy_enum cache_policy:2;
|
||||
unsigned int reserved4:2;
|
||||
} bitfields4;
|
||||
unsigned int ordinal4;
|
||||
};
|
||||
|
||||
} PM4MEC_INDIRECT_BUFFER, *PPM4MEC_INDIRECT_BUFFER;
|
||||
|
||||
//--------------------MEC_WRITE_DATA--------------------
|
||||
|
||||
enum MEC_WRITE_DATA_dst_sel_enum { dst_sel_mec_write_data_MEM_MAPPED_REGISTER_0 = 0, dst_sel_mec_write_data_TC_L2_2 = 2, dst_sel_mec_write_data_GDS_3 = 3, dst_sel_mec_write_data_MEMORY_5 = 5 };
|
||||
enum MEC_WRITE_DATA_addr_incr_enum { addr_incr_mec_write_data_INCREMENT_ADDR_0 = 0, addr_incr_mec_write_data_DO_NOT_INCREMENT_ADDR_1 = 1 };
|
||||
enum MEC_WRITE_DATA_wr_confirm_enum { wr_confirm_mec_write_data_DO_NOT_WAIT_FOR_CONFIRMATION_0 = 0, wr_confirm_mec_write_data_WAIT_FOR_CONFIRMATION_1 = 1 };
|
||||
enum MEC_WRITE_DATA_cache_policy_enum { cache_policy_mec_write_data_LRU_0 = 0, cache_policy_mec_write_data_STREAM_1 = 1, cache_policy_mec_write_data_BYPASS_2 = 2 };
|
||||
|
||||
//--------------------MEC_RELEASE_MEM--------------------
|
||||
|
||||
enum MEC_RELEASE_MEM_event_index_enum { event_index_mec_release_mem_EVENT_WRITE_EOP_5 = 5, event_index_mec_release_mem_CS_Done_6 = 6 };
|
||||
enum MEC_RELEASE_MEM_cache_policy_enum { cache_policy_mec_release_mem_LRU_0 = 0, cache_policy_mec_release_mem_STREAM_1 = 1, cache_policy_mec_release_mem_BYPASS_2 = 2 };
|
||||
enum MEC_RELEASE_MEM_dst_sel_enum { dst_sel_mec_release_mem_MEMORY_CONTROLLER_0 = 0, dst_sel_mec_release_mem_TC_L2_1 = 1 };
|
||||
enum MEC_RELEASE_MEM_int_sel_enum { int_sel_mec_release_mem_NONE_0 = 0, int_sel_mec_release_mem_SEND_INTERRUPT_ONLY_1 = 1, int_sel_mec_release_mem_SEND_INTERRUPT_AFTER_WRITE_CONFIRM_2 = 2, int_sel_mec_release_mem_SEND_DATA_AFTER_WRITE_CONFIRM_3 = 3 };
|
||||
enum MEC_RELEASE_MEM_data_sel_enum { data_sel_mec_release_mem_NONE_0 = 0, data_sel_mec_release_mem_SEND_32_BIT_LOW_1 = 1, data_sel_mec_release_mem_SEND_64_BIT_DATA_2 = 2, data_sel_mec_release_mem_SEND_GPU_CLOCK_COUNTER_3 = 3, data_sel_mec_release_mem_SEND_CP_PERFCOUNTER_HI_LO_4 = 4, data_sel_mec_release_mem_STORE_GDS_DATA_TO_MEMORY_5 = 5 };
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,316 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SDMA_PKT_STRUCT_H__
|
||||
#define __SDMA_PKT_STRUCT_H__
|
||||
|
||||
|
||||
const unsigned int SDMA_OP_COPY = 1;
|
||||
const unsigned int SDMA_OP_WRITE = 2;
|
||||
|
||||
const unsigned int SDMA_OP_FENCE = 5;
|
||||
const unsigned int SDMA_OP_TRAP = 6;
|
||||
|
||||
const unsigned int SDMA_OP_CONST_FILL = 11;
|
||||
|
||||
const unsigned int SDMA_SUBOP_COPY_LINEAR = 0;
|
||||
|
||||
const unsigned int SDMA_SUBOP_WRITE_LINEAR = 0;
|
||||
|
||||
/*
|
||||
** Definitions for SDMA_PKT_COPY_LINEAR packet
|
||||
*/
|
||||
|
||||
typedef struct SDMA_PKT_COPY_LINEAR_TAG
|
||||
{
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int op:8;
|
||||
unsigned int sub_op:8;
|
||||
unsigned int reserved_0:11;
|
||||
unsigned int broadcast:1;
|
||||
unsigned int reserved_1:4;
|
||||
};
|
||||
unsigned int DW_0_DATA;
|
||||
} HEADER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int count:22;
|
||||
unsigned int reserved_0:10;
|
||||
};
|
||||
unsigned int DW_1_DATA;
|
||||
} COUNT_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int reserved_0:16;
|
||||
unsigned int dst_sw:2;
|
||||
unsigned int reserved_1:4;
|
||||
unsigned int dst_ha:1;
|
||||
unsigned int reserved_2:1;
|
||||
unsigned int src_sw:2;
|
||||
unsigned int reserved_3:4;
|
||||
unsigned int src_ha:1;
|
||||
unsigned int reserved_4:1;
|
||||
};
|
||||
unsigned int DW_2_DATA;
|
||||
} PARAMETER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int src_addr_31_0:32;
|
||||
};
|
||||
unsigned int DW_3_DATA;
|
||||
} SRC_ADDR_LO_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int src_addr_63_32:32;
|
||||
};
|
||||
unsigned int DW_4_DATA;
|
||||
} SRC_ADDR_HI_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_31_0:32;
|
||||
};
|
||||
unsigned int DW_5_DATA;
|
||||
} DST_ADDR_LO_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_63_32:32;
|
||||
};
|
||||
unsigned int DW_6_DATA;
|
||||
} DST_ADDR_HI_UNION;
|
||||
} SDMA_PKT_COPY_LINEAR, *PSDMA_PKT_COPY_LINEAR;
|
||||
|
||||
/*
|
||||
** Definitions for SDMA_PKT_WRITE_UNTILED packet
|
||||
*/
|
||||
|
||||
typedef struct SDMA_PKT_WRITE_UNTILED_TAG
|
||||
{
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int op:8;
|
||||
unsigned int sub_op:8;
|
||||
unsigned int reserved_0:16;
|
||||
};
|
||||
unsigned int DW_0_DATA;
|
||||
} HEADER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_31_0:32;
|
||||
};
|
||||
unsigned int DW_1_DATA;
|
||||
} DST_ADDR_LO_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_63_32:32;
|
||||
};
|
||||
unsigned int DW_2_DATA;
|
||||
} DST_ADDR_HI_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int count:22;
|
||||
unsigned int reserved_0:2;
|
||||
unsigned int sw:2;
|
||||
unsigned int reserved_1:6;
|
||||
};
|
||||
unsigned int DW_3_DATA;
|
||||
} DW_3_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int data0:32;
|
||||
};
|
||||
unsigned int DW_4_DATA;
|
||||
} DATA0_UNION;
|
||||
} SDMA_PKT_WRITE_UNTILED, *PSDMA_PKT_WRITE_UNTILED;
|
||||
|
||||
/*
|
||||
** Definitions for SDMA_PKT_FENCE packet
|
||||
*/
|
||||
|
||||
typedef struct SDMA_PKT_FENCE_TAG
|
||||
{
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int op:8;
|
||||
unsigned int sub_op:8;
|
||||
unsigned int reserved_0:16;
|
||||
};
|
||||
unsigned int DW_0_DATA;
|
||||
} HEADER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int addr_31_0:32;
|
||||
};
|
||||
unsigned int DW_1_DATA;
|
||||
} ADDR_LO_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int addr_63_32:32;
|
||||
};
|
||||
unsigned int DW_2_DATA;
|
||||
} ADDR_HI_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int data:32;
|
||||
};
|
||||
unsigned int DW_3_DATA;
|
||||
} DATA_UNION;
|
||||
} SDMA_PKT_FENCE, *PSDMA_PKT_FENCE;
|
||||
|
||||
/*
|
||||
** Definitions for SDMA_PKT_CONSTANT_FILL packet
|
||||
*/
|
||||
|
||||
typedef struct SDMA_PKT_CONSTANT_FILL_TAG
|
||||
{
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int op:8;
|
||||
unsigned int sub_op:8;
|
||||
unsigned int sw:2;
|
||||
unsigned int reserved_0:12;
|
||||
unsigned int fillsize:2;
|
||||
};
|
||||
unsigned int DW_0_DATA;
|
||||
} HEADER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_31_0:32;
|
||||
};
|
||||
unsigned int DW_1_DATA;
|
||||
} DST_ADDR_LO_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int dst_addr_63_32:32;
|
||||
};
|
||||
unsigned int DW_2_DATA;
|
||||
} DST_ADDR_HI_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int src_data_31_0:32;
|
||||
};
|
||||
unsigned int DW_3_DATA;
|
||||
} DATA_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int count:22;
|
||||
unsigned int reserved_0:10;
|
||||
};
|
||||
unsigned int DW_4_DATA;
|
||||
} COUNT_UNION;
|
||||
} SDMA_PKT_CONSTANT_FILL, *PSDMA_PKT_CONSTANT_FILL;
|
||||
|
||||
/*
|
||||
** Definitions for SDMA_PKT_TRAP packet
|
||||
*/
|
||||
|
||||
typedef struct SDMA_PKT_TRAP_TAG
|
||||
{
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int op:8;
|
||||
unsigned int sub_op:8;
|
||||
unsigned int reserved_0:16;
|
||||
};
|
||||
unsigned int DW_0_DATA;
|
||||
} HEADER_UNION;
|
||||
|
||||
union
|
||||
{
|
||||
struct
|
||||
{
|
||||
unsigned int int_context:28;
|
||||
unsigned int reserved_0:4;
|
||||
};
|
||||
unsigned int DW_1_DATA;
|
||||
} INT_CONTEXT_UNION;
|
||||
} SDMA_PKT_TRAP, *PSDMA_PKT_TRAP;
|
||||
|
||||
|
||||
#endif // __SDMA_PKT_STRUCT_H__
|
||||
@@ -0,0 +1,142 @@
|
||||
# Permanent exclusions
|
||||
# These tests are included for debugging, but are not executed in normal execution on any ASIC
|
||||
# CU Masking Linear/Split are not working correctly due to how the HW distributes work over CUs.
|
||||
# They are available for testing but are not currently expected to pass on CI/VI/AI
|
||||
PERMANENT_BLACKLIST_ALL_ASICS=\
|
||||
"-KFDEventTest.MeasureInterruptConsumption:"\
|
||||
"KFDQMTest.BasicCuMaskingLinear:"\
|
||||
"RDMATest.GPUDirect"
|
||||
|
||||
# This is the temporary blacklist for all ASICs. This is to be used when a test is failing consistently
|
||||
# on every ASIC (Kaveri, Carrizo, Hawaii, Tonga, Fiji, Polaris10, Polaris11 and Vega10 .
|
||||
# TODO means that a JIRA ticket needs to be created for this issue, as no documentation regarding
|
||||
# failures can be found
|
||||
# NOTE: If you update this alphabetical listing, add the corresponding JIRA ticket for reference
|
||||
#
|
||||
# KFDGraphicsInterop.RegisterForeignDeviceMem (KFD-366)
|
||||
# KFDPMTest.SuspendWith[ActiveProcess|IdleQueue|IdleQueueAfterWork] (KFD-326|327|328)
|
||||
# KFDPNPTest.DisableAndCreateQueue (KFD-329)
|
||||
# KFDQMTest.GPUDoorbellWrite fails intermittently (KFD-318)
|
||||
# KFDQMTest.mGPUShareBO (KFD-334)
|
||||
TEMPORARY_BLACKLIST_ALL_ASICS=\
|
||||
"KFDGraphicsInterop.RegisterForeignDeviceMem:"\
|
||||
"KFDPMTest.SuspendWithActiveProcess:"\
|
||||
"KFDPMTest.SuspendWithIdleQueue:"\
|
||||
"KFDPMTest.SuspendWithIdleQueueAfterWork:"\
|
||||
"KFDPNPTest.DisableAndCreateQueue:"\
|
||||
"KFDQMTest.GPUDoorbellWrite:"\
|
||||
"KFDQMTest.mGPUShareBO"
|
||||
|
||||
BLACKLIST_ALL_ASICS=\
|
||||
"$PERMANENT_BLACKLIST_ALL_ASICS:"\
|
||||
"$TEMPORARY_BLACKLIST_ALL_ASICS"
|
||||
|
||||
# SDMA-based tests (KFDIPCTest.BasicTest, KFDQM.*Sdma*, KFDMemoryTest.MMBench) are all
|
||||
# disabled on non-Hawaii due to SDMA instability - SWDEV-101666
|
||||
SDMA_BLACKLIST=\
|
||||
"KFDIPCTest.*:"\
|
||||
"KFDMemoryTest.MMBench:"\
|
||||
"KFDQMTest.*Sdma*:"\
|
||||
"KFDQMTest.P2PTest"
|
||||
|
||||
# Anything involving CP queue creation is failing on Kaveri. Separate them here for convenience (KFD-336)
|
||||
KV_QUEUE_BLACKLIST=\
|
||||
"KFDExceptionTest.InvalidBadAddress:"\
|
||||
"KFDExceptionTest.InvalidWriteAddress:"\
|
||||
"KFDExceptionTest.InvalidPPR*:"\
|
||||
"KFDLocalMemoryTest.*:"\
|
||||
"KFDEventTest.Signal*Event*:"\
|
||||
"KFDQMTest.CreateQueueStressSingleThreaded:"\
|
||||
"KFDQMTest.*CpQueue*:"\
|
||||
"KFDQMTest.*Dispatch*:"\
|
||||
"KFDQMTest.Atomics:"\
|
||||
"KFDQMTest.GPUDoorbellWrite"
|
||||
|
||||
# KFDQMTest.CpuWriteCoherence fails. 0 dwordsAvailable (KFD-338)
|
||||
# KFDMemoryTest.MemoryRegister fails on SDMA queue creation (KFD-337)
|
||||
KV_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"$SDMA_BLACKLIST:"\
|
||||
"$KV_QUEUE_BLACKLIST:"\
|
||||
"KFDMemoryTest.MemoryRegister:"\
|
||||
"KFDQMTest.CpuWriteCoherence"
|
||||
|
||||
# KFDLocalMemoryTest.BasicTest is failing intermittently (KFD-368)
|
||||
# KFDMemoryTest.BigBufferStressTest was failing intermittently on 4.9 and hangs when executed twice (KFD-312)
|
||||
# KFDQMTest.GPUDoorbellWrite fails on Hawaii. Could be HW-related (KFD-342)
|
||||
HI_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDLocalMemoryTest.BasicTest:"\
|
||||
"KFDMemoryTest.BigBufferStressTest:"\
|
||||
"KFDQMTest.GPUDoorbellWrite"
|
||||
|
||||
CZ_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"$SDMA_BLACKLIST:"\
|
||||
"KFDExceptionTest.InvalidWriteAddress"
|
||||
|
||||
# KFDPerfCountersTest.*Trace fail (KFD-339)
|
||||
# KFDMemoryTest.QueryPointerInfo/MemoryRegister* (KFD-341)
|
||||
# The remaining tests listed here fail on map memory to GPU with a VA conflict (KFD-340)
|
||||
TONGA_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"$SDMA_BLACKLIST:"\
|
||||
"KFDCWSRTest.BasicTest:"\
|
||||
"KFDEventTest.*:"\
|
||||
"KFDLocalMemoryTest.*:"\
|
||||
"KFDMemoryTest.FlatScratchAccess:"\
|
||||
"KFDMemoryTest.MapMemoryToGPU:"\
|
||||
"KFDMemoryTest.MemoryRegister*:"\
|
||||
"KFDMemoryTest.QueryPointerInfo:"\
|
||||
"KFDPerfCountersTest.*:"\
|
||||
"KFDDBGTest.BasicAddressWatch:"\
|
||||
"KFDQMTest.*"
|
||||
|
||||
# Fragmentation test intermittently failing on 4096 order 3 blocks. Investigating in conjunction with KFD-344
|
||||
FIJI_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDLocalMemoryTest.Fragmentation:"\
|
||||
"$SDMA_BLACKLIST"
|
||||
|
||||
ELLESMERE_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"$SDMA_BLACKLIST"
|
||||
|
||||
# Fragmentation test failing on 4096 order 3 blocks. Investigating in conjunction with KFD-344
|
||||
BAFFIN_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDLocalMemoryTest.Fragmentation:"\
|
||||
"$SDMA_BLACKLIST"
|
||||
|
||||
# KFDDBG.BasicAddressWatch fails with message "E,INTERR: Setting ASIC VI (was previously set to GFX9), this changes the backend after we have already started parsing the shader, not currently supported by sp3, sorry." (KFD-317)
|
||||
# KFDExceptionTest.InvalidBadAddress causes some following tests to fail on SRIOV (KFD-343)
|
||||
# KFDLocalMemoryTest.Fragmentation is still flaking out intermittently (KFD-344)
|
||||
# KFDQMTest.BasicCuMaskingEven fails intermittently (WIP)
|
||||
# KFDExceptionTest.InvalidWriteAddress is failing once we enable no-retry (KFD-380)
|
||||
VEGA10_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDDBGTest.BasicAddressWatch:"\
|
||||
"KFDExceptionTest.InvalidBadAddress:"\
|
||||
"KFDExceptionTest.InvalidWriteAddress:"\
|
||||
"KFDQMTest.CreateQueueStressSingleThreaded:"\
|
||||
"KFDQMTest.GPUDoorbellWrite:"\
|
||||
"KFDMemoryTest.MemoryRegister:"\
|
||||
"KFDLocalMemoryTest.Fragmentation"
|
||||
|
||||
VEGA20_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDDBGTest.BasicAddressWatch:"\
|
||||
"KFDExceptionTest.InvalidBadAddress:"\
|
||||
"KFDExceptionTest.InvalidWriteAddress:"\
|
||||
"KFDQMTest.CreateQueueStressSingleThreaded:"\
|
||||
"KFDQMTest.GPUDoorbellWrite:"\
|
||||
"KFDMemoryTest.MemoryRegister:"\
|
||||
"KFDLocalMemoryTest.Fragmentation"
|
||||
|
||||
|
||||
RAVEN_TESTS_BLACKLIST=\
|
||||
"$BLACKLIST_ALL_ASICS:"\
|
||||
"KFDDBGTest.BasicAddressWatch:"\
|
||||
"KFDQMTest.CreateQueueStressSingleThreaded:"\
|
||||
"KFDQMTest.GPUDoorbellWrite:"\
|
||||
"KFDMemoryTest.MemoryRegister"
|
||||
@@ -0,0 +1,6 @@
|
||||
Note: This folder is primarily intended for AMD internal developers.
|
||||
|
||||
The folder lib_helper contains the script to generate SP3 library libamdsp3.a
|
||||
and the associated header files in the current folder for kfdtest to use.
|
||||
cmake is required for the script to run. Just run ./build_sp3.sh after setting
|
||||
up the environment variables (source build/envsetup.sh).
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,75 @@
|
||||
#
|
||||
# Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
|
||||
|
||||
project(amdsp3)
|
||||
|
||||
#set ( CMAKE_VERBOSE_MAKEFILE on )
|
||||
|
||||
find_package(PkgConfig)
|
||||
|
||||
set ( P4_PATH $ENV{WORK_ROOT}/p4/driver/drivers )
|
||||
|
||||
set ( SCLIB_SRC ${PROJECT_SOURCE_DIR} )
|
||||
#if( DEFINED ENV{SCLIB_SRC} )
|
||||
# set ( SCLIB_SRC $ENV{SCLIB_SRC} )
|
||||
#else()
|
||||
# set ( SCLIB_SRC ${P4_PATH}/sc/Chip )
|
||||
#endif()
|
||||
|
||||
include_directories(${SCLIB_SRC}/sp3)
|
||||
include_directories(${SCLIB_SRC}/sp3/release_headers)
|
||||
include_directories(${SCLIB_SRC}/sp3/gen)
|
||||
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-asic.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-dispatch.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-eval.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-gc.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-int.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-lib.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-native.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-cipher.c )
|
||||
set ( SRC_FILES ${SRC_FILES} ${SCLIB_SRC}/sp3/sp3-vm.c )
|
||||
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/gen SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/si SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/ci SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/gfx8 SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/gfx81 SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/gfx9 SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/release_headers/gfx81 SRC_FILES)
|
||||
aux_source_directory(${SCLIB_SRC}/sp3/release_headers/gfx9 SRC_FILES)
|
||||
|
||||
|
||||
message( STATUS "PROJECT_SOURCE_DIR:" ${PROJECT_SOURCE_DIR} )
|
||||
#message( STATUS "SRC_FILES: ")
|
||||
#foreach(file ${SRC_FILES})
|
||||
# message(STATUS "${file}")
|
||||
#endforeach()
|
||||
|
||||
set ( CMAKE_C_FLAGS "-DSP3_STATIC_LIB -Wno-error -DPUBLIC_RELEASE -DLITTLEENDIAN_CPU" )
|
||||
|
||||
add_library(amdsp3 ${SRC_FILES})
|
||||
|
||||
|
||||
Executable
+57
@@ -0,0 +1,57 @@
|
||||
#
|
||||
# Copyright (C) 2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
#
|
||||
# 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.
|
||||
#
|
||||
#
|
||||
|
||||
#!/bin/bash
|
||||
|
||||
if [ "$KFDTEST_ROOT" == "" ] || [ "$P4_ROOT" == "" ]; then
|
||||
echo "Environment variables should be set before running this script"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
cd $KFDTEST_ROOT/sp3/lib_helper
|
||||
|
||||
SP3_PROJECT=$P4_ROOT/driver/drivers/sc/Chip/
|
||||
LIB_OUTPUT=$KFDTEST_ROOT/sp3/
|
||||
|
||||
cp CMakeLists_sp3.txt $SP3_PROJECT/CMakeLists.txt
|
||||
|
||||
mkdir -p build
|
||||
echo "Building SP3 lib"
|
||||
pushd build
|
||||
cmake $SP3_PROJECT/
|
||||
make
|
||||
popd
|
||||
|
||||
rsync --progress -a build/libamdsp3.a $LIB_OUTPUT
|
||||
# Put the intermediate header files in the current folder for further processing
|
||||
rsync --progress -a $SP3_PROJECT/sp3/sp3.h .
|
||||
|
||||
# Remove the build folder and CMakeLists.txt put into SP source folder
|
||||
rm -r build
|
||||
rm $SP3_PROJECT/CMakeLists.txt
|
||||
|
||||
# Replace the license statement in the header files
|
||||
{ cat AMD_opensource_license.txt; sed -e '1,/#ifndef/ { /#ifndef/b; d }' sp3.h; } > $LIB_OUTPUT/sp3.h
|
||||
|
||||
# Delete the intermediate header files
|
||||
rm sp3.h
|
||||
@@ -0,0 +1,590 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __SP3_H__
|
||||
#define __SP3_H__
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
|
||||
/// @file sp3.h
|
||||
/// @brief sp3 API
|
||||
#include <stdint.h>
|
||||
|
||||
// Export tags
|
||||
#define SP3_EXPORT
|
||||
|
||||
|
||||
/// @defgroup sp3main SP3 Main API
|
||||
///
|
||||
/// Main API to assemble and disassemble SP3 shaders.
|
||||
///
|
||||
/// @{
|
||||
|
||||
|
||||
/// Valid shader stages.
|
||||
enum sp3_shtype {
|
||||
SP3_SHTYPE_NONE = -1,
|
||||
SP3_SHTYPE_PS = 0,
|
||||
SP3_SHTYPE_VS = 1,
|
||||
SP3_SHTYPE_GS = 2,
|
||||
SP3_SHTYPE_ES = 3,
|
||||
SP3_SHTYPE_HS = 4,
|
||||
SP3_SHTYPE_LS = 5,
|
||||
SP3_SHTYPE_CS = 6,
|
||||
SP3_SHTYPE_ACV = 7,
|
||||
};
|
||||
|
||||
/// Assorted constants used by sp3 API.
|
||||
enum sp3_count {
|
||||
SP3_NUM_MRT = 8, ///< Maximum number of render targets supported.
|
||||
SP3_NUM_STRM = 4, ///< Maximum number of streams supported.
|
||||
};
|
||||
|
||||
/// Disassembly flags. Bitwise-OR flags to set options.
|
||||
enum sp3_flag {
|
||||
SP3DIS_NO_STATE = 0x01, ///< Do not include state header at top of shader.
|
||||
SP3DIS_NO_BINARY = 0x02, ///< Do not include comments with raw binary microcode.
|
||||
SP3DIS_COMMENTS = 0x04, ///< Do not include comments.
|
||||
SP3DIS_NO_GPR_COUNT = 0x08, ///< Do not include GPR allocation counts.
|
||||
SP3DIS_FORCEVALID = 0x10, ///< Force all bytes of microcode to be disassembled.
|
||||
SP3DIS_NO_ASIC = 0x20, ///< Do not emit the asic header at top of shader.
|
||||
};
|
||||
|
||||
/// Shader context. Contains no user-visible fields.
|
||||
struct sp3_context;
|
||||
|
||||
/// Memory object. Contains no user-visible fields.
|
||||
struct sp3_vma;
|
||||
|
||||
/// VM addresses are 64-bit and the address unit is 32 bits
|
||||
typedef uint64_t sp3_vmaddr;
|
||||
|
||||
/// Storage entry for register streams.
|
||||
struct sp3_reg {
|
||||
uint32_t index; ///< One of the MM aperture register addresses.
|
||||
uint32_t value; ///< 32-bit register data.
|
||||
};
|
||||
|
||||
/// Bits for a single instruction.
|
||||
struct sp3_inst_bits {
|
||||
uint32_t val[5]; ///< Largest single instruction in any backend is 5 dwords.
|
||||
};
|
||||
|
||||
/// Wrapped shader metadata.
|
||||
///
|
||||
/// After generation, shaders are encapsulated in sp3_shader structures.
|
||||
///
|
||||
/// Those structures contain the shader binary, its register stream, constants and constant
|
||||
/// buffers and metadata needed for SC compatibility.
|
||||
///
|
||||
struct sp3_shader {
|
||||
enum sp3_shtype type; ///< One of the SHTYPE_* constants.
|
||||
uint32_t asic_int; ///< Internal ASIC index. Do not use.
|
||||
char asic[0x100]; ///< ASIC name as a string ("RV870" etc).
|
||||
uint32_t size; ///< Size of the compiled shader, in 32-bit words.
|
||||
uint32_t nsgprs; ///< Number of scalar GPRs used.
|
||||
uint32_t nvgprs; ///< Number of vector GPRs used.
|
||||
uint32_t nsvgprs; ///< Number of shared vector GPRs used.
|
||||
uint32_t nsgprs_manual_alloc;
|
||||
uint32_t nvgprs_manual_alloc;
|
||||
uint32_t nsvgprs_manual_alloc;
|
||||
uint32_t trap_present;
|
||||
uint32_t user_sgpr_count;
|
||||
uint32_t scratch_en;
|
||||
uint32_t dispatch_draw_en;
|
||||
uint32_t so_en;
|
||||
uint32_t so_base0_en;
|
||||
uint32_t so_base1_en;
|
||||
uint32_t so_base2_en;
|
||||
uint32_t so_base3_en;
|
||||
uint32_t oc_lds_en;
|
||||
uint32_t tg_size_en;
|
||||
uint32_t tidig_comp_cnt; ///< Number of components(-1) enabled for thread id in group
|
||||
uint32_t tgid_x_en;
|
||||
uint32_t tgid_y_en;
|
||||
uint32_t tgid_z_en;
|
||||
uint32_t wave_cnt_en;
|
||||
uint32_t primgen_en;
|
||||
uint32_t pc_base_en;
|
||||
uint32_t sgpr_scratch;
|
||||
uint32_t sgpr_psvs_state;
|
||||
uint32_t sgpr_gs2vs_offset;
|
||||
uint32_t sgpr_so_write_index;
|
||||
uint32_t sgpr_so_base_offset0;
|
||||
uint32_t sgpr_so_base_offset1;
|
||||
uint32_t sgpr_so_base_offset2;
|
||||
uint32_t sgpr_so_base_offset3;
|
||||
uint32_t sgpr_offchip_lds;
|
||||
uint32_t sgpr_is_offchip;
|
||||
uint32_t sgpr_ring_offset;
|
||||
uint32_t sgpr_gs_wave_id;
|
||||
uint32_t sgpr_global_wave_id;
|
||||
uint32_t sgpr_tg_size;
|
||||
uint32_t sgpr_tgid_x;
|
||||
uint32_t sgpr_tgid_y;
|
||||
uint32_t sgpr_tgid_z;
|
||||
uint32_t sgpr_tf_base;
|
||||
uint32_t sgpr_pc_base;
|
||||
uint32_t sgpr_wave_cnt;
|
||||
uint32_t wave_size; ///< Number of threads in a wavefront (only certain ASICs; 0 = don't care).
|
||||
uint32_t pc_exports; ///< Range of parameters exported (if VS).
|
||||
uint32_t pos_export; ///< Shader executes a position export (if VS).
|
||||
uint32_t cb_exports; ///< Range of MRTs exported (if PS).
|
||||
uint32_t mrtz_export_format;///< Export format of the mrtz export.
|
||||
uint32_t z_export; ///< Shader executes a Z export (if PS).
|
||||
uint32_t pops_en; ///< Shader is POPS (PS)
|
||||
uint32_t pops_num_samples; ///< (PS)
|
||||
uint32_t load_collision_waveid; ///< Shader sets load collision waveid (if PS).
|
||||
uint32_t load_intrawave_collision; ///< Shader is in intrawave mode (if PS).
|
||||
uint32_t stencil_test_export; ///< Shader exports stencil (if PS).
|
||||
uint32_t stencil_op_export; ///< Shader exports stencil (if PS).
|
||||
uint32_t kill_used; ///< Shader executes ALU KILL operations.
|
||||
uint32_t cb_masks[SP3_NUM_MRT]; ///< Component masks for each MRT exported (if PS).
|
||||
uint32_t emit_used; ///< EMIT opcodes used (if GS).
|
||||
uint32_t covmask_export; ///< Shader exports coverage mask (if PS).
|
||||
uint32_t mask_export; ///< Shader exports mask (if PS).
|
||||
uint32_t strm_used[SP3_NUM_STRM]; ///< Streamout operations used (map).
|
||||
uint32_t scratch_used; ///< Scratch SMX exports used.
|
||||
uint32_t scratch_itemsize; ///< Scratch ring item size.
|
||||
uint32_t reduction_used; ///< Reduction SMX exports used.
|
||||
uint32_t ring_used; ///< ESGS/GSVS ring SMX exports used.
|
||||
uint32_t ring_itemsize; ///< ESGS/GSVS ring item size (for ES/GS respectively).
|
||||
uint32_t vertex_size[4]; ///< GSVS ring vertex size (for GS).
|
||||
uint32_t mem_used; ///< Raw memory SMX exports used.
|
||||
uint32_t rats_used; ///< Mask of RATs (UAVs) used
|
||||
uint32_t group_size[3]; ///< Wavefront group size (for ELF files).
|
||||
uint32_t alloc_lds; ///< Number of LDS bytes allocated for wave group. (translates to lds_size in CS and LS)
|
||||
uint32_t *data; ///< Shader binary data.
|
||||
uint32_t nregs; ///< Number of register writes in the stream.
|
||||
uint64_t crc64; ///< CRC64 of compiled shader, may be used for identification/fingerprinting.
|
||||
uint32_t crc32; ///< 32-bit CRC of compiled shader (based on crc64), may be used for identification/fingerprinting.
|
||||
struct sp3_reg *regs; ///< Register writes (index-value pairs).
|
||||
struct sp3_shader *merged_2nd_shader; ///< Merged es/gs, ls/hs shader, this points to start of the second shader (only certain ASICs).
|
||||
};
|
||||
|
||||
/// Comment callback.
|
||||
typedef const char *(*sp3_comment_cb)(void *, int);
|
||||
|
||||
|
||||
/// Get version of the sp3 library.
|
||||
///
|
||||
/// @return String containing the version number.
|
||||
///
|
||||
SP3_EXPORT const char *sp3_version(void);
|
||||
|
||||
/// Create a new sp3 context.
|
||||
///
|
||||
/// @return A new context for use in assembling and disassembling shaders. Free with sp3_close().
|
||||
///
|
||||
SP3_EXPORT struct sp3_context *sp3_new(void);
|
||||
|
||||
/// Set option for sp3.
|
||||
///
|
||||
/// @param state sp3 context.
|
||||
/// @param option Option name. Unknown options will raise an error.
|
||||
/// @param value Option value. NULL is used to represent value-less options.
|
||||
///
|
||||
/// Currently supported options:
|
||||
///
|
||||
/// Werror (boolean) -- indicates whether warnings should be treated as errors.
|
||||
///
|
||||
/// wave_size (integer) -- sets the wave size being used by the draw calls that will be using
|
||||
/// this shader. Ignored in certain ASICs. You may set this to 32, 64 or the special value 0
|
||||
/// to indicate no preference on wave size. The shader will be checked to ensure it is
|
||||
/// compatible with the size specified here.
|
||||
///
|
||||
/// omit_version (boolean) -- omit generation of the S_VERSION opcode.
|
||||
///
|
||||
/// omit_code_end (boolean) -- omit generation of the S_CODE_END footer.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_option(
|
||||
struct sp3_context *state,
|
||||
const char *option,
|
||||
const char *value);
|
||||
|
||||
/// Parse a file into a context.
|
||||
///
|
||||
/// Use sp3_compile to generate binary microcode after the shader is parsed.
|
||||
///
|
||||
/// @param state Context to use for parsing.
|
||||
/// @param file File to read. If NULL, parse from stdin.
|
||||
///
|
||||
SP3_EXPORT void sp3_parse_file(struct sp3_context *state, const char *file);
|
||||
|
||||
/// Parse a string into a context.
|
||||
///
|
||||
/// Use sp3_compile to generate binary microcode after the shader is parsed.
|
||||
///
|
||||
/// @param state Context to use for parsing.
|
||||
/// @param string String to parse.
|
||||
///
|
||||
SP3_EXPORT void sp3_parse_string(struct sp3_context *state, const char *string);
|
||||
|
||||
/// Parse a file from the standard library into a context.
|
||||
///
|
||||
/// Use sp3_compile to generate binary microcode after the shader is parsed.
|
||||
///
|
||||
/// @param state Context to use for parsing.
|
||||
/// @param name Path to the standard library; files in this directory are parsed.
|
||||
///
|
||||
SP3_EXPORT void sp3_parse_library(struct sp3_context *state, const char *name);
|
||||
|
||||
/// Call a sp3 function.
|
||||
///
|
||||
SP3_EXPORT void sp3_call(struct sp3_context *state, const char *func);
|
||||
|
||||
/// Compile a shader program that has been parsed into the context.
|
||||
///
|
||||
/// @param state sp3 context.
|
||||
/// @param cffunc Name of clause to call. By convention, this is "main".
|
||||
/// @return A compiled and linked shader. Free memory with sp3_free_shader().
|
||||
///
|
||||
SP3_EXPORT struct sp3_shader *sp3_compile(
|
||||
struct sp3_context *state,
|
||||
const char *cffunc);
|
||||
|
||||
/// Free a sp3_shader.
|
||||
///
|
||||
/// @param sh Shader object to delete.
|
||||
///
|
||||
SP3_EXPORT void sp3_free_shader(struct sp3_shader *sh);
|
||||
|
||||
/// Get current ASIC name set for a context.
|
||||
///
|
||||
/// @param state Context to query.
|
||||
/// @return Name of ASIC.
|
||||
///
|
||||
SP3_EXPORT const char *sp3_getasic(struct sp3_context *state);
|
||||
|
||||
/// Set current ASIC name for a context.
|
||||
///
|
||||
/// @param state Context to modify.
|
||||
/// @param chip Case-insensitive string representing the ASIC to compile or disassemble for.
|
||||
///
|
||||
SP3_EXPORT void sp3_setasic(struct sp3_context *state, const char *chip);
|
||||
|
||||
/// Set global variable in context to an integer.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_param_int(
|
||||
struct sp3_context *state,
|
||||
const char *name,
|
||||
int32_t value);
|
||||
|
||||
/// Set global variable in context to an integer vector.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_param_intvec(
|
||||
struct sp3_context *state,
|
||||
const char *name,
|
||||
uint32_t size,
|
||||
const int32_t *value);
|
||||
|
||||
/// Set global variable in context to a float.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_param_float(
|
||||
struct sp3_context *state,
|
||||
const char *name,
|
||||
float value);
|
||||
|
||||
/// Set global variable in context to a float vector.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_param_floatvec(
|
||||
struct sp3_context *state,
|
||||
const char *name,
|
||||
uint32_t size,
|
||||
const float *value);
|
||||
|
||||
/// Set error message header.
|
||||
///
|
||||
/// @param state Context to modify.
|
||||
/// @param str Text to include in error message header.
|
||||
///
|
||||
SP3_EXPORT void sp3_set_error_header(struct sp3_context *state, const char *str);
|
||||
|
||||
/// Get ASIC metrics for the ASIC in current state.
|
||||
///
|
||||
/// Used by ELF tools to fill in some CAL fields.
|
||||
///
|
||||
/// @param state Context to query.
|
||||
/// @param name Name of ASIC metric.
|
||||
/// @return Value of ASIC metric.
|
||||
///
|
||||
SP3_EXPORT int sp3_asicinfo(struct sp3_context *state, const char *name);
|
||||
|
||||
/// Free a context allocated by sp3_new/open/parse.
|
||||
///
|
||||
/// @param state Context to delete.
|
||||
///
|
||||
SP3_EXPORT void sp3_close(struct sp3_context *state);
|
||||
|
||||
/// Disassemble a shader.
|
||||
///
|
||||
/// This call is likely to change to something that will take a filled sp3_shader structure
|
||||
/// later on.
|
||||
///
|
||||
/// @param state sp3 context (use sp3_new to allocate and sp3_setasic to set ASIC).
|
||||
/// @param bin Memory map with the opcodes (see sp3-vm.h).
|
||||
/// @param base Start of the shader in the memory map (in VM entries, i.e. 32-bit words).
|
||||
/// @param name Same to give the disassembled shader.
|
||||
/// @param shader_type One of the SHTYPE_* constants.
|
||||
/// @param include Literal text to include in the CF clause (NULL includes nothing).
|
||||
/// @param max_len Maximum length of CF clause. Matters if SP3DIS_FORCEVALID is set.
|
||||
/// @param flags A bitmask of SP3DIS_* flags.
|
||||
///
|
||||
/// @return Shader disassembly as a string. Free memory with sp3_free().
|
||||
///
|
||||
SP3_EXPORT char *sp3_disasm(
|
||||
struct sp3_context *state,
|
||||
struct sp3_vma *bin,
|
||||
sp3_vmaddr base,
|
||||
const char *name,
|
||||
enum sp3_shtype shader_type,
|
||||
const char *include,
|
||||
uint32_t max_len,
|
||||
uint32_t flags);
|
||||
|
||||
/// Disassemble a single shader instruction.
|
||||
///
|
||||
/// This call is likely to change to something that will take a filled sp3_shader structure
|
||||
/// later on.
|
||||
///
|
||||
/// @param state sp3 context (use sp3_new to allocate and sp3_setasic to set ASIC).
|
||||
/// @param inst Pointer to dwords containing instruction (exact number of dwords required depends on instruction).
|
||||
/// @param base Start of the shader in the memory map (in VM entries, i.e. 32-bit words).
|
||||
/// @param addr Address of the instruction being disassembled (in VM entries, i.e. 32-bit words).
|
||||
/// @param shader_type One of the SHTYPE_* constants.
|
||||
/// @param flags A mask of SP3DIS_* flags.
|
||||
///
|
||||
/// @return Shader disassembly as a string. Free memory with sp3_free().
|
||||
///
|
||||
SP3_EXPORT char *sp3_disasm_inst(
|
||||
struct sp3_context *state,
|
||||
const struct sp3_inst_bits *inst,
|
||||
sp3_vmaddr base,
|
||||
sp3_vmaddr addr,
|
||||
enum sp3_shtype shader_type,
|
||||
uint32_t flags);
|
||||
|
||||
/// Parse a register stream.
|
||||
///
|
||||
/// Can be called before sp3_disasm to preset things like ALU, boolean and loop constants.
|
||||
///
|
||||
/// This call is likely to merge with sp3_disasm later on.
|
||||
///
|
||||
/// @param state sp3 context to fill with state.
|
||||
/// @param nregs Number of register entries.
|
||||
/// @param regs Register stream to parse.
|
||||
/// @param shader_type One of the SHTYPE_* constants.
|
||||
///
|
||||
SP3_EXPORT void sp3_setregs(
|
||||
struct sp3_context *state,
|
||||
uint32_t nregs,
|
||||
const struct sp3_reg *regs,
|
||||
enum sp3_shtype shader_type);
|
||||
|
||||
|
||||
/// Set shader comments
|
||||
///
|
||||
/// @param state sp3 context.
|
||||
/// @param map Map of comments (0 for no comment, other values will be passed to the callback).
|
||||
/// @param f_top Callback returning comment to place above the opcode.
|
||||
/// @param f_right Callback returning comment to place to the right of the opcode.
|
||||
/// @param ctx Void pointer to pass to comment callbacks.
|
||||
///
|
||||
SP3_EXPORT void sp3_setcomments(
|
||||
struct sp3_context *state,
|
||||
struct sp3_vma *map,
|
||||
sp3_comment_cb f_top,
|
||||
sp3_comment_cb f_right,
|
||||
void *ctx);
|
||||
|
||||
/// Set alternate shader entry points
|
||||
///
|
||||
/// Used for disassembly; this marks an additional location in memory
|
||||
/// (besides the start address) where shader code may be found. Generally
|
||||
/// required for jump tables and any case where the shader may perform
|
||||
/// indirect jumps to ensure that disassembly locates all shader
|
||||
/// instructions.
|
||||
///
|
||||
/// @param state sp3 context (use sp3_new to allocate and sp3_setasic to set ASIC).
|
||||
/// @param addr Address of the instruction being disassembled (in VM entries, i.e. 32-bit words).
|
||||
///
|
||||
SP3_EXPORT void sp3_setentrypoint(
|
||||
struct sp3_context *state,
|
||||
sp3_vmaddr addr);
|
||||
|
||||
/// Clear alternate shader entry points.
|
||||
///
|
||||
/// Clear all entry points previously set with sp3_setentrypoint.
|
||||
///
|
||||
/// @param state sp3 context (use sp3_new to allocate and sp3_setasic to set ASIC).
|
||||
///
|
||||
SP3_EXPORT void sp3_clearentrypoints(struct sp3_context *state);
|
||||
|
||||
/// Free memory allocated by sp3.
|
||||
///
|
||||
/// Windows DLLs that allocate memory have to free it. This function
|
||||
/// should be used to free the result of sp3_disasm, sp3_compile etc.
|
||||
///
|
||||
SP3_EXPORT void sp3_free(void *ptr);
|
||||
|
||||
/// SP3 API to merge two shaders given file names as input.
|
||||
///
|
||||
SP3_EXPORT struct sp3_shader* sp3_merge_shaders(
|
||||
struct sp3_context *pointer,
|
||||
const char *first_file,
|
||||
const char *second_file);
|
||||
|
||||
/// SP3 API to merge two shaders given shader strings as input.
|
||||
///
|
||||
SP3_EXPORT struct sp3_shader* sp3_merge_shader_strings(
|
||||
struct sp3_context *pointer,
|
||||
const char *first_string,
|
||||
const char *second_string);
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
/// @defgroup sp3vm SP3 Memory Objects
|
||||
///
|
||||
/// The VM API is used to manage virtual memory maps. Those maps are used for binary storage
|
||||
/// for disassembly, as they can naturally mirror the GPU's memory map (so no register
|
||||
/// translation is needed).
|
||||
///
|
||||
/// @{
|
||||
|
||||
/// Callback function that will fill a VMA on demand
|
||||
///
|
||||
/// The VMA to be filled will be specified through the request address.
|
||||
/// The callback should fill the VMA using sp3_vm_write calls.
|
||||
///
|
||||
typedef void (* sp3_vmfill)(struct sp3_vma *vm, sp3_vmaddr addr, void *ctx);
|
||||
|
||||
/// Create a new VM that is empty.
|
||||
///
|
||||
/// Free the object with sp3_vm_free().
|
||||
///
|
||||
/// @return New VM object.
|
||||
///
|
||||
SP3_EXPORT
|
||||
struct sp3_vma *sp3_vm_new(void);
|
||||
|
||||
/// Create a new VM that has a sp3_vmfill callback.
|
||||
///
|
||||
/// Free the object with sp3_vm_free().
|
||||
///
|
||||
/// @param fill Function used to populate data in VM. The function will be pass the new VM object, the address and a context.
|
||||
/// @param ctx User-specified context. Passed to the fill function and not used by sp3 itself.
|
||||
/// @return New VM object.
|
||||
///
|
||||
SP3_EXPORT
|
||||
struct sp3_vma *sp3_vm_new_fill(sp3_vmfill fill, void *ctx);
|
||||
|
||||
/// Create a new VM from an array of words.
|
||||
///
|
||||
/// Free the object with sp3_vm_free().
|
||||
///
|
||||
/// @param base VM address to load array at.
|
||||
/// @param len Number of 32-bit words in the array.
|
||||
/// @param data Pointer to the array.
|
||||
/// @return New VM object.
|
||||
///
|
||||
SP3_EXPORT
|
||||
struct sp3_vma *sp3_vm_new_ptr(sp3_vmaddr base, sp3_vmaddr len, const uint32_t *data);
|
||||
|
||||
/// Find a VMA, optionally adding it.
|
||||
///
|
||||
/// @param vm VM to search in.
|
||||
/// @param addr Address to search for.
|
||||
/// @param add Flag indicating whether a failure should result in adding a new VMA.
|
||||
/// @return VM object matching the specified address.
|
||||
///
|
||||
SP3_EXPORT
|
||||
struct sp3_vma *sp3_vm_find(struct sp3_vma *vm, sp3_vmaddr addr, uint32_t add);
|
||||
|
||||
/// Write a word to a VM.
|
||||
///
|
||||
/// @param vm VM to write.
|
||||
/// @param addr Address to write.
|
||||
/// @param val 32-bits of data to write.
|
||||
///
|
||||
SP3_EXPORT
|
||||
void sp3_vm_write(struct sp3_vma *vm, sp3_vmaddr addr, uint32_t val);
|
||||
|
||||
/// Read a word from a VM.
|
||||
///
|
||||
/// @param vm VM to read.
|
||||
/// @param addr Address to read.
|
||||
/// @return 32-bits of data at specified address.
|
||||
///
|
||||
SP3_EXPORT
|
||||
uint32_t sp3_vm_read(struct sp3_vma *vm, sp3_vmaddr addr);
|
||||
|
||||
/// Probe VM for presence.
|
||||
///
|
||||
/// @param vm VM to probe.
|
||||
/// @param addr Address to search for.
|
||||
/// @return 1 if the specified address is backed in the VM, 0 otherwise.
|
||||
///
|
||||
SP3_EXPORT
|
||||
int sp3_vm_present(struct sp3_vma *vm, sp3_vmaddr addr);
|
||||
|
||||
/// Return base address of VM.
|
||||
///
|
||||
/// @param vm VM to query.
|
||||
/// @return Base address.
|
||||
///
|
||||
SP3_EXPORT
|
||||
sp3_vmaddr sp3_vm_base(struct sp3_vma *vm);
|
||||
|
||||
/// Return next VM.
|
||||
///
|
||||
/// @param vm VM to query.
|
||||
/// @return Next VM in list.
|
||||
///
|
||||
SP3_EXPORT
|
||||
struct sp3_vma *sp3_vm_next(struct sp3_vma *vm);
|
||||
|
||||
/// Free a VM and all its storage.
|
||||
///
|
||||
/// Use this function to free memory allocated by sp3_vm_new, sp3_vm_new_fill and
|
||||
/// sp3_vm_new_ptr.
|
||||
///
|
||||
/// @param vm VM to free.
|
||||
///
|
||||
SP3_EXPORT
|
||||
void sp3_vm_free(struct sp3_vma *vm);
|
||||
|
||||
|
||||
/// @}
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
#endif /* __SP3_H__ */
|
||||
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "AqlQueue.hpp"
|
||||
#include "GoogleTestExtension.hpp"
|
||||
|
||||
|
||||
AqlQueue::AqlQueue(void) {
|
||||
}
|
||||
|
||||
|
||||
AqlQueue::~AqlQueue(void) {
|
||||
}
|
||||
|
||||
unsigned int AqlQueue::Wptr() {
|
||||
return *m_Resources.Queue_write_ptr;
|
||||
}
|
||||
|
||||
unsigned int AqlQueue::Rptr() {
|
||||
return *m_Resources.Queue_read_ptr;
|
||||
}
|
||||
|
||||
unsigned int AqlQueue::RptrWhenConsumed() {
|
||||
return Wptr();
|
||||
}
|
||||
|
||||
void AqlQueue::SubmitPacket() {
|
||||
// m_pending Wptr is in DWORDs
|
||||
*m_Resources.Queue_write_ptr = m_pendingWptr;
|
||||
*(m_Resources.Queue_DoorBell) = Wptr();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_AQL_QUEUE__H__
|
||||
#define __KFD_AQL_QUEUE__H__
|
||||
|
||||
#include "BaseQueue.hpp"
|
||||
|
||||
class AqlQueue : public BaseQueue {
|
||||
public:
|
||||
AqlQueue();
|
||||
virtual ~AqlQueue();
|
||||
|
||||
// @brief update queue write pointer and sets the queue doorbell to the queue write pointer
|
||||
virtual void SubmitPacket();
|
||||
|
||||
// @ return read pointer are in DWORDs
|
||||
virtual unsigned int Rptr();
|
||||
// @ return write pointer are in DWORDs
|
||||
virtual unsigned int Wptr();
|
||||
// @ return expected m_Resources.Queue_read_ptr when all packets consumed
|
||||
virtual unsigned int RptrWhenConsumed();
|
||||
|
||||
protected:
|
||||
virtual PACKETTYPE PacketTypeSupported() { return PACKETTYPE_AQL; }
|
||||
|
||||
virtual _HSA_QUEUE_TYPE GetQueueType() { return HSA_QUEUE_COMPUTE_AQL; }
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "BasePacket.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
void BasePacket::Dump() const {
|
||||
unsigned int size = SizeInDWords();
|
||||
const HSAuint32 *packet = (const HSAuint32 *)GetPacket();
|
||||
std::ostream &log = LOG();
|
||||
unsigned int i;
|
||||
|
||||
log << "Packet dump:" << std::hex;
|
||||
for (i = 0; i < size; i++)
|
||||
log << " " << std::setw(8) << std::setfill('0') << packet[i];
|
||||
log << std::endl;
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_BASE_PACKET__H__
|
||||
#define __KFD_BASE_PACKET__H__
|
||||
|
||||
/**
|
||||
* all packets profiles must be defined here
|
||||
* every type defined here has sub-types
|
||||
*/
|
||||
enum PACKETTYPE {
|
||||
PACKETTYPE_PM4,
|
||||
PACKETTYPE_SDMA,
|
||||
PACKETTYPE_AQL
|
||||
};
|
||||
|
||||
// @class BasePacket
|
||||
class BasePacket {
|
||||
public:
|
||||
BasePacket(void) {}
|
||||
virtual ~BasePacket(void) {}
|
||||
|
||||
// @returns the packet type
|
||||
virtual PACKETTYPE PacketType() const = 0;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const = 0;
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const = 0;
|
||||
// @returns the packet size in DWORDS
|
||||
unsigned int SizeInDWords() const { return SizeInBytes()/sizeof(unsigned int); }
|
||||
|
||||
void Dump() const;
|
||||
|
||||
protected:
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,200 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "BaseQueue.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "AqlQueue.hpp"
|
||||
#include "hsakmt.h"
|
||||
|
||||
BaseQueue::BaseQueue()
|
||||
:m_Type(HSA_QUEUE_TYPE_SIZE),
|
||||
m_QueueBuf(NULL),
|
||||
m_SkipWaitConsumption(true) {
|
||||
}
|
||||
|
||||
BaseQueue::~BaseQueue(void) {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
HSAKMT_STATUS BaseQueue::Create(unsigned int NodeId, unsigned int size, HSAuint64 *pointers) {
|
||||
HSAKMT_STATUS status;
|
||||
|
||||
if (m_QueueBuf != NULL) {
|
||||
// queue already exist, one queue per object
|
||||
Destroy();
|
||||
}
|
||||
|
||||
memset(&m_Resources, 0, sizeof(m_Resources));
|
||||
|
||||
m_Type = GetQueueType();
|
||||
m_QueueBuf = new HsaMemoryBuffer(size, NodeId, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
|
||||
if (m_Type == HSA_QUEUE_COMPUTE_AQL) {
|
||||
m_Resources.Queue_read_ptr_aql = &pointers[0];
|
||||
m_Resources.Queue_write_ptr_aql = &pointers[1];
|
||||
}
|
||||
|
||||
status = hsaKmtCreateQueue(NodeId,
|
||||
m_Type,
|
||||
DEFAULT_QUEUE_PERCENTAGE,
|
||||
DEFAULT_PRIORITY,
|
||||
m_QueueBuf->As<unsigned int*>(),
|
||||
m_QueueBuf->Size(),
|
||||
NULL,
|
||||
&m_Resources);
|
||||
|
||||
if (status != HSAKMT_STATUS_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
if (m_Resources.Queue_read_ptr == NULL) {
|
||||
WARN() << "CreateQueue: read pointer value should be 0" << std::endl;
|
||||
status = HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
if (m_Resources.Queue_write_ptr == NULL) {
|
||||
WARN() << "CreateQueue: write pointer value should be 0" << std::endl;
|
||||
status = HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
// needs to match the queue write ptr
|
||||
m_pendingWptr = 0;
|
||||
m_pendingWptr64 = 0;
|
||||
m_Node = NodeId;
|
||||
return status;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS BaseQueue::Update(unsigned int percent, HSA_QUEUE_PRIORITY priority, bool nullifyBuffer) {
|
||||
void* pNewBuffer = (nullifyBuffer ? NULL : m_QueueBuf->As<void*>());
|
||||
HSAuint64 newSize = (nullifyBuffer ? 0 : m_QueueBuf->Size());
|
||||
|
||||
return hsaKmtUpdateQueue(m_Resources.QueueId, percent, priority, pNewBuffer, newSize, NULL);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS BaseQueue::SetCUMask(unsigned int *mask, unsigned int mask_count) {
|
||||
return hsaKmtSetQueueCUMask(m_Resources.QueueId, mask_count, mask);
|
||||
}
|
||||
|
||||
HSAKMT_STATUS BaseQueue::Destroy() {
|
||||
HSAKMT_STATUS status = HSAKMT_STATUS_SUCCESS;
|
||||
|
||||
if (m_QueueBuf != NULL) {
|
||||
status = hsaKmtDestroyQueue(m_Resources.QueueId);
|
||||
|
||||
if (status == HSAKMT_STATUS_SUCCESS) {
|
||||
delete m_QueueBuf;
|
||||
m_QueueBuf = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
void BaseQueue::PlaceAndSubmitPacket(const BasePacket &packet) {
|
||||
PlacePacket(packet);
|
||||
SubmitPacket();
|
||||
}
|
||||
|
||||
void BaseQueue::Wait4PacketConsumption() {
|
||||
ASSERT_TRUE(WaitOnValue(m_Resources.Queue_read_ptr, RptrWhenConsumed()));
|
||||
}
|
||||
|
||||
bool BaseQueue::AllPacketsSubmitted() {
|
||||
return Wptr() == Rptr();
|
||||
}
|
||||
|
||||
void BaseQueue::PlacePacket(const BasePacket &packet) {
|
||||
ASSERT_EQ(packet.PacketType(), PacketTypeSupported()) << "Cannot add a packet since packet type doesn't match queue";
|
||||
|
||||
unsigned int readPtr = Rptr();
|
||||
unsigned int writePtr = m_pendingWptr;
|
||||
HSAuint64 writePtr64 = m_pendingWptr64;
|
||||
|
||||
unsigned int packetSizeInDwords = packet.SizeInDWords();
|
||||
unsigned int dwordsRequired = packetSizeInDwords;
|
||||
unsigned int queueSizeInDWord = m_QueueBuf->Size() / sizeof(uint32_t);
|
||||
|
||||
if (writePtr + packetSizeInDwords > queueSizeInDWord) {
|
||||
// wraparound expected. We need enough room to also place NOPs to avoid crossing the buffer end.
|
||||
dwordsRequired += queueSizeInDWord - writePtr;
|
||||
}
|
||||
|
||||
unsigned int dwordsAvailable = (readPtr - 1 - writePtr + queueSizeInDWord) % queueSizeInDWord;
|
||||
ASSERT_GE(dwordsAvailable, dwordsRequired) << "Cannot add a packet, buffer overrun";
|
||||
|
||||
ASSERT_GE(queueSizeInDWord, packetSizeInDwords) << "Cannot add a packet, packet size too large";
|
||||
|
||||
if (writePtr + packetSizeInDwords >= queueSizeInDWord) {
|
||||
// wraparound
|
||||
while (writePtr + packetSizeInDwords > queueSizeInDWord) {
|
||||
m_QueueBuf->As<unsigned int *>()[writePtr] = CMD_NOP;
|
||||
writePtr = (writePtr + 1) % queueSizeInDWord;
|
||||
writePtr64++;
|
||||
}
|
||||
|
||||
// not updating Wptr since we might want to do place packet without submission
|
||||
m_pendingWptr = (writePtr % queueSizeInDWord);
|
||||
m_pendingWptr64 = writePtr64;
|
||||
}
|
||||
|
||||
memcpy(m_pendingWptr + m_QueueBuf->As<unsigned int*>(), packet.GetPacket(), packetSizeInDwords * 4);
|
||||
|
||||
m_pendingWptr = (m_pendingWptr + packetSizeInDwords) % queueSizeInDWord;
|
||||
m_pendingWptr64 += packetSizeInDwords;
|
||||
}
|
||||
|
||||
BaseQueue* QueueArray::GetQueue(unsigned int Node) {
|
||||
// If a queue exists for that node then return, else create one
|
||||
for (unsigned int i = 0; i < m_QueueList.size(); i++) {
|
||||
if (Node == m_QueueList.at(i)->GetNodeId())
|
||||
return m_QueueList.at(i);
|
||||
}
|
||||
|
||||
BaseQueue *pQueue = NULL;
|
||||
|
||||
switch (m_QueueType) {
|
||||
case HSA_QUEUE_COMPUTE:
|
||||
pQueue = new PM4Queue();
|
||||
break;
|
||||
case HSA_QUEUE_SDMA:
|
||||
pQueue = new SDMAQueue();
|
||||
break;
|
||||
case HSA_QUEUE_COMPUTE_AQL:
|
||||
pQueue = new AqlQueue();
|
||||
break;
|
||||
}
|
||||
|
||||
if (pQueue) {
|
||||
pQueue->Create(Node);
|
||||
m_QueueList.push_back(pQueue);
|
||||
}
|
||||
return pQueue;
|
||||
}
|
||||
|
||||
void QueueArray::Destroy() {
|
||||
for (unsigned int i = 0; i < m_QueueList.size(); i++)
|
||||
delete m_QueueList.at(i);
|
||||
|
||||
m_QueueList.clear();
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_BASE_QUEUE__H__
|
||||
#define __KFD_BASE_QUEUE__H__
|
||||
|
||||
#include <vector>
|
||||
#include "KFDTestUtil.hpp"
|
||||
#include "BasePacket.hpp"
|
||||
|
||||
// @class BasePacket
|
||||
class BaseQueue {
|
||||
public:
|
||||
static const unsigned int DEFAULT_QUEUE_SIZE = PAGE_SIZE;
|
||||
static const HSA_QUEUE_PRIORITY DEFAULT_PRIORITY = HSA_QUEUE_PRIORITY_NORMAL;
|
||||
static const unsigned int DEFAULT_QUEUE_PERCENTAGE = 100;
|
||||
static const unsigned int ZERO_QUEUE_PERCENTAGE = 0;
|
||||
static const unsigned int FLUSH_GPU_CACHES_TO = 1000;
|
||||
|
||||
BaseQueue(void);
|
||||
virtual ~BaseQueue(void);
|
||||
|
||||
/** Create the queue.
|
||||
* @see hsaKmtCreateQueue
|
||||
* @param pointers is used only for creating AQL queues. Otherwise it is omitted.
|
||||
*/
|
||||
virtual HSAKMT_STATUS Create(unsigned int NodeId, unsigned int size = DEFAULT_QUEUE_SIZE,
|
||||
HSAuint64 *pointers = NULL);
|
||||
/** Update the queue.
|
||||
* @see hsaKmtUpdateQueue
|
||||
* @param percent the new queue percentage
|
||||
* @param priority the new queue priority
|
||||
* @param nullifyBuffer
|
||||
* if 'true', set the new buffer address to NULL and the size to 0. Otherwise
|
||||
* don't change the queue buffer address/size.
|
||||
*/
|
||||
virtual HSAKMT_STATUS Update(unsigned int percent, HSA_QUEUE_PRIORITY priority, bool nullifyBuffer);
|
||||
virtual HSAKMT_STATUS SetCUMask(unsigned int *mask, unsigned int mask_count);
|
||||
/** Destroy the queue.
|
||||
* @see hsaKmtDestroyQueue
|
||||
*/
|
||||
virtual HSAKMT_STATUS Destroy();
|
||||
/** Wait for all the packets submitted to the queue to be consumed. (i.e. wait until RPTR=WPTR).
|
||||
* Note that all packets being consumed is not the same as all packets being processed.
|
||||
*/
|
||||
virtual void Wait4PacketConsumption();
|
||||
/** @brief place packet and submit it in one go
|
||||
*/
|
||||
virtual void PlaceAndSubmitPacket(const BasePacket &packet);
|
||||
/** @brief copy packet to queue and update write pointer
|
||||
*/
|
||||
virtual void PlacePacket(const BasePacket &packet);
|
||||
/** @brief update queue write pointer and sets the queue doorbell to the queue write pointer
|
||||
*/
|
||||
virtual void SubmitPacket() = 0;
|
||||
/** @brief checkes if all packets in queue already processed
|
||||
* compares queue read and write pointers
|
||||
*/
|
||||
bool AllPacketsSubmitted();
|
||||
|
||||
void SetSkipWaitConsump(int val) { m_SkipWaitConsumption = val; }
|
||||
int GetSkipWaitConsump() { return m_SkipWaitConsumption; }
|
||||
int Size() { return m_QueueBuf->Size(); }
|
||||
|
||||
HsaQueueResource *GetResource() { return &m_Resources; }
|
||||
unsigned int GetPendingWptr() { return m_pendingWptr; }
|
||||
HSAuint64 GetPendingWptr64() { return m_pendingWptr64; }
|
||||
virtual _HSA_QUEUE_TYPE GetQueueType() = 0;
|
||||
unsigned int GetNodeId() { return m_Node; }
|
||||
|
||||
protected:
|
||||
static const unsigned int CMD_NOP_TYPE_2 = 0x80000000;
|
||||
static const unsigned int CMD_NOP_TYPE_3 = 0xFFFF1002;
|
||||
|
||||
unsigned int CMD_NOP;
|
||||
unsigned int m_pendingWptr;
|
||||
HSAuint64 m_pendingWptr64;
|
||||
HSA_QUEUE_TYPE m_Type;
|
||||
HsaQueueResource m_Resources;
|
||||
HsaMemoryBuffer *m_QueueBuf;
|
||||
unsigned int m_Node;
|
||||
|
||||
// @ return write pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Wptr() = 0;
|
||||
// @ return read pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Rptr() = 0;
|
||||
// @ return expected m_Resources.Queue_read_ptr when all packets consumed
|
||||
virtual unsigned int RptrWhenConsumed() = 0;
|
||||
virtual PACKETTYPE PacketTypeSupported() = 0;
|
||||
|
||||
private:
|
||||
// Some tests(such as exception) may not need wait pm4 packet consumption on CZ.
|
||||
int m_SkipWaitConsumption;
|
||||
};
|
||||
|
||||
|
||||
// @class QueueArray
|
||||
// Managed QueueArray for different GPU Nodes
|
||||
class QueueArray {
|
||||
// List of Queues. One for each GPU
|
||||
std::vector<BaseQueue*> m_QueueList;
|
||||
_HSA_QUEUE_TYPE m_QueueType;
|
||||
|
||||
public:
|
||||
QueueArray(_HSA_QUEUE_TYPE type): m_QueueType(type) {}
|
||||
~QueueArray() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
BaseQueue* GetQueue(unsigned int Node);
|
||||
void Destroy();
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
#include "PM4Packet.hpp"
|
||||
|
||||
#include "asic_reg/gfx_7_2_d.h"
|
||||
#include "asic_reg/gfx_7_2_sh_mask.h"
|
||||
|
||||
Dispatch::Dispatch(const HsaMemoryBuffer& isaBuf, const bool eventAutoReset)
|
||||
:m_IsaBuf(isaBuf), m_IndirectBuf(PACKETTYPE_PM4, PAGE_SIZE / sizeof(unsigned int), isaBuf.Node()),
|
||||
m_DimX(1), m_DimY(1), m_DimZ(1), m_pArg1(NULL), m_pArg2(NULL), m_pEop(NULL), m_ScratchEn(false),
|
||||
m_ComputeTmpringSize(0), m_scratch_base(0ll), m_SpiPriority(0) {
|
||||
HsaEventDescriptor eventDesc;
|
||||
eventDesc.EventType = HSA_EVENTTYPE_SIGNAL;
|
||||
eventDesc.NodeId = isaBuf.Node();
|
||||
eventDesc.SyncVar.SyncVar.UserData = NULL;
|
||||
eventDesc.SyncVar.SyncVarSize = 0;
|
||||
|
||||
hsaKmtCreateEvent(&eventDesc, !eventAutoReset, false, &m_pEop);
|
||||
}
|
||||
|
||||
Dispatch::~Dispatch() {
|
||||
if (m_pEop != NULL)
|
||||
hsaKmtDestroyEvent(m_pEop);
|
||||
}
|
||||
|
||||
void Dispatch::SetArgs(void* pArg1, void* pArg2) {
|
||||
m_pArg1 = pArg1;
|
||||
m_pArg2 = pArg2;
|
||||
}
|
||||
|
||||
void Dispatch::SetDim(unsigned int x, unsigned int y, unsigned int z) {
|
||||
m_DimX = x;
|
||||
m_DimY = y;
|
||||
m_DimZ = z;
|
||||
}
|
||||
|
||||
void Dispatch::SetScratch(int numWaves, int waveSize, unsigned long long scratch_base) {
|
||||
m_ComputeTmpringSize = ((waveSize << 12) | (numWaves));
|
||||
m_ScratchEn = true;
|
||||
m_scratch_base = scratch_base;
|
||||
}
|
||||
|
||||
void Dispatch::SetSpiPriority(unsigned int priority) {
|
||||
m_SpiPriority = priority;
|
||||
}
|
||||
|
||||
void Dispatch::Submit(BaseQueue& queue) {
|
||||
ASSERT_NE(m_pEop, (void*)0);
|
||||
|
||||
BuildIb();
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4IndirectBufPacket(&m_IndirectBuf));
|
||||
|
||||
// Write data to SyncVar for synchronization purpose
|
||||
if (m_pEop->EventData.EventData.SyncVar.SyncVar.UserData != NULL) {
|
||||
queue.PlaceAndSubmitPacket(PM4WriteDataPacket((unsigned int*)m_pEop->
|
||||
EventData.EventData.SyncVar.SyncVar.UserData, m_pEop->EventId));
|
||||
}
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4ReleaseMemoryPacket(false, m_pEop->EventData.HWData2, m_pEop->EventId));
|
||||
|
||||
if (!queue.GetSkipWaitConsump())
|
||||
queue.Wait4PacketConsumption();
|
||||
}
|
||||
|
||||
void Dispatch::Sync(unsigned int timeout) {
|
||||
ASSERT_SUCCESS(hsaKmtWaitOnEvent(m_pEop, timeout));
|
||||
}
|
||||
|
||||
// returning with status in order to allow to take actions before proc termination
|
||||
int Dispatch::SyncWithStatus(unsigned int timeout) {
|
||||
int stat;
|
||||
|
||||
return ((stat = hsaKmtWaitOnEvent(m_pEop, timeout)) != HSAKMT_STATUS_SUCCESS);
|
||||
}
|
||||
|
||||
void Dispatch::BuildIb() {
|
||||
unsigned long long shiftedIsaAddr = m_IsaBuf.As<uint64_t>() >> 8;
|
||||
unsigned int arg0, arg1, arg2, arg3;
|
||||
SplitU64(reinterpret_cast<uint64_t>(m_pArg1), arg0, arg1);
|
||||
SplitU64(reinterpret_cast<uint64_t>(m_pArg2), arg2, arg3);
|
||||
|
||||
// starts at COMPUTE_START_X
|
||||
const unsigned int COMPUTE_DISPATCH_DIMS_VALUES[] = {
|
||||
0, // START_X
|
||||
0, // START_Y
|
||||
0, // START_Z
|
||||
1, // NUM_THREADS_X - this is actually the number of threads in a thread group
|
||||
1, // NUM_THREADS_Y
|
||||
1, // NUM_THREADS_Z
|
||||
0, // COMPUTE_PIPELINESTAT_ENABLE
|
||||
0, // COMPUTE_PERFCOUNT_ENABLE
|
||||
};
|
||||
|
||||
unsigned int pgmRsrc2 = 0;
|
||||
pgmRsrc2 |= (m_ScratchEn << COMPUTE_PGM_RSRC2__SCRATCH_EN__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__SCRATCH_EN_MASK;
|
||||
pgmRsrc2 |= ((m_scratch_base ? 6 : 4 ) << COMPUTE_PGM_RSRC2__USER_SGPR__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__USER_SGPR_MASK;
|
||||
pgmRsrc2 |= (1 << COMPUTE_PGM_RSRC2__TRAP_PRESENT__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__TRAP_PRESENT_MASK;
|
||||
pgmRsrc2 |= (1 << COMPUTE_PGM_RSRC2__TGID_X_EN__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__TGID_X_EN_MASK;
|
||||
pgmRsrc2 |= (1 << COMPUTE_PGM_RSRC2__TIDIG_COMP_CNT__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__TIDIG_COMP_CNT_MASK;
|
||||
pgmRsrc2 |= (0 << COMPUTE_PGM_RSRC2__EXCP_EN__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__EXCP_EN_MASK;
|
||||
pgmRsrc2 |= (1 << COMPUTE_PGM_RSRC2__EXCP_EN_MSB__SHIFT)
|
||||
& COMPUTE_PGM_RSRC2__EXCP_EN_MSB_MASK;
|
||||
|
||||
const unsigned int COMPUTE_PGM_RSRC[] = {
|
||||
0x000c0084 | ((m_SpiPriority & 3) << 10), // PGM_RSRC1 = { VGPRS: 16 SGPRS: 16 PRIORITY: m_SpiPriority FLOAT_MODE: c0 PRIV: 0 DX10_CLAMP: 0 DEBUG_MODE: 0 IEEE_MODE: 0 BULKY: 0 CDBG_USER: 0 }
|
||||
pgmRsrc2
|
||||
};
|
||||
|
||||
// starts at COMPUTE_PGM_LO
|
||||
const unsigned int COMPUTE_PGM_VALUES_GFX8[] = {
|
||||
static_cast<uint32_t>(shiftedIsaAddr), // PGM_LO
|
||||
static_cast<uint32_t>(shiftedIsaAddr >> 32) // PGM_HI
|
||||
| (is_dgpu() ? 0 : (1<<8)) // including PGM_ATC=?
|
||||
};
|
||||
|
||||
// starts at COMPUTE_PGM_LO
|
||||
const unsigned int COMPUTE_PGM_VALUES_GFX9[] = {
|
||||
static_cast<uint32_t>(shiftedIsaAddr), // PGM_LO
|
||||
static_cast<uint32_t>(shiftedIsaAddr >> 32) // PGM_HI
|
||||
| (is_dgpu() ? 0 : (1<<8)), // including PGM_ATC=?
|
||||
0,
|
||||
0,
|
||||
static_cast<uint32_t>(m_scratch_base >> 8), // compute_dispatch_scratch_base
|
||||
static_cast<uint32_t>(m_scratch_base >> 40)
|
||||
};
|
||||
|
||||
// starts at COMPUTE_RESOURCE_LIMITS
|
||||
const unsigned int COMPUTE_RESOURCE_LIMITS[] = {
|
||||
0, // COMPUTE_RESOURCE_LIMITS
|
||||
};
|
||||
|
||||
// starts at COMPUTE_TMPRING_SIZE
|
||||
const unsigned int COMPUTE_TMPRING_SIZE[] = {
|
||||
m_ComputeTmpringSize, // COMPUTE_TMPRING_SIZE
|
||||
};
|
||||
|
||||
// starts at COMPUTE_RESTART_X
|
||||
const unsigned int COMPUTE_RESTART_VALUES[] = {
|
||||
0, // COMPUTE_RESTART_X
|
||||
0, // COMPUTE_RESTART_Y
|
||||
0, // COMPUTE_RESTART_Z
|
||||
0 // COMPUTE_THREAD_TRACE_ENABLE
|
||||
};
|
||||
|
||||
// starts at COMPUTE_USER_DATA_0
|
||||
const unsigned int COMPUTE_USER_DATA_VALUES[] = {
|
||||
// Reg name - use in KFDtest - use in ABI
|
||||
arg0, // COMPUTE_USER_DATA_0 - arg0 - resource descriptor for the scratch buffer - 1st DWORD
|
||||
arg1, // COMPUTE_USER_DATA_1 - arg1 - resource descriptor for the scratch buffer - 2nd DWORD
|
||||
arg2, // COMPUTE_USER_DATA_2 - arg2 - resource descriptor for the scratch buffer - 3rd DWORD
|
||||
arg3, // COMPUTE_USER_DATA_3 - arg3 - resource descriptor for the scratch buffer - 4th DWORD
|
||||
static_cast<uint32_t>(m_scratch_base), // COMPUTE_USER_DATA_4 - flat_scratch_lo
|
||||
static_cast<uint32_t>(m_scratch_base >> 32), // COMPUTE_USER_DATA_4 - flat_scratch_hi
|
||||
0, // COMPUTE_USER_DATA_6 - - AQL queue address, low part
|
||||
0, // COMPUTE_USER_DATA_7 - - AQL queue address, high part
|
||||
0, // COMPUTE_USER_DATA_8 - - kernel arguments block, low part
|
||||
0, // COMPUTE_USER_DATA_9 - - kernel arguments block, high part
|
||||
0, // COMPUTE_USER_DATA_10 - - unused
|
||||
0, // COMPUTE_USER_DATA_11 - - unused
|
||||
0, // COMPUTE_USER_DATA_12 - - unused
|
||||
0, // COMPUTE_USER_DATA_13 - - unused
|
||||
0, // COMPUTE_USER_DATA_14 - - unused
|
||||
0, // COMPUTE_USER_DATA_15 - - unused
|
||||
};
|
||||
|
||||
const unsigned int DISPATCH_INIT_VALUE = 0x00000021 | (is_dgpu() ? 0 : 0x1000);
|
||||
// {COMPUTE_SHADER_EN=1, PARTIAL_TG_EN=0, FORCE_START_AT_000=0, ORDERED_APPEND_ENBL=0,
|
||||
// ORDERED_APPEND_MODE=0, USE_THREAD_DIMENSIONS=1, ORDER_MODE=0, DISPATCH_CACHE_CNTL=0,
|
||||
// SCALAR_L1_INV_VOL=0, VECTOR_L1_INV_VOL=0, DATA_ATC=?, RESTORE=0}
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4AcquireMemoryPacket());
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_START_X, COMPUTE_DISPATCH_DIMS_VALUES, ARRAY_SIZE(COMPUTE_DISPATCH_DIMS_VALUES)));
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_PGM_LO,
|
||||
(g_TestGPUFamilyId >= FAMILY_AI) ? COMPUTE_PGM_VALUES_GFX9 : COMPUTE_PGM_VALUES_GFX8,
|
||||
(g_TestGPUFamilyId >= FAMILY_AI) ? ARRAY_SIZE(COMPUTE_PGM_VALUES_GFX9) : ARRAY_SIZE(COMPUTE_PGM_VALUES_GFX8)));
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_PGM_RSRC1, COMPUTE_PGM_RSRC, ARRAY_SIZE(COMPUTE_PGM_RSRC)));
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_RESOURCE_LIMITS, COMPUTE_RESOURCE_LIMITS, ARRAY_SIZE(COMPUTE_RESOURCE_LIMITS)));
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_TMPRING_SIZE, COMPUTE_TMPRING_SIZE, ARRAY_SIZE(COMPUTE_TMPRING_SIZE)));
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_RESTART_X, COMPUTE_RESTART_VALUES, ARRAY_SIZE(COMPUTE_RESTART_VALUES)));
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4SetShaderRegPacket(mmCOMPUTE_USER_DATA_0, COMPUTE_USER_DATA_VALUES, ARRAY_SIZE(COMPUTE_USER_DATA_VALUES)));
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4DispatchDirectPacket(m_DimX, m_DimY, m_DimZ, DISPATCH_INIT_VALUE));
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4PartialFlushPacket());
|
||||
|
||||
m_IndirectBuf.AddPacket(PM4AcquireMemoryPacket());
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_DISPATCH__H__
|
||||
#define __KFD_DISPATCH__H__
|
||||
#include "KFDTestUtil.hpp"
|
||||
#include "IndirectBuffer.hpp"
|
||||
#include "BaseQueue.hpp"
|
||||
|
||||
class Dispatch {
|
||||
public:
|
||||
Dispatch(const HsaMemoryBuffer& isaBuf, const bool eventAutoReset = false);
|
||||
~Dispatch();
|
||||
|
||||
void SetArgs(void* pArg1, void* pArg2);
|
||||
|
||||
void SetDim(unsigned int x, unsigned int y, unsigned int z);
|
||||
|
||||
void Submit(BaseQueue& queue);
|
||||
|
||||
void Sync(unsigned int timeout = HSA_EVENTTIMEOUT_INFINITE);
|
||||
|
||||
int SyncWithStatus(unsigned int timeout);
|
||||
|
||||
void SetScratch(int numWaves, int waveSize, unsigned long long scratch_base);
|
||||
|
||||
void SetSpiPriority(unsigned int priority);
|
||||
|
||||
HsaEvent *GetHsaEvent() { return m_pEop; }
|
||||
|
||||
private:
|
||||
void BuildIb();
|
||||
|
||||
private:
|
||||
const HsaMemoryBuffer& m_IsaBuf;
|
||||
|
||||
IndirectBuffer m_IndirectBuf;
|
||||
|
||||
unsigned int m_DimX;
|
||||
unsigned int m_DimY;
|
||||
unsigned int m_DimZ;
|
||||
|
||||
void* m_pArg1;
|
||||
void* m_pArg2;
|
||||
|
||||
HsaEvent* m_pEop;
|
||||
|
||||
bool m_ScratchEn;
|
||||
unsigned int m_ComputeTmpringSize;
|
||||
|
||||
unsigned long long m_scratch_base;
|
||||
unsigned int m_SpiPriority;
|
||||
};
|
||||
|
||||
#endif // __KFD_DISPATCH__H__
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "GoogleTestExtension.hpp"
|
||||
#include "OSWrapper.hpp"
|
||||
|
||||
bool Ok2Run(unsigned int testProfile) {
|
||||
bool testMatchProfile = true;
|
||||
if ((testProfile & g_TestRunProfile) == 0) {
|
||||
// display msg to notify a test that is not running
|
||||
WARN() << "Test is skipped beacuse profile does not match current run mode" << std::endl;
|
||||
testMatchProfile = false;
|
||||
}
|
||||
|
||||
return testMatchProfile;
|
||||
}
|
||||
|
||||
// This predication is used when specific HW capabilites must exist for the test to succeed.
|
||||
bool TestReqEnvCaps(unsigned int envCaps) {
|
||||
bool testMatchEnv = true;
|
||||
if ((envCaps & g_TestENVCaps) != envCaps) {
|
||||
// display msg to notify a test that is not running
|
||||
WARN() << "Test is skipped due to HW capability issues" << std::endl;
|
||||
testMatchEnv = false;
|
||||
}
|
||||
|
||||
return testMatchEnv;
|
||||
}
|
||||
|
||||
// This predication is used when specific HW capabilites must abscent for the test to succeed.
|
||||
// e.g testing capabilites not supported by HW scheduling
|
||||
bool TestReqNoEnvCaps(unsigned int envCaps) {
|
||||
bool testMatchEnv = true;
|
||||
if ((envCaps & g_TestENVCaps) != 0) {
|
||||
// display msg to notify a test that is not running
|
||||
WARN() << "Test is skipped due to HW capability issues" << std::endl;
|
||||
testMatchEnv = false;
|
||||
}
|
||||
|
||||
return testMatchEnv;
|
||||
}
|
||||
|
||||
std::ostream& operator<< (KFDLog log, LOGTYPE level) {
|
||||
const char *heading;
|
||||
|
||||
if (level == LOGTYPE_WARNING) {
|
||||
SetConsoleTextColor(TEXTCOLOR_YELLOW);
|
||||
heading = "[----------] ";
|
||||
} else {
|
||||
SetConsoleTextColor(TEXTCOLOR_GREEN);
|
||||
heading = "[ ] ";
|
||||
}
|
||||
|
||||
std::clog << heading;
|
||||
SetConsoleTextColor(TEXTCOLOR_WHITE);
|
||||
|
||||
return std::clog;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __GOOGLETEST_EXTENSION__H__
|
||||
#define __GOOGLETEST_EXTENSION__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "hsakmt.h"
|
||||
#include "KFDTestFlags.hpp"
|
||||
|
||||
enum LOGTYPE {
|
||||
LOGTYPE_INFO, // msg header in green
|
||||
LOGTYPE_WARNING // msg header in yellow
|
||||
};
|
||||
|
||||
class KFDLog{};
|
||||
std::ostream& operator << (KFDLog log ,LOGTYPE level);
|
||||
|
||||
// @brief log additional details, to be displayed in the same format as other google test outputs
|
||||
// currently not supported by google test
|
||||
// should be used like cout: LOG() << "message" << value << std::endl;
|
||||
#define LOG() KFDLog() << LOGTYPE_INFO
|
||||
#define WARN() KFDLog() << LOGTYPE_WARNING
|
||||
|
||||
// all test MUST be in a try catch since google test flag to throw exception on any fatal fail is on
|
||||
#define TEST_START(testProfile) if (Ok2Run(testProfile)) try {
|
||||
#define TEST_END } catch (...) {}
|
||||
|
||||
// used to wrape setup and teardown functions, anything that is build-in gtest and is not a test
|
||||
#define ROUTINE_START try {
|
||||
#define ROUTINE_END }catch(...) {}
|
||||
|
||||
#define TEST_REQUIRE_ENV_CAPABILITIES(envCaps) if (!TestReqEnvCaps(envCaps)) return;
|
||||
#define TEST_REQUIRE_NO_ENV_CAPABILITIES(envCaps) if (!TestReqNoEnvCaps(envCaps)) return;
|
||||
|
||||
#define ASSERT_SUCCESS(_val) ASSERT_EQ(HSAKMT_STATUS_SUCCESS, (_val))
|
||||
#define EXPECT_SUCCESS(_val) EXPECT_EQ(HSAKMT_STATUS_SUCCESS, (_val))
|
||||
|
||||
#define ASSERT_NOTNULL(_val) ASSERT_NE((void *)NULL, _val)
|
||||
#define EXPECT_NOTNULL(_val) EXPECT_NE((void *)NULL, _val)
|
||||
|
||||
// @brief determines if its ok to run a test given input flags
|
||||
bool Ok2Run(unsigned int testProfile);
|
||||
|
||||
// @brief checks if all HW capabilities needed for a test to run exist
|
||||
bool TestReqEnvCaps(unsigned int hwCaps);
|
||||
|
||||
// @brief checks if all HW capabilities that prevents a test from running are non existing
|
||||
bool TestReqNoEnvCaps(unsigned int hwCaps);
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "IndirectBuffer.hpp"
|
||||
#include "GoogleTestExtension.hpp"
|
||||
#include "pm4_pkt_struct_common.h"
|
||||
#include "PM4Packet.hpp"
|
||||
|
||||
|
||||
IndirectBuffer::IndirectBuffer(PACKETTYPE type, unsigned int sizeInDWords, unsigned int NodeId)
|
||||
:m_NumOfPackets(0), m_MaxSize(sizeInDWords), m_ActualSize(0), m_PacketTypeAllowed(type) {
|
||||
m_IndirectBuf = new HsaMemoryBuffer(sizeInDWords*sizeof(unsigned int), NodeId, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
}
|
||||
|
||||
IndirectBuffer::~IndirectBuffer(void) {
|
||||
delete m_IndirectBuf;
|
||||
}
|
||||
|
||||
void IndirectBuffer::AddPacket(const BasePacket &packet) {
|
||||
ASSERT_EQ(packet.PacketType(), m_PacketTypeAllowed) << "Cannot add a packet since packet type doesn't match queue";
|
||||
|
||||
unsigned int writePtr = m_ActualSize;
|
||||
|
||||
ASSERT_GE(m_MaxSize, packet.SizeInDWords() + writePtr) << "Cannot add a packet, not enough room";
|
||||
|
||||
memcpy(m_IndirectBuf->As<unsigned int*>() + writePtr , packet.GetPacket(), packet.SizeInBytes());
|
||||
m_ActualSize += packet.SizeInDWords();
|
||||
m_NumOfPackets++;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __INDIRECT_BUFFER__H__
|
||||
#define __INDIRECT_BUFFER__H__
|
||||
|
||||
#include "BasePacket.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
/** @class IndirectBuffer
|
||||
* when working with indirect buffer, create IndirectBuffer, fill it with all the packets you want
|
||||
* create an indirect packet to point to it, and submit the packet to queue
|
||||
*/
|
||||
class IndirectBuffer {
|
||||
public:
|
||||
// @param[size] queue max size in DWords
|
||||
// @param[type] packets type allowed in queue
|
||||
IndirectBuffer(PACKETTYPE type, unsigned int sizeInDWords, unsigned int NodeId);
|
||||
~IndirectBuffer(void);
|
||||
|
||||
// @brief add packet to queue, all validations are done with gtest ASSERT and EXPECT
|
||||
void AddPacket(const BasePacket &packet);
|
||||
// @returns the actual size of the indirect queue in DWord, equivalent to write pointer
|
||||
unsigned int SizeInDWord() { return m_ActualSize; }
|
||||
// @returns indirect queue address
|
||||
unsigned int *Addr() { return m_IndirectBuf->As<unsigned int*>(); }
|
||||
|
||||
protected:
|
||||
// how many packets in queue
|
||||
unsigned int m_NumOfPackets;
|
||||
// max size of queue in DWords
|
||||
unsigned int m_MaxSize;
|
||||
// current size of queue in DWords
|
||||
unsigned int m_ActualSize;
|
||||
HsaMemoryBuffer *m_IndirectBuf;
|
||||
// defines what packets are supported in this queue
|
||||
PACKETTYPE m_PacketTypeAllowed;
|
||||
};
|
||||
|
||||
#endif // __INDIRECT_BUFFER__H__
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
#include "IsaGenerator_Gfx72.hpp"
|
||||
#include "IsaGenerator_Gfx8.hpp"
|
||||
#include "IsaGenerator_Gfx9.hpp"
|
||||
|
||||
#include "GoogleTestExtension.hpp"
|
||||
|
||||
#include "sp3.h"
|
||||
|
||||
const std::string IsaGenerator::ADDRESS_WATCH_SP3(
|
||||
"var REG_TRAPSTS_EXCP_MASK = 0x000001ff\n"
|
||||
"var WAVE_COUNT_OFFSET = 12\n"
|
||||
"var TMA_CYCLE_OFFSET = 16\n"
|
||||
"\n"
|
||||
"/*\n"
|
||||
" * ttmp[0:1] -- The ISA address that triggered this trap handler\n"
|
||||
" * ttmp[10:11] -- The TMA user provided, used to store the debug info in this shader\n"
|
||||
" * v[10:14] ttmp[7:8] -- temp use inside this shader\n"
|
||||
" * s5 -- store the counts that this trap been triggered\n"
|
||||
" * Each time when the trap is triggered , this shader will write\n"
|
||||
" * ttmp[0] : ttmp[1] : Trap_Status : [reserved]\n"
|
||||
" * to TMA + (trap count * TMA_CYCLE_OFFSET)\n"
|
||||
" * The TMA + WAVE_COUNT_OFFSET(the first [reserved] address)\n"
|
||||
" * used to store the total triggered trap count.\n"
|
||||
" */\n"
|
||||
"shader main\n"
|
||||
"\n"
|
||||
" asic(VI)\n"
|
||||
"\n"
|
||||
" type(CS)\n"
|
||||
" v_mov_b32 v10, ttmp10\n"
|
||||
" v_mov_b32 v11, ttmp11\n"
|
||||
" s_mov_b32 ttmp7, s5\n"
|
||||
" s_mulk_i32 ttmp7, TMA_CYCLE_OFFSET\n"
|
||||
" s_addk_i32 s5, 1\n"
|
||||
" v_mov_b32 v12, ttmp0\n"
|
||||
" v_add_u32 v10, vcc, ttmp7, v10\n"
|
||||
" flat_store_dword v[10,11], v12 slc glc\n"
|
||||
" v_mov_b32 v12, ttmp1\n"
|
||||
" v_add_u32 v10, vcc, 4, v10\n"
|
||||
" flat_store_dword v[10,11], v12 slc glc\n"
|
||||
" s_getreg_b32 ttmp8, hwreg(HW_REG_TRAPSTS)\n"
|
||||
" s_and_b32 ttmp8, ttmp8, REG_TRAPSTS_EXCP_MASK\n"
|
||||
" v_mov_b32 v12, ttmp8\n"
|
||||
" v_add_u32 v10, vcc, 4, v10\n"
|
||||
" flat_store_dword v[10,11], v12 glc\n"
|
||||
" v_mov_b32 v10, ttmp10\n"
|
||||
" v_add_u32 v10, vcc, WAVE_COUNT_OFFSET, v10\n"
|
||||
" v_mov_b32 v13, 1\n"
|
||||
" flat_atomic_add v14, v[10:11], v13 slc glc\n"
|
||||
" s_and_b32 ttmp1, ttmp1, 0xffff\n"
|
||||
" s_rfe_b64 [ttmp0,ttmp1]\n"
|
||||
"end\n"
|
||||
);
|
||||
|
||||
IsaGenerator* IsaGenerator::Create(unsigned int familyId) {
|
||||
switch (familyId) {
|
||||
case FAMILY_CI:
|
||||
case FAMILY_KV:
|
||||
return new IsaGenerator_Gfx72;
|
||||
case FAMILY_VI:
|
||||
case FAMILY_CZ:
|
||||
return new IsaGenerator_Gfx8;
|
||||
case FAMILY_AI:
|
||||
case FAMILY_RV:
|
||||
return new IsaGenerator_Gfx9;
|
||||
default:
|
||||
LOG() << "Error: Invalid ISA" << std::endl;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
void IsaGenerator::GetAwTrapHandler(HsaMemoryBuffer& rBuf) {
|
||||
CompileShader(ADDRESS_WATCH_SP3.c_str(), "main", rBuf);
|
||||
}
|
||||
|
||||
void IsaGenerator::CompileShader(const char* shaderCode, const char* shaderName, HsaMemoryBuffer& rBuf) {
|
||||
sp3_context* pSp3 = sp3_new();
|
||||
sp3_setasic(pSp3, GetAsicName().c_str());
|
||||
sp3_parse_string(pSp3, shaderCode);
|
||||
sp3_shader* pShader = sp3_compile(pSp3, shaderName);
|
||||
|
||||
std::copy(pShader->data, pShader->data + pShader->size, rBuf.As<unsigned int*>());
|
||||
sp3_free_shader(pShader);
|
||||
|
||||
/** Inside this close function, there is an unknown reason of free memory not used by compiler.
|
||||
* Comment out this as a workaround. System will do the garbage collection after this
|
||||
* application is closed.
|
||||
*/
|
||||
// sp3_close(pSp3);
|
||||
}
|
||||
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISAGENERATOR_H_
|
||||
#define _ISAGENERATOR_H_
|
||||
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
/* isa generation class - interface */
|
||||
class IsaGenerator {
|
||||
|
||||
public:
|
||||
static IsaGenerator* Create(unsigned int familyId);
|
||||
|
||||
virtual ~IsaGenerator() {}
|
||||
|
||||
virtual void GetNoopIsa(HsaMemoryBuffer& rBuf) = 0;
|
||||
virtual void GetCopyDwordIsa(HsaMemoryBuffer& rBuf) = 0;
|
||||
virtual void GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf) = 0;
|
||||
virtual void GetAtomicIncIsa(HsaMemoryBuffer& rBuf) = 0;
|
||||
virtual void GetCwsrTrapHandler(HsaMemoryBuffer& rBuf) {}
|
||||
virtual void GetAwTrapHandler(HsaMemoryBuffer& rBuf);
|
||||
|
||||
void CompileShader(const char* shaderCode, const char* shaderName, HsaMemoryBuffer& rBuf);
|
||||
|
||||
protected:
|
||||
virtual const std::string& GetAsicName() = 0;
|
||||
|
||||
private:
|
||||
static const std::string ADDRESS_WATCH_SP3;
|
||||
};
|
||||
|
||||
#endif //_ISAGENERATOR_H_
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "IsaGenerator_Gfx72.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
const std::string IsaGenerator_Gfx72::ASIC_NAME = "CI";
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::NOOP_ISA[] = {
|
||||
0xbf810000 // S_ENDPGM
|
||||
};
|
||||
|
||||
/* The below arrays are filled with hex values in order not to reference
|
||||
* proprietary header files, but we still leave the code here for future
|
||||
* reference.
|
||||
*/
|
||||
#if 0
|
||||
const uint32_t IsaGenerator_Gfx72::COPY_DWORD_ISA[] = {
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (0 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (0 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v0, s0 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (1 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (1 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v1, s1 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (2 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (2 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v2, s2 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (3 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (3 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v3, s3 (VOP1)
|
||||
|
||||
(55u << SQ_FLAT_0__ENCODING__SHIFT) | (SQ_FLAT_LOAD_DWORD << SQ_FLAT_0__OP__SHIFT) | (1 << SQ_FLAT_0__SLC__SHIFT) | (1 << SQ_FLAT_0__GLC__SHIFT)/*(3 << 16)*/, // SQ_FLAT_0, flat_load_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
(4u << SQ_FLAT_1__VDST__SHIFT) | (0 << SQ_FLAT_1__ADDR__SHIFT), // ADDR = V0:V1, VDST = V4 (FLAT_1)
|
||||
|
||||
(383u << SQ_SOPP__ENCODING__SHIFT) | (SQ_S_WAITCNT << SQ_SOPP__OP__SHIFT) | (0 << SQ_SOPP__SIMM16__SHIFT), // s_waitcnt 0 (SOPP)
|
||||
|
||||
(55u << SQ_FLAT_0__ENCODING__SHIFT) | (SQ_FLAT_STORE_DWORD << SQ_FLAT_0__OP__SHIFT) | (1 << SQ_FLAT_0__SLC__SHIFT) | (1 << SQ_FLAT_0__GLC__SHIFT), // SQ_FLAT_0, flat_store_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
(4u << SQ_FLAT_1__DATA__SHIFT) | (2 << SQ_FLAT_1__ADDR__SHIFT), // ADDR = V2:V3, DATA = V4 (FLAT_1)
|
||||
|
||||
0xBF810000u // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::INFINITE_LOOP_ISA[] = {
|
||||
(0x17F << SQ_SOPP__ENCODING__SHIFT) | (SQ_S_BRANCH << SQ_SOPP__OP__SHIFT) | ( (const uint32_t)-1 << SQ_SOPP__SIMM16__SHIFT), // s_branch -1 (PC <- PC + SIMM*4)+4
|
||||
0xBF810000u // S_ENDPGM
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::ATOMIC_INC_ISA[] = {
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (0 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (0 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v0, s0 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (1 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (1 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v1, s1 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (2 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (0xC1 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 0xFFFFFFFF, s2 (VOP1)
|
||||
|
||||
(55u << SQ_FLAT_0__ENCODING__SHIFT) | (SQ_FLAT_ATOMIC_INC << SQ_FLAT_0__OP__SHIFT) | (1 << SQ_FLAT_0__SLC__SHIFT) | (0 << SQ_FLAT_0__GLC__SHIFT), // SQ_FLAT_0, flat_atomic_inc, slc = 1, glc = 0 (FLAT_0)
|
||||
(3u << SQ_FLAT_1__VDST__SHIFT) | (2u << SQ_FLAT_1__DATA__SHIFT) | (0 << SQ_FLAT_1__ADDR__SHIFT), // ADDR/dst = V0:V1, VDST/ret = V3, DATA/src=V2 (FLAT_1)
|
||||
0xBF810000u // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::COPY_DWORD_ISA[] = {
|
||||
0x7e000200, // v_mov_b32 v0, s0 (VOP1)
|
||||
0x7e020201, // v_mov_b32 v1, s1 (VOP1)
|
||||
0x7e040202, // v_mov_b32 v2, s2 (VOP1)
|
||||
0x7e060203, // v_mov_b32 v3, s3 (VOP1)
|
||||
|
||||
0xdc330000, // SQ_FLAT_0, flat_load_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
0x04000000, // ADDR = V0:V1, VDST = V4 (FLAT_1)
|
||||
|
||||
0xbf8c0000, // s_waitcnt 0 (SOPP)
|
||||
|
||||
0xdc730000, // SQ_FLAT_0, flat_store_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
0x00000402, // ADDR = V2:V3, DATA = V4 (FLAT_1)
|
||||
|
||||
0xbf810000 // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::INFINITE_LOOP_ISA[] = {
|
||||
0xbf82ffff, // s_branch -1 (PC <- PC + SIMM*4)+4
|
||||
0xbf810000 // S_ENDPGM
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx72::ATOMIC_INC_ISA[] = {
|
||||
0x7e000200, // v_mov_b32 v0, s0 (VOP1)
|
||||
0x7e020201, // v_mov_b32 v1, s1 (VOP1)
|
||||
0x7e0402c1, // v_mov_b32 0xFFFFFFFF, s2 (VOP1)
|
||||
|
||||
0xdcf20000, // SQ_FLAT_0, flat_atomic_inc, slc = 1, glc = 0 (FLAT_0)
|
||||
0x03000200, // ADDR/dst = V0:V1, VDST/ret = V3, DATA/src=V2 (FLAT_1)
|
||||
0xbf810000 // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
|
||||
void IsaGenerator_Gfx72::GetNoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(NOOP_ISA, NOOP_ISA+ARRAY_SIZE(NOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx72::GetCopyDwordIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(COPY_DWORD_ISA, COPY_DWORD_ISA+ARRAY_SIZE(COPY_DWORD_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx72::GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(INFINITE_LOOP_ISA, INFINITE_LOOP_ISA+ARRAY_SIZE(INFINITE_LOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx72::GetAtomicIncIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(ATOMIC_INC_ISA, ATOMIC_INC_ISA+ARRAY_SIZE(ATOMIC_INC_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
const std::string& IsaGenerator_Gfx72::GetAsicName() {
|
||||
return ASIC_NAME;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISAGENERATOR_GFX72_H_
|
||||
#define _ISAGENERATOR_GFX72_H_
|
||||
|
||||
#include <string>
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
class IsaGenerator_Gfx72 : public IsaGenerator {
|
||||
public:
|
||||
virtual void GetNoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetCopyDwordIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetAtomicIncIsa(HsaMemoryBuffer& rBuf);
|
||||
|
||||
protected:
|
||||
virtual const std::string& GetAsicName();
|
||||
|
||||
private:
|
||||
static const std::string ASIC_NAME;
|
||||
|
||||
static const uint32_t NOOP_ISA[];
|
||||
static const uint32_t COPY_DWORD_ISA[];
|
||||
static const uint32_t INFINITE_LOOP_ISA[];
|
||||
static const uint32_t ATOMIC_INC_ISA[];
|
||||
};
|
||||
|
||||
#endif // _ISAGENERATOR_GFX72_H_
|
||||
@@ -0,0 +1,128 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "IsaGenerator_Gfx8.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
const std::string IsaGenerator_Gfx8::ASIC_NAME = "VI";
|
||||
|
||||
const uint32_t IsaGenerator_Gfx8::NOOP_ISA[] = {
|
||||
0xbf810000 // S_ENDPGM
|
||||
};
|
||||
|
||||
/** The below arrays are filled with hex values in order not to reference
|
||||
* proprietary header files, but we still leave the code here for future
|
||||
* reference.
|
||||
*/
|
||||
#if 0
|
||||
const uint32_t IsaGenerator_Gfx8::COPY_DWORD_ISA[] = {
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (0 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (0 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v0, s0 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (1 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (1 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v1, s1 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (2 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (2 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v2, s2 (VOP1)
|
||||
(63u << SQ_VOP1__ENCODING__SHIFT) | (3 << SQ_VOP1__VDST__SHIFT) | (SQ_V_MOV_B32 << SQ_VOP1__OP__SHIFT) | (3 << SQ_VOP1__SRC0__SHIFT), // v_mov_b32 v3, s3 (VOP1)
|
||||
|
||||
(55u << SQ_FLAT_0__ENCODING__SHIFT) | (SQ_FLAT_LOAD_DWORD << SQ_FLAT_0__OP__SHIFT) | (1 << SQ_FLAT_0__SLC__SHIFT) | (1 << SQ_FLAT_0__GLC__SHIFT)/*(3 << 16)*/, // SQ_FLAT_0, flat_load_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
(4u << SQ_FLAT_1__VDST__SHIFT) | (0 << SQ_FLAT_1__ADDR__SHIFT), // ADDR = V0:V1, VDST = V4 (FLAT_1)
|
||||
|
||||
(383u << SQ_SOPP__ENCODING__SHIFT) | (SQ_S_WAITCNT << SQ_SOPP__OP__SHIFT) | (0 << SQ_SOPP__SIMM16__SHIFT), // s_waitcnt 0 (SOPP)
|
||||
|
||||
(55u << SQ_FLAT_0__ENCODING__SHIFT) | (SQ_FLAT_STORE_DWORD << SQ_FLAT_0__OP__SHIFT) | (1 << SQ_FLAT_0__SLC__SHIFT) | (1 << SQ_FLAT_0__GLC__SHIFT), // SQ_FLAT_0, flat_store_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
(4u << SQ_FLAT_1__DATA__SHIFT) | (2 << SQ_FLAT_1__ADDR__SHIFT), // ADDR = V2:V3, DATA = V4 (FLAT_1)
|
||||
|
||||
0xBF810000u // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx8::INFINITE_LOOP_ISA[] = {
|
||||
(0x17F << SQ_SOPP__ENCODING__SHIFT) | (SQ_S_BRANCH << SQ_SOPP__OP__SHIFT) | ( (const uint32_t)-1 << SQ_SOPP__SIMM16__SHIFT), // s_branch -1 (PC <- PC + SIMM*4)+4
|
||||
0xBF810000u // S_ENDPGM
|
||||
};
|
||||
#endif
|
||||
|
||||
const uint32_t IsaGenerator_Gfx8::COPY_DWORD_ISA[] = {
|
||||
0x7e000200, // v_mov_b32 v0, s0 (VOP1)
|
||||
0x7e020201, // v_mov_b32 v1, s1 (VOP1)
|
||||
0x7e040202, // v_mov_b32 v2, s2 (VOP1)
|
||||
0x7e060203, // v_mov_b32 v3, s3 (VOP1)
|
||||
|
||||
0xdc530000, // SQ_FLAT_0, flat_load_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
0x04000000, // ADDR = V0:V1, VDST = V4 (FLAT_1)
|
||||
|
||||
0xbf8c0000, // s_waitcnt 0 (SOPP)
|
||||
|
||||
0xdc730000, // SQ_FLAT_0, flat_store_dword, slc = 1, glc = 1 (FLAT_0)
|
||||
0x00000402, // ADDR = V2:V3, DATA = V4 (FLAT_1)
|
||||
|
||||
0xbf810000 // s_endpgm, note that we rely on the implicit s_waitcnt 0,0,0
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx8::INFINITE_LOOP_ISA[] = {
|
||||
0xbf82ffff, // s_branch -1 (PC <- PC + SIMM*4)+4
|
||||
0xbf810000 // S_ENDPGM
|
||||
};
|
||||
|
||||
/**
|
||||
* The atomic_add_isa binary is generated from following ISA
|
||||
* The original atomic_inc is not support by some PCIE, so use atomic_add instead
|
||||
*
|
||||
*/
|
||||
/*
|
||||
shader atomic_add
|
||||
asic(VI)
|
||||
type(CS)
|
||||
v_mov_b32 v0, s0
|
||||
v_mov_b32 v1, s1
|
||||
v_mov_b32 v2, 1
|
||||
flat_atomic_add v3, v[0:1], v2 slc glc
|
||||
s_waitcnt 0
|
||||
s_endpgm
|
||||
end
|
||||
*/
|
||||
|
||||
const uint32_t IsaGenerator_Gfx8::ATOMIC_ADD_ISA[] = {
|
||||
0x7e000200, 0x7e020201,
|
||||
0x7e040281, 0xdd0b0000,
|
||||
0x03000200, 0xbf8c0000,
|
||||
0xbf810000, 0x00000000
|
||||
};
|
||||
|
||||
void IsaGenerator_Gfx8::GetNoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(NOOP_ISA, NOOP_ISA+ARRAY_SIZE(NOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx8::GetCopyDwordIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(COPY_DWORD_ISA, COPY_DWORD_ISA+ARRAY_SIZE(COPY_DWORD_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx8::GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(INFINITE_LOOP_ISA, INFINITE_LOOP_ISA+ARRAY_SIZE(INFINITE_LOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx8::GetAtomicIncIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(ATOMIC_ADD_ISA, ATOMIC_ADD_ISA+ARRAY_SIZE(ATOMIC_ADD_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
const std::string& IsaGenerator_Gfx8::GetAsicName() {
|
||||
return ASIC_NAME;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISAGENERATOR_GFX8_H_
|
||||
#define _ISAGENERATOR_GFX8_H_
|
||||
|
||||
#include <string>
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
class IsaGenerator_Gfx8 : public IsaGenerator {
|
||||
public:
|
||||
virtual void GetNoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetCopyDwordIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetAtomicIncIsa(HsaMemoryBuffer& rBuf);
|
||||
|
||||
protected:
|
||||
virtual const std::string& GetAsicName();
|
||||
|
||||
private:
|
||||
static const std::string ASIC_NAME;
|
||||
|
||||
static const uint32_t NOOP_ISA[];
|
||||
static const uint32_t COPY_DWORD_ISA[];
|
||||
static const uint32_t INFINITE_LOOP_ISA[];
|
||||
static const uint32_t ATOMIC_ADD_ISA[];
|
||||
};
|
||||
|
||||
#endif // _ISAGENERATOR_GFX72_H_
|
||||
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "IsaGenerator_Gfx9.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <string>
|
||||
|
||||
const std::string IsaGenerator_Gfx9::ASIC_NAME = "GFX9";
|
||||
|
||||
/* The binaries are generated from following ISA */
|
||||
#if 0
|
||||
/* flat_atomic_inc will not support by some PCIE, use flat_atomic_add instead */
|
||||
shader atomic_add
|
||||
asic(GFX9)
|
||||
type(CS)
|
||||
v_mov_b32 v0, s0
|
||||
v_mov_b32 v1, s1
|
||||
v_mov_b32 v2, 1
|
||||
flat_atomic_add v3, v[0:1], v2 slc glc
|
||||
s_waitcnt 0
|
||||
s_endpgm
|
||||
end
|
||||
|
||||
shader copy_dword
|
||||
asic(GFX9)
|
||||
type(CS)
|
||||
/* copy the parameters from scalar registers to vector registers */
|
||||
v_mov_b32 v0, s0
|
||||
v_mov_b32 v1, s1
|
||||
v_mov_b32 v2, s2
|
||||
v_mov_b32 v3, s3
|
||||
/* copy a dword between the passed addresses */
|
||||
flat_load_dword v4, v[0:1] slc glc
|
||||
s_waitcnt 0
|
||||
flat_store_dword v[2:3], v4 slc glc
|
||||
s_endpgm
|
||||
end
|
||||
|
||||
shader main
|
||||
asic(GFX9)
|
||||
type(CS)
|
||||
loop:
|
||||
s_branch loop
|
||||
s_endpgm
|
||||
end
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
const uint32_t IsaGenerator_Gfx9::NOOP_ISA[] = {
|
||||
0xbf810000
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx9::COPY_DWORD_ISA[] = {
|
||||
0x7e000200, 0x7e020201,
|
||||
0x7e040202, 0x7e060203,
|
||||
0xdc530000, 0x047f0000,
|
||||
0xbf8c0000, 0xdc730000,
|
||||
0x007f0402, 0xbf810000
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx9::INFINITE_LOOP_ISA[] = {
|
||||
0xbf82ffff, 0xbf810000
|
||||
};
|
||||
|
||||
const uint32_t IsaGenerator_Gfx9::ATOMIC_ADD_ISA[] = {
|
||||
0x7e000200, 0x7e020201,
|
||||
0x7e040281, 0xdd0b0000,
|
||||
0x037f0200, 0xbf8c0000,
|
||||
0xbf810000, 0x00000000
|
||||
};
|
||||
|
||||
void IsaGenerator_Gfx9::GetNoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(NOOP_ISA, NOOP_ISA+ARRAY_SIZE(NOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx9::GetCopyDwordIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(COPY_DWORD_ISA, COPY_DWORD_ISA+ARRAY_SIZE(COPY_DWORD_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx9::GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(INFINITE_LOOP_ISA, INFINITE_LOOP_ISA+ARRAY_SIZE(INFINITE_LOOP_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
void IsaGenerator_Gfx9::GetAtomicIncIsa(HsaMemoryBuffer& rBuf) {
|
||||
std::copy(ATOMIC_ADD_ISA, ATOMIC_ADD_ISA+ARRAY_SIZE(ATOMIC_ADD_ISA), rBuf.As<uint32_t*>());
|
||||
}
|
||||
|
||||
const std::string& IsaGenerator_Gfx9::GetAsicName() {
|
||||
return ASIC_NAME;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _ISAGENERATOR_GFX9_H_
|
||||
#define _ISAGENERATOR_GFX9_H_
|
||||
|
||||
#include <string>
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
class IsaGenerator_Gfx9 : public IsaGenerator {
|
||||
public:
|
||||
virtual void GetNoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetCopyDwordIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetInfiniteLoopIsa(HsaMemoryBuffer& rBuf);
|
||||
virtual void GetAtomicIncIsa(HsaMemoryBuffer& rBuf);
|
||||
|
||||
protected:
|
||||
virtual const std::string& GetAsicName();
|
||||
|
||||
private:
|
||||
static const std::string ASIC_NAME;
|
||||
|
||||
static const uint32_t NOOP_ISA[];
|
||||
static const uint32_t COPY_DWORD_ISA[];
|
||||
static const uint32_t INFINITE_LOOP_ISA[];
|
||||
static const uint32_t ATOMIC_ADD_ISA[];
|
||||
};
|
||||
|
||||
#endif // _ISAGENERATOR_GFX9_H_
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
void KFDBaseComponentTest::SetUpTestCase() {
|
||||
}
|
||||
|
||||
void KFDBaseComponentTest::TearDownTestCase() {
|
||||
}
|
||||
|
||||
void KFDBaseComponentTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtOpenKFD());
|
||||
EXPECT_SUCCESS(hsaKmtGetVersion(&m_VersionInfo));
|
||||
memset( &m_SystemProperties, 0, sizeof(m_SystemProperties) );
|
||||
|
||||
/** in order to be correctly testing the KFD interfaces and ensure
|
||||
* that the KFD acknowledges relevant node parameters
|
||||
* for the rest of the tests and used for more specific topology tests
|
||||
* call to GetSystemProperties for a system snapshot of the topology here
|
||||
*/
|
||||
ASSERT_SUCCESS(hsaKmtAcquireSystemProperties(&m_SystemProperties));
|
||||
ASSERT_GT(m_SystemProperties.NumNodes, HSAuint32(0)) << "HSA has no nodes.";
|
||||
|
||||
m_NodeInfo.Init(m_SystemProperties.NumNodes);
|
||||
|
||||
// setting memory flags with default values , can be modified according to needs
|
||||
m_MemoryFlags.ui32.NonPaged = 0; // Paged
|
||||
m_MemoryFlags.ui32.CachePolicy = HSA_CACHING_NONCACHED; // Non cached
|
||||
m_MemoryFlags.ui32.ReadOnly = 0; // Read/Write
|
||||
m_MemoryFlags.ui32.PageSize = HSA_PAGE_SIZE_4KB; // 4KB page
|
||||
m_MemoryFlags.ui32.HostAccess = 1; // host accessible
|
||||
m_MemoryFlags.ui32.NoSubstitute = 0; // fall back to node 0 if needed
|
||||
m_MemoryFlags.ui32.GDSMemory = 0;
|
||||
m_MemoryFlags.ui32.Scratch = 0;
|
||||
|
||||
const HsaNodeProperties *nodeProperties = m_NodeInfo.HsaDefaultGPUNodeProperties();
|
||||
ASSERT_NOTNULL(nodeProperties) << "failed to get HSA default GPU Node properties";
|
||||
|
||||
g_TestGPUFamilyId = FamilyIdFromNode(nodeProperties);
|
||||
|
||||
m_FamilyId = g_TestGPUFamilyId;
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDBaseComponentTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtReleaseSystemProperties());
|
||||
ASSERT_SUCCESS(hsaKmtCloseKFD());
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
HSAuint64 KFDBaseComponentTest::GetSysMemSize() {
|
||||
const HsaNodeProperties *nodeProps;
|
||||
HsaMemoryProperties cpuMemoryProps;
|
||||
HSAuint64 systemMemSize = 0;
|
||||
|
||||
/* Find System Memory size */
|
||||
for (unsigned node = 0; node < m_SystemProperties.NumNodes; node++) {
|
||||
nodeProps = m_NodeInfo.GetNodeProperties(node);
|
||||
if (nodeProps != NULL && nodeProps->NumCPUCores > 0 && nodeProps->NumMemoryBanks > 0) {
|
||||
/* For NUMA nodes, memory is distributed among differnt nodes.
|
||||
* Compute total system memory size. KFD driver also computes
|
||||
* the system memory (si_meminfo) similarly
|
||||
*/
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeMemoryProperties(node, 1, &cpuMemoryProps));
|
||||
systemMemSize += cpuMemoryProps.SizeInBytes;
|
||||
}
|
||||
}
|
||||
|
||||
return systemMemSize;
|
||||
}
|
||||
|
||||
HSAuint64 KFDBaseComponentTest::GetVramSize(int defaultGPUNode) {
|
||||
const HsaNodeProperties *nodeProps;
|
||||
|
||||
/* Find framebuffer size */
|
||||
nodeProps = m_NodeInfo.GetNodeProperties(defaultGPUNode);
|
||||
EXPECT_NE((const HsaNodeProperties *)NULL, nodeProps);
|
||||
HSAuint32 numBanks = nodeProps->NumMemoryBanks;
|
||||
HsaMemoryProperties memoryProps[numBanks];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeMemoryProperties(defaultGPUNode, numBanks, memoryProps));
|
||||
unsigned bank;
|
||||
for (bank = 0; bank < numBanks; bank++) {
|
||||
if (memoryProps[bank].HeapType == HSA_HEAPTYPE_FRAME_BUFFER_PRIVATE
|
||||
|| memoryProps[bank].HeapType == HSA_HEAPTYPE_FRAME_BUFFER_PUBLIC)
|
||||
return memoryProps[bank].SizeInBytes;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "hsakmt.h"
|
||||
#include "OSWrapper.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
#ifndef __KFD_BASE_COMPONENT_TEST__H__
|
||||
#define __KFD_BASE_COMPONENT_TEST__H__
|
||||
|
||||
// @class KFDBaseComponentTest
|
||||
class KFDBaseComponentTest : public testing::Test {
|
||||
public:
|
||||
KFDBaseComponentTest(void) { m_MemoryFlags.Value = 0; }
|
||||
~KFDBaseComponentTest(void) {}
|
||||
|
||||
HSAuint64 GetSysMemSize();
|
||||
HSAuint64 GetVramSize(int defaultGPUNode);
|
||||
|
||||
protected:
|
||||
HsaVersionInfo m_VersionInfo;
|
||||
HsaSystemProperties m_SystemProperties;
|
||||
unsigned int m_FamilyId;
|
||||
HsaMemFlags m_MemoryFlags;
|
||||
HsaNodeInfo m_NodeInfo;
|
||||
|
||||
// @brief SetUpTestCase function run before the first test that uses KFDOpenCloseKFDTest class fixture, and opens KFD.
|
||||
static void SetUpTestCase();
|
||||
// @brief TearDownTestCase function run after the last test from KFDOpenCloseKFDTest class fixture and calls close KFD.
|
||||
static void TearDownTestCase();
|
||||
// @brief SetUp function run before every test that uses KFDOpenCloseKFDTest class fixture, sets all common settings for the tests.
|
||||
virtual void SetUp();
|
||||
// @brief TearDown function run after every test that uses KFDOpenCloseKFDTest class fixture.
|
||||
virtual void TearDown();
|
||||
};
|
||||
|
||||
#endif // __KFD_BASE_COMPONENT_TEST__H__
|
||||
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDCWSRTest.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
static const char* iterate_isa_gfx8 = \
|
||||
"\
|
||||
shader iterate_isa\n\
|
||||
asic(VI)\n\
|
||||
type(CS)\n\
|
||||
/*copy the parameters from scalar registers to vector registers*/\n\
|
||||
v_mov_b32 v1, s1\n\
|
||||
v_mov_b32 v2, s2\n\
|
||||
v_mov_b32 v3, s3\n\
|
||||
/*v0 stores the workitem ID inside the workgroup, use it to caculate the dest*/\n\
|
||||
// v_lshlrev_b32 v0, 2, v0\n\
|
||||
// v_add_u32 v2, vcc, v0, v2\n\
|
||||
v_mov_b32 v0, s0\n\
|
||||
flat_load_dword v4, v[0:1] slc /*load target iteration value*/\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
v_mov_b32 v5, 0\n\
|
||||
LOOP:\n\
|
||||
v_add_u32 v5, vcc, 1, v5\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
/*compare the result value (v5) to iteration value (v4), and jump if equal (i.e. if VCC is not zero after the comparison)*/\n\
|
||||
v_cmp_lt_u32 vcc, v5, v4\n\
|
||||
s_cbranch_vccnz LOOP\n\
|
||||
flat_store_dword v[2,3], v5\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
s_endpgm\n\
|
||||
end\n\
|
||||
";
|
||||
|
||||
static const char* iterate_isa_gfx9 = \
|
||||
"\
|
||||
shader iterate_isa\n\
|
||||
asic(GFX9)\n\
|
||||
type(CS)\n\
|
||||
/*copy the parameters from scalar registers to vector registers*/\n\
|
||||
v_mov_b32 v0, s0\n\
|
||||
v_mov_b32 v1, s1\n\
|
||||
v_mov_b32 v2, s2\n\
|
||||
v_mov_b32 v3, s3\n\
|
||||
flat_load_dword v4, v[0:1] slc /*load target iteration value*/\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
v_mov_b32 v5, 0\n\
|
||||
LOOP:\n\
|
||||
v_add_co_u32 v5, vcc, 1, v5\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
/*compare the result value (v5) to iteration value (v4), and jump if equal (i.e. if VCC is not zero after the comparison)*/\n\
|
||||
v_cmp_lt_u32 vcc, v5, v4\n\
|
||||
s_cbranch_vccnz LOOP\n\
|
||||
flat_store_dword v[2,3], v5\n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
s_endpgm\n\
|
||||
end\n\
|
||||
";
|
||||
|
||||
/*
|
||||
v[0:1] = target iteration value
|
||||
v[2:3] = iterate result
|
||||
*/
|
||||
|
||||
void KFDCWSRTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
m_pIsaGen = IsaGenerator::Create(m_FamilyId);
|
||||
|
||||
// TODO: Seems in the ISA, I can not get the workitem_id as expected, so I can not set the destination based on workitem_id.
|
||||
// Set the wave_num to 1 for now as a workarpound. Will set it to 8 or even 256 in the future.
|
||||
wave_number = 1;
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDCWSRTest::TearDown() {
|
||||
ROUTINE_START
|
||||
if (m_pIsaGen)
|
||||
delete m_pIsaGen;
|
||||
m_pIsaGen = NULL;
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
/**
|
||||
* KFDCWSRTest.BasicTest
|
||||
*
|
||||
* This test dispatches the loop_inc_isa shader and lets it run, ensuring its destination pointer gets incremented.
|
||||
* It then triggers CWSR and ensures the shader stops running.
|
||||
* It then resumes the shader, ensures that it's running again and terminates it.
|
||||
*/
|
||||
|
||||
TEST_F(KFDCWSRTest, BasicTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
|
||||
if (m_FamilyId >= FAMILY_VI) {
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HsaMemoryBuffer iterateBuf(PAGE_SIZE, defaultGPUNode, true, false, false);
|
||||
HsaMemoryBuffer resultBuf(PAGE_SIZE, defaultGPUNode, true, false, false);
|
||||
|
||||
unsigned int* iter = iterateBuf.As<unsigned int*>();
|
||||
unsigned int* result = resultBuf.As<unsigned int*>();
|
||||
|
||||
m_pIsaGen->CompileShader((m_FamilyId >= FAMILY_AI) ? iterate_isa_gfx9 : iterate_isa_gfx8 ,
|
||||
"iterate_isa", isaBuffer);
|
||||
|
||||
PM4Queue queue1, queue2;
|
||||
|
||||
EXPECT_SUCCESS(queue1.Create(defaultGPUNode));
|
||||
|
||||
Dispatch *dispatch1, *dispatch2;
|
||||
|
||||
dispatch1 = new Dispatch(isaBuffer);
|
||||
dispatch2 = new Dispatch(isaBuffer);
|
||||
|
||||
dispatch1->SetArgs(&iter[0], &result[0]);
|
||||
dispatch1->SetDim(wave_number, 1, 1);
|
||||
dispatch2->SetArgs(&iter[1], &result[wave_number]);
|
||||
dispatch2->SetDim(wave_number, 1, 1);
|
||||
|
||||
iter[0] = 40000000;
|
||||
iter[1] = 20000000;
|
||||
|
||||
// submit the shader, queue1
|
||||
dispatch1->Submit(queue1);
|
||||
// Create queue2 during queue1 still running will trigger the CWSR
|
||||
EXPECT_SUCCESS(queue2.Create(defaultGPUNode));
|
||||
// submit the shader
|
||||
dispatch2->Submit(queue2);
|
||||
dispatch1->Sync();
|
||||
dispatch2->Sync();
|
||||
// ensure all the waves complete as expected
|
||||
int i;
|
||||
for (i = 0 ; i < wave_number; ++i) {
|
||||
if (result[i] != iter[0]) {
|
||||
LOG() << "Dispatch 1, work item " << i << ' ' << result[i] << std::endl;
|
||||
break;
|
||||
}
|
||||
if (result[i + wave_number] != iter[1]) {
|
||||
LOG() << "Dispatch 2, work item " << i << ' ' << result[i] << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
EXPECT_EQ(i, wave_number);
|
||||
|
||||
EXPECT_SUCCESS(queue1.Destroy());
|
||||
EXPECT_SUCCESS(queue2.Destroy());
|
||||
|
||||
delete dispatch1;
|
||||
delete dispatch2;
|
||||
|
||||
} else {
|
||||
LOG() << "Test is skipped for family ID 0x" << m_FamilyId << std::endl;
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2015-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_CWSR_TEST__H__
|
||||
#define __KFD_CWSR_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "PM4Queue.hpp"
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDCWSRTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDCWSRTest() :m_pIsaGen(NULL) {}
|
||||
~KFDCWSRTest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected: // members
|
||||
unsigned wave_number;
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __KFD_CWSR_TEST__H__
|
||||
@@ -0,0 +1,176 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDDBGTest.hpp"
|
||||
#include "KFDQMTest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
|
||||
static const char* loop_inc_isa = \
|
||||
"\
|
||||
shader loop_inc_isa\n\
|
||||
asic(VI)\n\
|
||||
type(CS)\n\
|
||||
vgpr_count(16)\n\
|
||||
trap_present(1)\n\
|
||||
/* TODO Enable here Address Watch Exception: */ \n\
|
||||
/*copy the parameters from scalar registers to vector registers*/\n\
|
||||
v_mov_b32 v0, s0\n\
|
||||
v_mov_b32 v1, s1\n\
|
||||
v_mov_b32 v2, s2\n\
|
||||
v_mov_b32 v3, s3\n\
|
||||
v_mov_b32 v5, 0 \n\
|
||||
/*Iteration 1*/\n\
|
||||
v_mov_b32 v4, -1\n\
|
||||
flat_atomic_inc v5, v[0:1], v4 glc \n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
flat_load_dword v8, v[2:3] \n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
v_cmp_gt_u32 vcc, 2, v5 \n\
|
||||
/*Iteration 2*/\n\
|
||||
v_mov_b32 v4, -1\n\
|
||||
flat_atomic_inc v5, v[0:1], v4 glc \n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
flat_load_dword v8, v[2:3] \n\
|
||||
s_waitcnt vmcnt(0)&lgkmcnt(0)\n\
|
||||
v_cmp_gt_u32 vcc, 2, v5 \n\
|
||||
/*Epilogue*/\n\
|
||||
v_mov_b32 v5, 0 \n\
|
||||
s_endpgm\n\
|
||||
\n\
|
||||
end\n\
|
||||
";
|
||||
|
||||
void KFDDBGTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
m_pIsaGen = IsaGenerator::Create(m_FamilyId);
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDDBGTest::TearDown() {
|
||||
ROUTINE_START
|
||||
if (m_pIsaGen)
|
||||
delete m_pIsaGen;
|
||||
m_pIsaGen = NULL;
|
||||
|
||||
/* reset the user trap handler */
|
||||
hsaKmtSetTrapHandler(m_NodeInfo.HsaDefaultGPUNode(), 0, 0, 0, 0);
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(KFDDBGTest, BasicAddressWatch) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
if (m_FamilyId >= FAMILY_VI) {
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
static const unsigned int TMA_TRAP_COUNT_OFFSET = 3;
|
||||
static const unsigned int TMA_TRAP_COUNT_VALUE = 3;
|
||||
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
// Allocate Buffers on System Memory
|
||||
HsaMemoryBuffer trapHandler(PAGE_SIZE*2, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HsaMemoryBuffer isaBuf(PAGE_SIZE, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HsaMemoryBuffer dstBuf(PAGE_SIZE*4, defaultGPUNode, true, false, false);
|
||||
HsaMemoryBuffer tmaBuf(PAGE_SIZE, defaultGPUNode, false, false, false);
|
||||
|
||||
// Get Address Watch TrapHandler
|
||||
m_pIsaGen->GetAwTrapHandler(trapHandler);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtSetTrapHandler(defaultGPUNode,
|
||||
trapHandler.As<void *>(),
|
||||
0x1000,
|
||||
tmaBuf.As<void*>(),
|
||||
0x1000));
|
||||
|
||||
m_pIsaGen->CompileShader(loop_inc_isa, "loop_inc_isa", isaBuf);
|
||||
PM4Queue queue, queue_flush;
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
ASSERT_SUCCESS(queue_flush.Create(defaultGPUNode));
|
||||
|
||||
// Set Address Watch Params
|
||||
// TODO: Set atchMode[1] to Atomic in case we want to test this mode.
|
||||
|
||||
HSA_DBG_WATCH_MODE WatchMode[2];
|
||||
HSAuint64 WatchAddress[2];
|
||||
HSAuint64 WatchMask[2];
|
||||
HSAKMT_STATUS AddressWatchSuccess;
|
||||
HSAuint64 AddressMask64 = 0x0;
|
||||
unsigned char *secDstBuf = (unsigned char *)dstBuf.As<void*>() + 8192;
|
||||
|
||||
WatchMode[0] = HSA_DBG_WATCH_ALL;
|
||||
WatchAddress[0] = (HSAuint64) dstBuf.As<void*>() & (~AddressMask64);
|
||||
WatchMask[0] = ~AddressMask64;
|
||||
WatchMode[1] = HSA_DBG_WATCH_ALL;
|
||||
WatchAddress[1] = (HSAuint64)secDstBuf & (~AddressMask64);
|
||||
WatchMask[1] = ~AddressMask64;
|
||||
|
||||
queue_flush.PlaceAndSubmitPacket(PM4WriteDataPacket(dstBuf.As<unsigned int*>(), 0x0, 0x0));
|
||||
queue_flush.PlaceAndSubmitPacket(PM4WriteDataPacket((unsigned int *)secDstBuf, 0x0, 0x0));
|
||||
Delay(50);
|
||||
ASSERT_SUCCESS(hsaKmtDbgRegister(defaultGPUNode));
|
||||
|
||||
AddressWatchSuccess = hsaKmtDbgAddressWatch(
|
||||
defaultGPUNode, // IN
|
||||
2, // # watch points
|
||||
&WatchMode[0], // IN
|
||||
(void **) &WatchAddress[0], // IN
|
||||
&WatchMask[0], // IN, optional
|
||||
NULL // IN, optional
|
||||
);
|
||||
|
||||
EXPECT_EQ(AddressWatchSuccess, HSAKMT_STATUS_SUCCESS);
|
||||
|
||||
Dispatch dispatch(isaBuf);
|
||||
dispatch.SetArgs(dstBuf.As<void*>(), (void *)secDstBuf);
|
||||
dispatch.SetDim(1, 1, 1);
|
||||
|
||||
// TODO: use Memory ordering rules w/ atomics
|
||||
// for host-GPU memory syncs.
|
||||
// set to: std::memory_order_seq_cst
|
||||
|
||||
dispatch.Submit(queue);
|
||||
|
||||
Delay(50);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
// Check that we got trap handler calls due to add watch triggers
|
||||
ASSERT_GE(*(tmaBuf.As<unsigned int*>()+ TMA_TRAP_COUNT_OFFSET), TMA_TRAP_COUNT_VALUE);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtDbgUnregister(defaultGPUNode));
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
ASSERT_SUCCESS(queue_flush.Destroy());
|
||||
} else {
|
||||
LOG() << "Test is skipped for family ID 0x" << m_FamilyId << std::endl;
|
||||
}
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_DBG_TEST__H__
|
||||
#define __KFD_DBG_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDDBGTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDDBGTest() :m_pIsaGen(NULL) {}
|
||||
~KFDDBGTest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected: // members
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __KFD_DBG_TEST__H__
|
||||
@@ -0,0 +1,285 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <math.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "KFDEventTest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
|
||||
|
||||
void KFDEventTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
m_pHsaEvent = NULL;
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDEventTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
// not all tests create event, destroy only if there is one
|
||||
if (m_pHsaEvent != NULL) {
|
||||
// hsaKmtDestroyEvent moved to TearDown to make sure it is being called
|
||||
EXPECT_SUCCESS(hsaKmtDestroyEvent(m_pHsaEvent));
|
||||
}
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(KFDEventTest, CreateDestroyEvent) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &m_pHsaEvent));
|
||||
EXPECT_NE(0, m_pHsaEvent->EventData.HWData2);
|
||||
|
||||
// destroy event is being called in test TearDown
|
||||
TEST_END;
|
||||
}
|
||||
|
||||
TEST_F(KFDEventTest, CreateMaxEvents) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
static const unsigned int MAX_EVENT_NUMBER = 256;
|
||||
|
||||
HsaEvent* pHsaEvent[MAX_EVENT_NUMBER];
|
||||
|
||||
unsigned int i = 0;
|
||||
|
||||
for (i = 0; i < MAX_EVENT_NUMBER; i++) {
|
||||
pHsaEvent[i] = NULL;
|
||||
ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &pHsaEvent[i]));
|
||||
}
|
||||
|
||||
for (i = 0; i < MAX_EVENT_NUMBER; i++) {
|
||||
EXPECT_SUCCESS(hsaKmtDestroyEvent(pHsaEvent[i]));
|
||||
}
|
||||
|
||||
TEST_END;
|
||||
}
|
||||
|
||||
TEST_F(KFDEventTest, SignalEvent) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_NodeInfo.HsaDefaultGPUNode(), &m_pHsaEvent));
|
||||
ASSERT_NE(0, m_pHsaEvent->EventData.HWData2);
|
||||
|
||||
PM4Queue queue;
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4ReleaseMemoryPacket(false, m_pHsaEvent->EventData.HWData2, m_pHsaEvent->EventId));
|
||||
|
||||
queue.Wait4PacketConsumption();
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtWaitOnEvent(m_pHsaEvent, g_TestTimeOut));
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
TEST_END;
|
||||
}
|
||||
|
||||
static uint64_t gettime() {
|
||||
struct timespec ts;
|
||||
clock_gettime(CLOCK_MONOTONIC, &ts);
|
||||
return ((int64_t)ts.tv_sec) * 1000 * 1000 * 1000 + ts.tv_nsec;
|
||||
}
|
||||
|
||||
static inline double pow2_round_up(int num) {
|
||||
return pow(2, ceil(log(num)/log(2)));
|
||||
}
|
||||
|
||||
class QueueAndSignalBenchmark {
|
||||
private:
|
||||
static const int HISTORY_SIZE = 100;
|
||||
|
||||
int mNumEvents;
|
||||
int mHistorySlot;
|
||||
uint64_t mTimeHistory[HISTORY_SIZE];
|
||||
uint64_t mLatHistory[HISTORY_SIZE];
|
||||
|
||||
public:
|
||||
QueueAndSignalBenchmark(int events) : mNumEvents(events), mHistorySlot(0) {
|
||||
memset(mTimeHistory, 0, sizeof(mTimeHistory));
|
||||
memset(mLatHistory, 0, sizeof(mLatHistory));
|
||||
}
|
||||
|
||||
int queueAndSignalEvents(int node, int eventCount, uint64_t &time, uint64_t &latency) {
|
||||
int r;
|
||||
uint64_t startTime;
|
||||
PM4Queue queue;
|
||||
|
||||
HsaEvent** pHsaEvent = (HsaEvent**) calloc(eventCount, sizeof(HsaEvent*));
|
||||
size_t packetSize = PM4ReleaseMemoryPacket(false, 0, 0).SizeInBytes();
|
||||
int qSize = fmax(PAGE_SIZE, pow2_round_up(packetSize*eventCount + 1));
|
||||
|
||||
time = 0;
|
||||
|
||||
r = queue.Create(node, qSize);
|
||||
if (r != HSAKMT_STATUS_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
r = CreateQueueTypeEvent(false, false, node, &pHsaEvent[i]);
|
||||
if (r != HSAKMT_STATUS_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
queue.PlacePacket(PM4ReleaseMemoryPacket(false, pHsaEvent[i]->EventData.HWData2, pHsaEvent[i]->EventId));
|
||||
}
|
||||
|
||||
startTime = gettime();
|
||||
queue.SubmitPacket();
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
r = hsaKmtWaitOnEvent(pHsaEvent[i], g_TestTimeOut);
|
||||
|
||||
if (r != HSAKMT_STATUS_SUCCESS)
|
||||
goto exit;
|
||||
|
||||
if (i == 0)
|
||||
latency = gettime() - startTime;
|
||||
}
|
||||
time = gettime() - startTime;
|
||||
|
||||
exit:
|
||||
for (int i = 0; i < eventCount; i++) {
|
||||
if (pHsaEvent[i])
|
||||
hsaKmtDestroyEvent(pHsaEvent[i]);
|
||||
}
|
||||
queue.Destroy();
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
void run(int node) {
|
||||
int r = 0;
|
||||
uint64_t time = 0, latency = 0;
|
||||
uint64_t avgLat = 0, avgTime = 0;
|
||||
uint64_t minTime = ULONG_MAX, maxTime = 0;
|
||||
uint64_t minLat = ULONG_MAX, maxLat = 0;
|
||||
|
||||
r = queueAndSignalEvents(node, mNumEvents, time, latency);
|
||||
ASSERT_EQ(r, HSAKMT_STATUS_SUCCESS);
|
||||
|
||||
mTimeHistory[mHistorySlot%HISTORY_SIZE] = time;
|
||||
mLatHistory[mHistorySlot%HISTORY_SIZE] = latency;
|
||||
|
||||
for (int i = 0; i < HISTORY_SIZE; i++) {
|
||||
minTime = mTimeHistory[i] < minTime ? mTimeHistory[i] : minTime;
|
||||
maxTime = mTimeHistory[i] > maxTime ? mTimeHistory[i] : maxTime;
|
||||
avgTime += mTimeHistory[i];
|
||||
|
||||
minLat = mLatHistory[i] < minLat ? mLatHistory[i] : minLat;
|
||||
maxLat = mLatHistory[i] > maxLat ? mLatHistory[i] : maxLat;
|
||||
avgLat += mLatHistory[i];
|
||||
}
|
||||
|
||||
avgTime /= HISTORY_SIZE;
|
||||
avgLat /= HISTORY_SIZE;
|
||||
mHistorySlot++;
|
||||
|
||||
printf("\033[KEvents: %d History: %d/%d\n", mNumEvents, mHistorySlot, HISTORY_SIZE);
|
||||
printf("\033[KMin Latency: %f ms\n", (float)minLat/1000000);
|
||||
printf("\033[KMax Latency: %f ms\n", (float)maxLat/1000000);
|
||||
printf("\033[KAvg Latency: %f ms\n", (float)avgLat/1000000);
|
||||
printf("\033[K Min Rate: %f IH/ms\n", ((float)mNumEvents)/maxTime*1000000);
|
||||
printf("\033[K Max Rate: %f IH/ms\n", ((float)mNumEvents)/minTime*1000000);
|
||||
printf("\033[K Avg Rate: %f IH/ms\n", ((float)mNumEvents)/avgTime*1000000);
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(KFDEventTest, MeasureInterruptConsumption) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
QueueAndSignalBenchmark latencyBench(128);
|
||||
QueueAndSignalBenchmark sustainedBench(4096);
|
||||
|
||||
printf("\033[2J");
|
||||
while (true) {
|
||||
printf("\033[H");
|
||||
printf("--------------------------\n");
|
||||
latencyBench.run(m_NodeInfo.HsaDefaultGPUNode());
|
||||
printf("--------------------------\n");
|
||||
sustainedBench.run(m_NodeInfo.HsaDefaultGPUNode());
|
||||
printf("--------------------------\n");
|
||||
}
|
||||
|
||||
TEST_END;
|
||||
}
|
||||
|
||||
TEST_F(KFDEventTest, SignalMaxEvents) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
static const unsigned int MAX_EVENT_NUMBER = 4096;
|
||||
uint64_t time, latency;
|
||||
|
||||
QueueAndSignalBenchmark maxEventTest(MAX_EVENT_NUMBER);
|
||||
maxEventTest.queueAndSignalEvents(m_NodeInfo.HsaDefaultGPUNode(), MAX_EVENT_NUMBER,
|
||||
time, latency);
|
||||
|
||||
TEST_END;
|
||||
}
|
||||
|
||||
TEST_F(KFDEventTest, SignalMultipleEventsWaitForAll) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
static const unsigned int EVENT_NUMBER = 64; // 64 is the maximum for hsaKmtWaitOnMultipleEvents
|
||||
static const unsigned int WAIT_BETWEEN_SUBMISSIONS_MS = 50;
|
||||
|
||||
HsaEvent* pHsaEvent[EVENT_NUMBER];
|
||||
unsigned int i = 0;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
for (i = 0; i < EVENT_NUMBER; i++) {
|
||||
pHsaEvent[i] = NULL;
|
||||
ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, defaultGPUNode, &pHsaEvent[i]));
|
||||
}
|
||||
|
||||
PM4Queue queue;
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
|
||||
unsigned int pktSizeDwords = 0;
|
||||
for (i = 0; i < EVENT_NUMBER; i++) {
|
||||
queue.PlaceAndSubmitPacket(PM4ReleaseMemoryPacket(false, pHsaEvent[i]->EventData.HWData2, pHsaEvent[i]->EventId));
|
||||
queue.Wait4PacketConsumption();
|
||||
|
||||
Delay(WAIT_BETWEEN_SUBMISSIONS_MS);
|
||||
}
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtWaitOnMultipleEvents(pHsaEvent, EVENT_NUMBER, true, g_TestTimeOut));
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
for (i = 0; i < EVENT_NUMBER; i++)
|
||||
EXPECT_SUCCESS(hsaKmtDestroyEvent(pHsaEvent[i]));
|
||||
|
||||
TEST_END;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
#ifndef __KFD_EVENT_TEST__H__
|
||||
#define __KFD_EVENT_TEST__H__
|
||||
|
||||
class KFDEventTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDEventTest(void) {}
|
||||
~KFDEventTest(void) {}
|
||||
|
||||
// @brief SetUp function runs before every test in KFDEventTest.
|
||||
virtual void SetUp();
|
||||
// @brief TearDown function runs after every test in KFDEventTest.
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
static const unsigned int EVENT_TIMEOUT = 5000; // 5 seconds
|
||||
HsaEvent* m_pHsaEvent;
|
||||
};
|
||||
|
||||
#endif // __KFD_EVENT_TEST__H__
|
||||
@@ -0,0 +1,454 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include "KFDEvictTest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
#define N_PROCESSES (8) /* number of processes running in parallel, at least 2 */
|
||||
#define ALLOCATE_BUF_SIZE_MB (64)
|
||||
#define ALLOCATE_RETRY_TIMES (3)
|
||||
|
||||
HSAint32 KFDEvictTest::GetBufferCounter(HSAuint64 vramSize, HSAuint64 vramBufSize) {
|
||||
HSAuint64 vramBufSizeInPages = vramBufSize >> PAGE_SHIFT;
|
||||
HSAuint64 sysMemSize = GetSysMemSize();
|
||||
HSAuint64 size, sizeInPages;
|
||||
HSAuint32 count;
|
||||
|
||||
LOG() << "Found System RAM of " << std::dec << (sysMemSize >> 20) << "MB" << std::endl;
|
||||
|
||||
/* use one third of total system memory for eviction buffer to test
|
||||
* limit max allocate size to duoble of vramSize
|
||||
* count is zero if not enough memory (sysMemSize/3 + vramSize) < (vramBufSize * N_PROCESSES)
|
||||
*/
|
||||
size = sysMemSize/3 + vramSize;
|
||||
size = size > vramSize<<1 ? vramSize<<1 : size;
|
||||
sizeInPages = size >> PAGE_SHIFT;
|
||||
count = sizeInPages / (vramBufSizeInPages * N_PROCESSES);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
void KFDEvictTest::AllocBuffers(HSAuint32 defaultGPUNode, HSAuint32 count, HSAuint64 vramBufSize,
|
||||
std::vector<void *> &pBuffers) {
|
||||
HSAuint64 totalMB;
|
||||
|
||||
totalMB = N_PROCESSES*count*(vramBufSize>>20);
|
||||
if (m_IsParent) {
|
||||
LOG() << "Testing " << N_PROCESSES << "*" << count << "*" << (vramBufSize>>20) << "(="<< totalMB << ")MB" << std::endl;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS ret;
|
||||
HSAuint32 retry = 0;
|
||||
|
||||
m_Flags.Value = 0;
|
||||
m_Flags.ui32.PageSize = HSA_PAGE_SIZE_4KB;
|
||||
m_Flags.ui32.HostAccess = 0;
|
||||
m_Flags.ui32.NonPaged = 1;
|
||||
|
||||
for (HSAuint32 i = 0; i < count; ) {
|
||||
ret = hsaKmtAllocMemory(defaultGPUNode, vramBufSize, m_Flags, &m_pBuf);
|
||||
if (ret == HSAKMT_STATUS_SUCCESS) {
|
||||
if (is_dgpu()) {
|
||||
if (hsaKmtMapMemoryToGPU(m_pBuf, vramBufSize, NULL) == HSAKMT_STATUS_ERROR) {
|
||||
EXPECT_SUCCESS(hsaKmtFreeMemory(m_pBuf, vramBufSize));
|
||||
break;
|
||||
}
|
||||
}
|
||||
pBuffers.push_back(m_pBuf);
|
||||
|
||||
i++;
|
||||
retry = 0;
|
||||
} else {
|
||||
if (retry++ > ALLOCATE_RETRY_TIMES) {
|
||||
break;
|
||||
}
|
||||
|
||||
/* wait for 1 second to try allocate again */
|
||||
sleep(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KFDEvictTest::FreeBuffers(std::vector<void *> &pBuffers, HSAuint64 vramBufSize) {
|
||||
for (HSAuint32 i = 0; i < pBuffers.size(); i++) {
|
||||
m_pBuf = pBuffers[i];
|
||||
if (m_pBuf != NULL) {
|
||||
if (is_dgpu())
|
||||
EXPECT_SUCCESS(hsaKmtUnmapMemoryToGPU(m_pBuf));
|
||||
EXPECT_SUCCESS(hsaKmtFreeMemory(m_pBuf, vramBufSize));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void KFDEvictTest::ForkChildProcesses(int nprocesses) {
|
||||
int i;
|
||||
|
||||
for (i = 0; i < nprocesses - 1; ++i) {
|
||||
pid_t pid = fork();
|
||||
ASSERT_GE(pid, 0);
|
||||
|
||||
if (pid == 0) {
|
||||
/* Child process */
|
||||
/* Cleanup file descriptors copied from parent process
|
||||
* then call SetUp->hsaKmtOpenKFD to create new process
|
||||
*/
|
||||
m_psName = "Test process " + std::to_string(i) + " ";
|
||||
TearDown();
|
||||
SetUp();
|
||||
m_ChildPids.clear();
|
||||
m_IsParent = false;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Parent process */
|
||||
m_ChildPids.push_back(pid);
|
||||
}
|
||||
|
||||
m_psName = "Test process " + std::to_string(i) + " ";
|
||||
}
|
||||
|
||||
void KFDEvictTest::WaitChildProcesses() {
|
||||
if (m_IsParent) {
|
||||
/* only run by parent process */
|
||||
int childStatus;
|
||||
int childExitOkNum = 0;
|
||||
int size = m_ChildPids.size();
|
||||
|
||||
for (HSAuint32 i = 0; i < size; i++) {
|
||||
pid_t pid = m_ChildPids.front();
|
||||
|
||||
waitpid(pid, &childStatus, 0);
|
||||
if (WIFEXITED(childStatus) == 1 && WEXITSTATUS(childStatus) == 0)
|
||||
childExitOkNum++;
|
||||
|
||||
m_ChildPids.erase(m_ChildPids.begin());
|
||||
}
|
||||
|
||||
ASSERT_EQ(childExitOkNum, size);
|
||||
}
|
||||
|
||||
/* child process or parent process finished successfullly */
|
||||
m_ChildStatus = HSAKMT_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* Evict and restore procedure basic test
|
||||
*
|
||||
* Use N_PROCESSES processes to allocate vram buf size larger than total vram size
|
||||
*
|
||||
* ALLOCATE_BUF_SIZE_MB buf allocation size
|
||||
*
|
||||
* number of buf is equal to (vramSizeMB / (vramBufSizeMB * N_PROCESSES) ) + 8
|
||||
* Total vram all processes allocated: 8GB for 4GB Fiji, and 20GB for 16GB Vega10
|
||||
*
|
||||
* many times of eviction and restore will happen:
|
||||
* ttm will evict buffers of another process if not enough free vram
|
||||
* process restore will evict buffers of another process
|
||||
*
|
||||
* Sometimes the allocate may fail (maybe that is normal)
|
||||
* ALLOCATE_RETRY_TIMES max retry times to allocate
|
||||
*
|
||||
* This is basic test, no queue so vram are not used by GPU during test
|
||||
*
|
||||
* Todo:
|
||||
* - Synchronization between the processes, so they know for sure when
|
||||
* they are done allocating memory
|
||||
*/
|
||||
TEST_F(KFDEvictTest, BasicTest) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
HSAuint32 defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
HSAuint64 vramBufSize = ALLOCATE_BUF_SIZE_MB * 1024 * 1024;
|
||||
|
||||
HSAuint64 vramSize = GetVramSize(defaultGPUNode);
|
||||
|
||||
if (!vramSize) {
|
||||
LOG() << "No VRAM found, skipping the test" << std::endl;
|
||||
return;
|
||||
} else {
|
||||
LOG() << "Found VRAM of " << std::dec << (vramSize >> 20) << "MB" << std::endl;
|
||||
}
|
||||
|
||||
HSAuint32 count = GetBufferCounter(vramSize, vramBufSize);
|
||||
if (count == 0) {
|
||||
LOG() << "Not enough system memory, skipping the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Fork the child processes */
|
||||
ForkChildProcesses(N_PROCESSES);
|
||||
|
||||
std::vector<void *> pBuffers;
|
||||
AllocBuffers(defaultGPUNode, count, vramBufSize, pBuffers);
|
||||
|
||||
/* wait for other processes to finish allocation, then free buffer */
|
||||
sleep(ALLOCATE_RETRY_TIMES);
|
||||
|
||||
LOG() << m_psName << "free buffer" << std::endl;
|
||||
FreeBuffers(pBuffers, vramBufSize);
|
||||
|
||||
WaitChildProcesses();
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Shader to read local buffers using multiple wavefronts in parallel
|
||||
* until address buffer is filled with specific value 0x5678 by host program,
|
||||
* then each wavefront fills value 0x5678 at corresponding result buffer and quit
|
||||
*
|
||||
* initial state:
|
||||
* s[0:1] - address buffer base address
|
||||
* s[2:3] - result buffer base address
|
||||
* s4 - workgroup id
|
||||
* v0 - workitem id, always 0 because NUM_THREADS_X(number of threads) in workgroup set to 1
|
||||
* registers:
|
||||
* v0 - calculated workitem id, v0 = v0 + s4 * NUM_THREADS_X
|
||||
* v[2:3] - address of corresponding local buf address offset: s[0:1] + v0 * 8
|
||||
* v[4:5] - corresponding output buf address: s[2:3] + v0 * 4
|
||||
* v[6:7] - local buf address used for read test
|
||||
*/
|
||||
static const char* gfx9_ReadMemory =
|
||||
"\
|
||||
shader ReadMemory\n\
|
||||
asic(GFX9)\n\
|
||||
type(CS)\n\
|
||||
\n\
|
||||
// compute address of corresponding output buffer\n\
|
||||
v_mov_b32 v0, s4 // use workgroup id as index\n\
|
||||
v_lshlrev_b32 v0, 2, v0 // v0 *= 4\n\
|
||||
v_add_co_u32 v4, vcc, s2, v0 // v[4:5] = s[2:3] + v0 * 4\n\
|
||||
v_mov_b32 v5, s3\n\
|
||||
v_add_u32 v5, vcc_lo, v5\n\
|
||||
\n\
|
||||
// compute input buffer offset used to store corresponding local buffer address\n\
|
||||
v_lshlrev_b32 v0, 1, v0 // v0 *= 8\n\
|
||||
v_add_co_u32 v2, vcc, s0, v0 // v[2:3] = s[0:1] + v0 * 8\n\
|
||||
v_mov_b32 v3, s1\n\
|
||||
v_add_u32 v3, vcc_lo, v3\n\
|
||||
\n\
|
||||
// load 64bit local buffer address stored at v[2:3] to v[6:7]\n\
|
||||
flat_load_dwordx2 v[6:7], v[2:3] slc\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory reads to finish\n\
|
||||
\n\
|
||||
v_mov_b32 v8, 0x5678\n\
|
||||
s_movk_i32 s8, 0x5678\n\
|
||||
L_REPEAT:\n\
|
||||
s_load_dword s16, s[0:1], 0x0 glc\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory reads to finish\n\
|
||||
s_cmp_eq_i32 s16, s8\n\
|
||||
s_cbranch_scc1 L_QUIT // if notified to quit by host\n\
|
||||
// loop read 64M local buffer starting at v[6:7]\n\
|
||||
// every 4k page only read once\n\
|
||||
v_mov_b32 v9, 0\n\
|
||||
v_mov_b32 v10, 0x1000 // 4k page\n\
|
||||
v_mov_b32 v11, 0x4000000 // 64M size\n\
|
||||
v_mov_b32 v12, v6\n\
|
||||
v_mov_b32 v13, v7\n\
|
||||
L_LOOP_READ:\n\
|
||||
flat_load_dwordx2 v[14:15], v[12:13] slc\n\
|
||||
v_add_u32 v9, v9, v10 \n\
|
||||
v_add_co_u32 v12, vcc, v12, v10\n\
|
||||
v_add_u32 v13, vcc_lo, v13\n\
|
||||
v_cmp_lt_u32 vcc, v9, v11\n\
|
||||
s_cbranch_vccnz L_LOOP_READ\n\
|
||||
s_branch L_REPEAT\n\
|
||||
L_QUIT:\n\
|
||||
flat_store_dword v[4:5], v8\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory writes to finish\n\
|
||||
s_endpgm\n\
|
||||
end\n\
|
||||
";
|
||||
|
||||
static const char* gfx8_ReadMemory =
|
||||
"\
|
||||
shader ReadMemory\n\
|
||||
asic(VI)\n\
|
||||
type(CS)\n\
|
||||
\n\
|
||||
// compute address of corresponding output buffer\n\
|
||||
v_mov_b32 v0, s4 // use workgroup id as index\n\
|
||||
v_lshlrev_b32 v0, 2, v0 // v0 *= 4\n\
|
||||
v_add_u32 v4, vcc, s2, v0 // v[4:5] = s[2:3] + v0 * 4\n\
|
||||
v_mov_b32 v5, s3\n\
|
||||
v_addc_u32 v5, vcc, v5, 0, vcc\n\
|
||||
\n\
|
||||
// compute input buffer offset used to store corresponding local buffer address\n\
|
||||
v_lshlrev_b32 v0, 1, v0 // v0 *= 8\n\
|
||||
v_add_u32 v2, vcc, s0, v0 // v[2:3] = s[0:1] + v0 * 8\n\
|
||||
v_mov_b32 v3, s1\n\
|
||||
v_addc_u32 v3, vcc, v3, 0, vcc\n\
|
||||
\n\
|
||||
// load 64bit local buffer address stored at v[2:3] to v[6:7]\n\
|
||||
flat_load_dwordx2 v[6:7], v[2:3] slc\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory reads to finish\n\
|
||||
\n\
|
||||
v_mov_b32 v8, 0x5678\n\
|
||||
s_movk_i32 s8, 0x5678\n\
|
||||
L_REPEAT:\n\
|
||||
s_load_dword s16, s[0:1], 0x0 glc\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory reads to finish\n\
|
||||
s_cmp_eq_i32 s16, s8\n\
|
||||
s_cbranch_scc1 L_QUIT // if notified to quit by host\n\
|
||||
// loop read 64M local buffer starting at v[6:7]\n\
|
||||
// every 4k page only read once\n\
|
||||
v_mov_b32 v9, 0\n\
|
||||
v_mov_b32 v10, 0x1000 // 4k page\n\
|
||||
v_mov_b32 v11, 0x4000000 // 64M size\n\
|
||||
v_mov_b32 v12, v6\n\
|
||||
v_mov_b32 v13, v7\n\
|
||||
L_LOOP_READ:\n\
|
||||
flat_load_dwordx2 v[14:15], v[12:13] slc\n\
|
||||
v_add_u32 v9, vcc, v9, v10 \n\
|
||||
v_add_u32 v12, vcc, v12, v10\n\
|
||||
v_addc_u32 v13, vcc, v13, 0, vcc\n\
|
||||
v_cmp_lt_u32 vcc, v9, v11\n\
|
||||
s_cbranch_vccnz L_LOOP_READ\n\
|
||||
s_branch L_REPEAT\n\
|
||||
L_QUIT:\n\
|
||||
flat_store_dword v[4:5], v8\n\
|
||||
s_waitcnt vmcnt(0) & lgkmcnt(0) // wait for memory writes to finish\n\
|
||||
s_endpgm\n\
|
||||
end\n\
|
||||
";
|
||||
|
||||
std::string KFDEvictTest::CreateShader() {
|
||||
if (m_FamilyId >= FAMILY_AI)
|
||||
return gfx9_ReadMemory;
|
||||
else
|
||||
return gfx8_ReadMemory;
|
||||
}
|
||||
|
||||
/* Evict and restore queue test
|
||||
*
|
||||
* N_PROCESSES processes read all local buffers in parallel while buffers are evicted and restored
|
||||
* If GPU vm page fault happens, then test shader will stop and failed to write specific value
|
||||
* at dest buffer. Test will report failed.
|
||||
*
|
||||
* Steps:
|
||||
* - fork N_PROCESSES processes, each process does the same below
|
||||
* - allocate local buffers, each buffer size is 64MB
|
||||
* - allocate zero initialized host access address buffer and result buffer
|
||||
* address buffer to pass address of local buffers to shader
|
||||
* result buffer to store shader output result
|
||||
* - submit queue to run ReadMemory shader
|
||||
* - shader start m_DimX wavefronts, each wavefront keep reading one local buffer
|
||||
* - notify shader to quit
|
||||
* - check result buffer with specific value to confirm all wavefronts quit normally
|
||||
*/
|
||||
TEST_F(KFDEvictTest, QueueTest) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
HSAuint32 defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
HSAuint64 vramBufSize = ALLOCATE_BUF_SIZE_MB * 1024 * 1024;
|
||||
|
||||
const HsaNodeProperties *pNodeProperties = m_NodeInfo.HsaDefaultGPUNodeProperties();
|
||||
|
||||
/* Skip test for chip it doesn't have CWSR, which the test depends on */
|
||||
if (m_FamilyId < FAMILY_VI || isTonga(pNodeProperties)) {
|
||||
LOG() << std::hex << "Test is skipped for family ID 0x" << m_FamilyId << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HSAuint32 i;
|
||||
HSAuint64 vramSize = GetVramSize(defaultGPUNode);
|
||||
|
||||
if (!vramSize) {
|
||||
LOG() << "No VRAM found, skipping the test" << std::endl;
|
||||
return;
|
||||
} else {
|
||||
LOG() << "Found VRAM of " << std::dec << (vramSize >> 20) << "MB." << std::endl;
|
||||
}
|
||||
|
||||
HSAuint32 count = GetBufferCounter(vramSize, vramBufSize);
|
||||
if (count == 0) {
|
||||
LOG() << "Not enough system memory, skipping the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
/* assert all buffer address can be stored within one page
|
||||
* because only one page host memory srcBuf is allocated
|
||||
*/
|
||||
ASSERT_LE(count, PAGE_SIZE/sizeof(unsigned int *));
|
||||
|
||||
/* Fork the child processes */
|
||||
ForkChildProcesses(N_PROCESSES);
|
||||
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HsaMemoryBuffer addrBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
HsaMemoryBuffer resultBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
|
||||
std::vector<void *> pBuffers;
|
||||
AllocBuffers(defaultGPUNode, count, vramBufSize, pBuffers);
|
||||
|
||||
unsigned int wavefront_num = pBuffers.size();
|
||||
LOG() << m_psName << "wavefront number " << wavefront_num << std::endl;
|
||||
|
||||
void **localBufAddr = addrBuffer.As<void **>();
|
||||
unsigned int *result = resultBuffer.As<uint32_t *>();
|
||||
|
||||
for (i = 0; i < wavefront_num; i++)
|
||||
*(localBufAddr + i) = pBuffers[i];
|
||||
|
||||
m_pIsaGen->CompileShader(CreateShader().c_str(), "ReadMemory", isaBuffer);
|
||||
|
||||
PM4Queue pm4Queue;
|
||||
ASSERT_SUCCESS(pm4Queue.Create(defaultGPUNode));
|
||||
|
||||
Dispatch dispatch0(isaBuffer);
|
||||
dispatch0.SetArgs(localBufAddr, result);
|
||||
dispatch0.SetDim(wavefront_num, 1, 1);
|
||||
/* submit the packet and start shader */
|
||||
dispatch0.Submit(pm4Queue);
|
||||
|
||||
/* doing evict/restore queue test for 5 seconds while queue is running */
|
||||
sleep(5);
|
||||
|
||||
/* LOG() << m_psName << "notify shader to quit" << std::endl; */
|
||||
/* fill address buffer so shader quits */
|
||||
addrBuffer.Fill(0x5678);
|
||||
|
||||
/* wait for shader to finish or timeout if shade has vm page fault */
|
||||
dispatch0.SyncWithStatus(120000);
|
||||
|
||||
ASSERT_SUCCESS(pm4Queue.Destroy());
|
||||
/* LOG() << m_psName << "free buffer" << std::endl; */
|
||||
/* cleanup */
|
||||
FreeBuffers(pBuffers, vramBufSize);
|
||||
|
||||
/* check if all wavefronts finish successfully */
|
||||
for (i = 0; i < wavefront_num; i++)
|
||||
ASSERT_EQ(0x5678, *(result + i));
|
||||
|
||||
WaitChildProcesses();
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_EVICT_TEST__H__
|
||||
#define __KFD_EVICT_TEST__H__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "KFDLocalMemoryTest.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
// @class KFDEvictTest
|
||||
// Test eviction and restore procedure using two processes
|
||||
class KFDEvictTest : public KFDLocalMemoryTest {
|
||||
public:
|
||||
KFDEvictTest(void): m_ChildStatus(HSAKMT_STATUS_ERROR), m_IsParent(true) {}
|
||||
|
||||
~KFDEvictTest(void) {
|
||||
if (!m_IsParent) {
|
||||
/* child process has to exit
|
||||
* otherwise gtest will continue other tests
|
||||
*/
|
||||
exit(m_ChildStatus);
|
||||
}
|
||||
|
||||
try {
|
||||
WaitChildProcesses();
|
||||
} catch (...) {}
|
||||
}
|
||||
|
||||
protected:
|
||||
std::string CreateShader();
|
||||
void AllocBuffers(HSAuint32 defaultGPUNode, HSAuint32 count, HSAuint64 vramBufSize,
|
||||
std::vector<void *> &pBuffers);
|
||||
void FreeBuffers(std::vector<void *> &pBuffers, HSAuint64 vramBufSize);
|
||||
void ForkChildProcesses(int nprocesses);
|
||||
void WaitChildProcesses();
|
||||
HSAint32 GetBufferCounter(HSAuint64 vramSize, HSAuint64 vramBufSize);
|
||||
|
||||
protected: // members
|
||||
std::string m_psName;
|
||||
std::vector<pid_t> m_ChildPids;
|
||||
HsaMemFlags m_Flags;
|
||||
void* m_pBuf;
|
||||
HSAKMT_STATUS m_ChildStatus;
|
||||
bool m_IsParent;
|
||||
};
|
||||
|
||||
#endif // __KFD_EVICT_TEST__H__
|
||||
@@ -0,0 +1,355 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDExceptionTest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
// All tests are marked by their serial number in the QCM FDD
|
||||
|
||||
void KFDExceptionTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
m_pIsaGen = IsaGenerator::Create(m_FamilyId);
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDExceptionTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
if (m_pIsaGen)
|
||||
delete m_pIsaGen;
|
||||
m_pIsaGen = NULL;
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
/* Test for memory exception. The function expects a Memory Fault to be
|
||||
* triggered by the GPU when it tries to copy dword from pSrc to pDst.
|
||||
* Should be called from a Child Process since the Memory Fault causes
|
||||
* all the queues to be halted.
|
||||
*/
|
||||
void KFDExceptionTest::TestMemoryException(int defaultGPUNode, HSAuint64 pSrc,
|
||||
HSAuint64 pDst, unsigned int dimX,
|
||||
unsigned int dimY, unsigned int dimZ) {
|
||||
PM4Queue queue;
|
||||
HsaEvent *vmFaultEvent;
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HSAuint64 faultAddress, page_mask = ~((HSAuint64)PAGE_SIZE - 1);
|
||||
Dispatch dispatch(isaBuffer, false);
|
||||
|
||||
HsaEventDescriptor eventDesc;
|
||||
eventDesc.EventType = HSA_EVENTTYPE_MEMORY;
|
||||
eventDesc.NodeId = defaultGPUNode;
|
||||
eventDesc.SyncVar.SyncVar.UserData = NULL;
|
||||
eventDesc.SyncVar.SyncVarSize = 0;
|
||||
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
m_ChildStatus = queue.Create(defaultGPUNode);
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "Queue create failed" << std::endl;
|
||||
return;
|
||||
}
|
||||
m_ChildStatus = hsaKmtCreateEvent(&eventDesc, true, false, &vmFaultEvent);
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "Event create failed" << std::endl;
|
||||
goto queuefail;
|
||||
}
|
||||
|
||||
dispatch.SetDim(dimX, dimY, dimZ);
|
||||
dispatch.SetArgs((void *)pSrc, (void *)pDst);
|
||||
dispatch.Submit(queue);
|
||||
|
||||
m_ChildStatus = hsaKmtWaitOnEvent(vmFaultEvent, g_TestTimeOut);
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "Wait failed. No Exception triggered" << std::endl;
|
||||
goto eventfail;
|
||||
}
|
||||
|
||||
if (vmFaultEvent->EventData.EventType != HSA_EVENTTYPE_MEMORY) {
|
||||
WARN() << "Unexpected Event Received " << vmFaultEvent->EventData.EventType
|
||||
<< std::endl;
|
||||
m_ChildStatus = HSAKMT_STATUS_ERROR;
|
||||
goto eventfail;
|
||||
}
|
||||
faultAddress = vmFaultEvent->EventData.EventData.MemoryAccessFault.VirtualAddress;
|
||||
if (faultAddress != (pSrc & page_mask) &&
|
||||
faultAddress != (pDst & page_mask) ) {
|
||||
WARN() << "Unexpected Fault Address " << faultAddress
|
||||
<< " expected " << (pSrc & page_mask) << " or "
|
||||
<< (pDst & page_mask) << std::endl;
|
||||
m_ChildStatus = HSAKMT_STATUS_ERROR;
|
||||
}
|
||||
|
||||
eventfail:
|
||||
hsaKmtDestroyEvent(vmFaultEvent);
|
||||
queuefail:
|
||||
queue.Destroy();
|
||||
}
|
||||
|
||||
/* Test Bad Address access in a child process */
|
||||
TEST_F(KFDExceptionTest, InvalidBadAddress) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (m_FamilyId == FAMILY_RV) {
|
||||
LOG() << "Skip the test on Raven due to IOMMU issues" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
m_ChildStatus = hsaKmtOpenKFD();
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "KFD open failed in child process" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer srcBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
|
||||
srcBuffer.Fill(0xAA55AA55);
|
||||
TestMemoryException(defaultGPUNode, srcBuffer.As<HSAuint64>(),
|
||||
0x12345678ULL);
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
if (is_dgpu()) {
|
||||
ASSERT_EQ(WIFEXITED(childStatus), true);
|
||||
ASSERT_EQ(WEXITSTATUS(childStatus), HSAKMT_STATUS_SUCCESS);
|
||||
} else {
|
||||
ASSERT_EQ(WIFSIGNALED(childStatus), true);
|
||||
ASSERT_EQ(WTERMSIG(childStatus), SIGSEGV);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* TODO: Check why this test doesn't behave as expected.
|
||||
* Expected behaviour: Since pDst is not mapped in GPU VM, an attempt
|
||||
* to write to pDst should trigger a Memory Fault.
|
||||
* However, If pDst > 40bits (MC Size) GPU does not create Memory Fault.
|
||||
* An EOP interrupt is generated however as expected no data is copied
|
||||
* into pDst.
|
||||
*/
|
||||
TEST_F(KFDExceptionTest, InvalidPPRWriteProtection) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (is_dgpu()) {
|
||||
LOG() << "Not an APU, no PPR available, skip the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_FamilyId == FAMILY_RV) {
|
||||
LOG() << "Skip the test on Raven due to IOMMU issues" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
m_ChildStatus = hsaKmtOpenKFD();
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "KFD open failed in child process" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer srcBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
void* pDst = VirtualAllocMemory(NULL, PAGE_SIZE, MEM_READ);
|
||||
|
||||
LOG() << "PPR dst address is " << pDst << std::endl;
|
||||
|
||||
srcBuffer.Fill(0xAA55AA55);
|
||||
TestMemoryException(defaultGPUNode, srcBuffer.As<HSAuint64>(),
|
||||
(HSAuint64)pDst);
|
||||
|
||||
/* Wait enough time here to ensure this process got killed by kernel
|
||||
* due to PPR exception.
|
||||
*/
|
||||
sleep(5);
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
ASSERT_EQ(WIFSIGNALED(childStatus), true);
|
||||
ASSERT_EQ(WTERMSIG(childStatus), SIGSEGV);
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* TODO: Same as previous test InvalidPPRWriteProtection
|
||||
*/
|
||||
TEST_F(KFDExceptionTest, InvalidPPRReadProtection) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (is_dgpu()) {
|
||||
LOG() << "Not an APU, no PPR available, skip the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (m_FamilyId == FAMILY_RV) {
|
||||
LOG() << "Skip the test on Raven due to IOMMU issues" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
m_ChildStatus = hsaKmtOpenKFD();
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "KFD open failed in child process" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer dstBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
void* pSrc = VirtualAllocMemory(NULL, PAGE_SIZE, MEM_NONE);
|
||||
|
||||
LOG() << "PPR src address is " << pSrc << std::endl;
|
||||
|
||||
dstBuffer.Fill(0xAA55AA55);
|
||||
TestMemoryException(defaultGPUNode, (HSAuint64)pSrc,
|
||||
dstBuffer.As<HSAuint64>());
|
||||
|
||||
/* Wait enough time here to ensure this process got killed by kernel
|
||||
* due to PPR exception.
|
||||
*/
|
||||
sleep(5);
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
ASSERT_EQ(WIFSIGNALED(childStatus), true);
|
||||
ASSERT_EQ(WTERMSIG(childStatus), SIGSEGV);
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Allocate Read Only buffer. Test Memory Exception failure by
|
||||
* attempting to write to that buffer in the child process.
|
||||
*/
|
||||
TEST_F(KFDExceptionTest, InvalidWriteAddress) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (m_FamilyId == FAMILY_RV) {
|
||||
LOG() << "Skip the test on Raven due to IOMMU issues" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
m_ChildStatus = hsaKmtOpenKFD();
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "KFD open failed in child process" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer readOnlyBuffer(PAGE_SIZE, defaultGPUNode, false /*zero*/,
|
||||
false /*isLocal*/, true /*isExec*/,
|
||||
false /*isScratch*/, true /*isReadOnly*/);
|
||||
HsaMemoryBuffer srcSysBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
|
||||
srcSysBuffer.Fill(0xAA55AA55);
|
||||
|
||||
TestMemoryException(defaultGPUNode, srcSysBuffer.As<HSAuint64>(),
|
||||
readOnlyBuffer.As<HSAuint64>());
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
if (is_dgpu()) {
|
||||
ASSERT_EQ(WIFEXITED(childStatus), true);
|
||||
ASSERT_EQ(WEXITSTATUS(childStatus), HSAKMT_STATUS_SUCCESS);
|
||||
} else {
|
||||
ASSERT_EQ(WIFSIGNALED(childStatus), true);
|
||||
ASSERT_EQ(WTERMSIG(childStatus), SIGSEGV);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Test VM fault storm handling by copying to/from invalid pointers
|
||||
* with lots of work items at the same time
|
||||
*/
|
||||
TEST_F(KFDExceptionTest, FaultStorm) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (m_FamilyId == FAMILY_RV) {
|
||||
LOG() << "Skip the test on Raven due to IOMMU issues" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HSAKMT_STATUS status;
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
m_ChildStatus = hsaKmtOpenKFD();
|
||||
if (m_ChildStatus != HSAKMT_STATUS_SUCCESS) {
|
||||
WARN() << "KFD open failed in child process" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
TestMemoryException(defaultGPUNode, 0x12345678, 0x76543210, 1024, 1024, 1);
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
if (is_dgpu()) {
|
||||
ASSERT_EQ(WIFEXITED(childStatus), true);
|
||||
ASSERT_EQ(WEXITSTATUS(childStatus), HSAKMT_STATUS_SUCCESS);
|
||||
} else {
|
||||
ASSERT_EQ(WIFSIGNALED(childStatus), true);
|
||||
ASSERT_EQ(WTERMSIG(childStatus), SIGSEGV);
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_EXCEPTION_TEST__H__
|
||||
#define __KFD_EXCEPTION_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDExceptionTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDExceptionTest() :m_pIsaGen(NULL), m_ChildPid(-1) {
|
||||
/* Because there could be early return before m_ChildPid is set
|
||||
* by fork(), we should initialize m_ChildPid to a non-zero value
|
||||
* to avoid possible exit of the main process.
|
||||
*/
|
||||
}
|
||||
|
||||
~KFDExceptionTest() {
|
||||
/* exit() is necessary for the child process. Otherwise when the
|
||||
* child process finishes, gtest assumes the test has finished and
|
||||
* starts the next test while the parent is still active.
|
||||
*/
|
||||
if (m_ChildPid == 0)
|
||||
exit(m_ChildStatus);
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
void TestMemoryException(int defaultGPUNode, HSAuint64 pSrc, HSAuint64 pDst,
|
||||
unsigned int dimX = 1, unsigned int dimY = 1,
|
||||
unsigned int dimZ = 1);
|
||||
|
||||
protected: // members
|
||||
pid_t m_ChildPid;
|
||||
HSAKMT_STATUS m_ChildStatus;
|
||||
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __KFD_EXCEPTION_TEST__H__
|
||||
@@ -0,0 +1,317 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDGraphicsInterop.hpp"
|
||||
|
||||
extern "C" {
|
||||
#include <xf86drm.h>
|
||||
#include <amdgpu.h>
|
||||
#include <amdgpu_drm.h>
|
||||
}
|
||||
#include <unistd.h>
|
||||
#include <sys/param.h>
|
||||
#include <vector>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include "Dispatch.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
|
||||
void KFDGraphicsInterop::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDMemoryTest::SetUp();
|
||||
|
||||
// Try to open and initialize a render node for each device
|
||||
for (int i = 0; i < MAX_RENDER_NODES; i++) {
|
||||
m_RenderNodes[i].fd = drmOpenRender(i + 128);
|
||||
|
||||
if (m_RenderNodes[i].fd <= 0)
|
||||
continue;
|
||||
|
||||
if (amdgpu_device_initialize(m_RenderNodes[i].fd,
|
||||
&m_RenderNodes[i].major_version,
|
||||
&m_RenderNodes[i].minor_version,
|
||||
&m_RenderNodes[i].device_handle) != 0) {
|
||||
drmClose(m_RenderNodes[i].fd);
|
||||
m_RenderNodes[i].fd = 0;
|
||||
}
|
||||
|
||||
// Try to determine the bus-ID from sysfs
|
||||
char path[PATH_MAX], link[PATH_MAX];
|
||||
snprintf(path, PATH_MAX, "/sys/class/drm/renderD%d", i+128);
|
||||
if (readlink(path, link, PATH_MAX) < 0) {
|
||||
LOG() << "Failed to read sysfs link " << path
|
||||
<< ", can't determine bus ID." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
char *state = NULL;
|
||||
char *prev = NULL;
|
||||
char *tok = strtok_r(link, "/", &state);
|
||||
while (tok && strcmp(tok, "drm")) {
|
||||
prev = tok;
|
||||
tok = strtok_r(NULL, "/", &state);
|
||||
}
|
||||
unsigned domain, bus, device, func;
|
||||
if (!prev ||
|
||||
sscanf(prev, "%04x:%02x:%02x.%1x", &domain, &bus, &device, &func)
|
||||
!= 4) {
|
||||
LOG() << "Failed to parse sysfs link " << path
|
||||
<< ", can't determine bus ID." << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
m_RenderNodes[i].bdf = (bus << 8) | (device << 3) | func;
|
||||
}
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDGraphicsInterop::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
for (int i = 0; i < MAX_RENDER_NODES; i++) {
|
||||
if (m_RenderNodes[i].fd <= 0)
|
||||
continue;
|
||||
|
||||
EXPECT_EQ(0, amdgpu_device_deinitialize(m_RenderNodes[i].device_handle));
|
||||
EXPECT_EQ(0, drmClose(m_RenderNodes[i].fd));
|
||||
}
|
||||
|
||||
KFDMemoryTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
int KFDGraphicsInterop::FindDRMRenderNode(int gpuNode) {
|
||||
int rn;
|
||||
const HsaNodeProperties *pNodeProps =
|
||||
m_NodeInfo.GetNodeProperties(gpuNode);
|
||||
|
||||
for (rn = 0; rn < MAX_RENDER_NODES; rn++) {
|
||||
if (m_RenderNodes[rn].fd <= 0)
|
||||
continue;
|
||||
if (m_RenderNodes[rn].bdf == pNodeProps->LocationId)
|
||||
return rn;
|
||||
}
|
||||
LOG() << "Found no render node corresponding to GPU node "
|
||||
<< gpuNode << std::endl;
|
||||
LOG() << "Check your device permissions" << std::endl;
|
||||
return -1;
|
||||
}
|
||||
|
||||
TEST_F(KFDGraphicsInterop, RegisterGraphicsHandle) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
const HsaNodeProperties *pNodeProps =
|
||||
m_NodeInfo.GetNodeProperties(defaultGPUNode);
|
||||
const HSAuint32 familyID = FamilyIdFromNode(pNodeProps);
|
||||
|
||||
if (isTonga(pNodeProps)) {
|
||||
LOG() << "Skipping test: Tonga workaround in thunk returns incorrect allocation size" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HSAuint32 nodes[1] = {(uint32_t)defaultGPUNode};
|
||||
|
||||
const char metadata[] = "This data is really meta.";
|
||||
unsigned metadata_size = strlen(metadata)+1;
|
||||
int rn = FindDRMRenderNode(defaultGPUNode);
|
||||
|
||||
if (rn < 0) {
|
||||
LOG() << "Skipping test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Create the buffer with metadata and get a dmabuf handle to it
|
||||
struct amdgpu_bo_alloc_request alloc;
|
||||
amdgpu_bo_handle handle;
|
||||
if (familyID == FAMILY_CZ || isTonga(pNodeProps))
|
||||
alloc.alloc_size = PAGE_SIZE * 8;
|
||||
else
|
||||
alloc.alloc_size = PAGE_SIZE;
|
||||
alloc.phys_alignment = PAGE_SIZE;
|
||||
alloc.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
alloc.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
ASSERT_EQ(0, amdgpu_bo_alloc(m_RenderNodes[rn].device_handle, &alloc, &handle));
|
||||
|
||||
void *pCpuMap;
|
||||
ASSERT_EQ(0, amdgpu_bo_cpu_map(handle, &pCpuMap));
|
||||
memset(pCpuMap, 0xaa, PAGE_SIZE);
|
||||
ASSERT_EQ(0, amdgpu_bo_cpu_unmap(handle));
|
||||
|
||||
struct amdgpu_bo_metadata meta;
|
||||
meta.flags = 0;
|
||||
meta.tiling_info = 0;
|
||||
meta.size_metadata = metadata_size;
|
||||
memcpy(meta.umd_metadata, metadata, metadata_size);
|
||||
ASSERT_EQ(0, amdgpu_bo_set_metadata(handle, &meta));
|
||||
|
||||
uint32_t dmabufFd;
|
||||
ASSERT_EQ(0, amdgpu_bo_export(handle, amdgpu_bo_handle_type_dma_buf_fd, &dmabufFd));
|
||||
|
||||
// Register it with HSA
|
||||
HsaGraphicsResourceInfo info;
|
||||
ASSERT_SUCCESS(hsaKmtRegisterGraphicsHandleToNodes(dmabufFd, &info,
|
||||
1, nodes));
|
||||
|
||||
// DMA buffer handle and GEM handle are no longer needed, KFD
|
||||
// should have taken a reference to the BO
|
||||
ASSERT_EQ(0, close(dmabufFd));
|
||||
ASSERT_EQ(0, amdgpu_bo_free(handle));
|
||||
|
||||
// Check that buffer size and metadata match
|
||||
ASSERT_EQ(info.SizeInBytes, alloc.alloc_size);
|
||||
ASSERT_EQ(info.MetadataSizeInBytes, metadata_size);
|
||||
ASSERT_EQ(0, strcmp(metadata, (const char *)info.Metadata));
|
||||
|
||||
// Map the buffer
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(info.MemoryAddress,
|
||||
info.SizeInBytes,
|
||||
NULL));
|
||||
|
||||
// Copy contents to a system memory buffer for comparison
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
|
||||
HsaMemoryBuffer dstBuffer(PAGE_SIZE, defaultGPUNode, true/*zero*/);
|
||||
|
||||
PM4Queue queue;
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
Dispatch dispatch(isaBuffer);
|
||||
|
||||
dispatch.SetArgs(info.MemoryAddress, dstBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
ASSERT_EQ(dstBuffer.As<unsigned int *>()[0], 0xaaaaaaaa);
|
||||
|
||||
// Test QueryMem before the cleanup
|
||||
HsaPointerInfo ptrInfo;
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo((const void *)info.MemoryAddress, &ptrInfo));
|
||||
EXPECT_EQ(ptrInfo.Type, HSA_POINTER_REGISTERED_GRAPHICS);
|
||||
EXPECT_EQ(ptrInfo.Node, (HSAuint32)defaultGPUNode);
|
||||
EXPECT_EQ(ptrInfo.GPUAddress, (HSAuint64)info.MemoryAddress);
|
||||
EXPECT_EQ(ptrInfo.SizeInBytes, alloc.alloc_size);
|
||||
|
||||
// Cleanup
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(info.MemoryAddress));
|
||||
ASSERT_SUCCESS(hsaKmtDeregisterMemory(info.MemoryAddress));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Third-party device memory can be registered for GPU access in
|
||||
* ROCm stack. Test this feature. Third party device is mimicked
|
||||
* in multi-GPU system using Graphics stack (libdrm). CPU accessible
|
||||
* device memory is allocated using Graphics stack on gpuNode2 and
|
||||
* this memory will be registered on gpuNode1 for GPU access.
|
||||
*/
|
||||
TEST_F(KFDGraphicsInterop, RegisterForeignDeviceMem) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
if (!is_dgpu()) {
|
||||
LOG() << "Skipping test: Supports only multi-dGPU system" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
const std::vector<int> gpuNodes = m_NodeInfo.GetNodesWithGPU();
|
||||
if (gpuNodes.size() < 2) {
|
||||
LOG() << "Skipping test: Need at least two GPUs" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* gpuNode2 must have public memory (large bar) to allocate CPU accessible
|
||||
* device memory.
|
||||
*/
|
||||
HSAint32 gpuNode1 = m_NodeInfo.HsaDefaultGPUNode(), gpuNode2 = 0;
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
|
||||
gpuNode2 = m_NodeInfo.FindLargeBarGPUNode();
|
||||
if (gpuNode2 < 0) {
|
||||
LOG() << "Skipping test: Need at least one large bar GPU" << std::endl;
|
||||
return;
|
||||
}
|
||||
if (gpuNode1 == gpuNode2) {
|
||||
for (unsigned i = 0; i < gpuNodes.size(); i++) {
|
||||
if (gpuNodes.at(i) != gpuNode2) {
|
||||
gpuNode1 = gpuNodes.at(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const HsaNodeProperties *pNodeProps =
|
||||
m_NodeInfo.GetNodeProperties(gpuNode2);
|
||||
const HSAuint32 familyID = FamilyIdFromNode(pNodeProps);
|
||||
|
||||
int rn = FindDRMRenderNode(gpuNode2);
|
||||
if (rn < 0) {
|
||||
LOG() << "Skipping test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
// Allocate CPU accessible device memory on gpuNode2
|
||||
struct amdgpu_bo_alloc_request alloc;
|
||||
amdgpu_bo_handle handle;
|
||||
if (familyID == FAMILY_CZ || isTonga(pNodeProps))
|
||||
alloc.alloc_size = PAGE_SIZE * 8;
|
||||
else
|
||||
alloc.alloc_size = PAGE_SIZE;
|
||||
alloc.phys_alignment = PAGE_SIZE;
|
||||
alloc.preferred_heap = AMDGPU_GEM_DOMAIN_VRAM;
|
||||
alloc.flags = AMDGPU_GEM_CREATE_CPU_ACCESS_REQUIRED;
|
||||
ASSERT_EQ(0, amdgpu_bo_alloc(m_RenderNodes[rn].device_handle, &alloc, &handle));
|
||||
|
||||
void *pCpuMap;
|
||||
ASSERT_EQ(0, amdgpu_bo_cpu_map(handle, &pCpuMap));
|
||||
memset(pCpuMap, 0xAA, PAGE_SIZE);
|
||||
|
||||
/* Register third-party device memory in KFD. Test GPU access
|
||||
* by carrying out a simple copy test
|
||||
*/
|
||||
HsaMemoryBuffer lockDeviceMemory(pCpuMap, PAGE_SIZE);
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, gpuNode1, true/*zero*/, false/*local*/, true/*exec*/);
|
||||
HsaMemoryBuffer dstBuffer(PAGE_SIZE, gpuNode1, true/*zero*/);
|
||||
PM4Queue queue;
|
||||
Dispatch dispatch(isaBuffer);
|
||||
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
ASSERT_SUCCESS(queue.Create(gpuNode1));
|
||||
|
||||
dispatch.SetArgs(lockDeviceMemory.As<void*>(), dstBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
ASSERT_EQ(dstBuffer.As<HSAuint32*>()[0], 0xAAAAAAAA);
|
||||
|
||||
ASSERT_EQ(0, amdgpu_bo_cpu_unmap(handle));
|
||||
ASSERT_EQ(0, amdgpu_bo_free(handle));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDMemoryTest.hpp"
|
||||
extern "C" {
|
||||
#include <amdgpu.h>
|
||||
}
|
||||
|
||||
#ifndef __KFD_GRAPHICS_INTEROP_TEST__H__
|
||||
#define __KFD_GRAPHICS_INTEROP_TEST__H__
|
||||
|
||||
// @class KFDGraphicsInteropTest
|
||||
// Adds access to graphics device for interoperability testing
|
||||
class KFDGraphicsInterop : public KFDMemoryTest
|
||||
{
|
||||
public:
|
||||
KFDGraphicsInterop(void) {};
|
||||
~KFDGraphicsInterop(void) {};
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
#define MAX_RENDER_NODES 64
|
||||
struct {
|
||||
int fd;
|
||||
uint32_t major_version;
|
||||
uint32_t minor_version;
|
||||
amdgpu_device_handle device_handle;
|
||||
uint32_t bdf;
|
||||
} m_RenderNodes[MAX_RENDER_NODES];
|
||||
|
||||
// @brief Finds DRM Render node corresponding to gpuNode
|
||||
// @return DRM Render Node if successful or -1 on failure
|
||||
int FindDRMRenderNode(int gpuNode);
|
||||
};
|
||||
|
||||
#endif
|
||||
@@ -0,0 +1,731 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDIPCTest.hpp"
|
||||
#include <sys/types.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/stat.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <vector>
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
|
||||
void KFDIPCTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDIPCTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
KFDIPCTest::~KFDIPCTest(void) {
|
||||
/* exit() is necessary for the child process. Otherwise when the
|
||||
* child process finishes, gtest assumes the test has finished and
|
||||
* starts the next test while the parent is still active.
|
||||
*/
|
||||
if (m_ChildPid == 0)
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/* Imort shared Local Memory from parent process. Check for the pattern
|
||||
* filled in by the parent process. Then fill a new pattern.
|
||||
*/
|
||||
void KFDIPCTest::BasicTestChildProcess(int defaultGPUNode, int *pipefd) {
|
||||
/* Open KFD device for child process. This needs to called before
|
||||
* any memory definitions
|
||||
*/
|
||||
if (HSAKMT_STATUS_SUCCESS != hsaKmtOpenKFD())
|
||||
exit(1);
|
||||
|
||||
SDMAQueue sdmaQueue;
|
||||
HsaSharedMemoryHandle sharedHandleLM;
|
||||
HSAuint64 size = PAGE_SIZE, sharedSize;
|
||||
HsaMemoryBuffer tempSysBuffer(size, defaultGPUNode, false);
|
||||
HSAuint32 *sharedLocalBuffer = NULL;
|
||||
|
||||
/* Read from Pipe the shared Handle. Import shared Local Memory */
|
||||
ASSERT_GE(read(pipefd[0], (void*)&sharedHandleLM, sizeof(sharedHandleLM)), 0);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtRegisterSharedHandle(&sharedHandleLM,
|
||||
(void**)&sharedLocalBuffer, &sharedSize));
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(sharedLocalBuffer, sharedSize, NULL));
|
||||
|
||||
/* Check for pattern in the shared Local Memory */
|
||||
ASSERT_SUCCESS(sdmaQueue.Create(defaultGPUNode));
|
||||
size = size < sharedSize ? size : sharedSize;
|
||||
sdmaQueue.PlaceAndSubmitPacket(SDMACopyDataPacket(tempSysBuffer.As<HSAuint32*>(),
|
||||
sharedLocalBuffer, size));
|
||||
sdmaQueue.Wait4PacketConsumption();
|
||||
ASSERT_TRUE(WaitOnValue(tempSysBuffer.As<HSAuint32*>(), 0xAAAAAAAA));
|
||||
|
||||
/* Fill in the Local Memory with different pattern */
|
||||
sdmaQueue.PlaceAndSubmitPacket(SDMAWriteDataPacket(sharedLocalBuffer, 0xBBBBBBBB));
|
||||
sdmaQueue.Wait4PacketConsumption();
|
||||
|
||||
/* Clean up */
|
||||
ASSERT_SUCCESS(sdmaQueue.Destroy());
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(sharedLocalBuffer));
|
||||
ASSERT_SUCCESS(hsaKmtDeregisterMemory(sharedLocalBuffer));
|
||||
}
|
||||
|
||||
/* Fill a pattern in to Local Memory and share with the child process.
|
||||
* Then wait until Child process to exit and check for the new pattern
|
||||
* fill in by the child process.
|
||||
*/
|
||||
|
||||
void KFDIPCTest::BasicTestParentProcess(int defaultGPUNode, pid_t cpid, int *pipefd) {
|
||||
HSAuint64 size = PAGE_SIZE, sharedSize;
|
||||
int status;
|
||||
HSAuint64 AlternateVAGPU;
|
||||
HsaMemoryBuffer toShareLocalBuffer(size, defaultGPUNode, false, true);
|
||||
HsaMemoryBuffer tempSysBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
SDMAQueue sdmaQueue;
|
||||
HsaSharedMemoryHandle sharedHandleLM;
|
||||
|
||||
/* Fill a Local Buffer with a pattern */
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(toShareLocalBuffer.As<void*>(), toShareLocalBuffer.Size(), &AlternateVAGPU));
|
||||
tempSysBuffer.Fill(0xAAAAAAAA);
|
||||
|
||||
/* Copy pattern in Local Memory before sharing it */
|
||||
ASSERT_SUCCESS(sdmaQueue.Create(defaultGPUNode));
|
||||
sdmaQueue.PlaceAndSubmitPacket(SDMACopyDataPacket(toShareLocalBuffer.As<HSAuint32*>(),
|
||||
tempSysBuffer.As<HSAuint32*>(), size));
|
||||
sdmaQueue.Wait4PacketConsumption();
|
||||
|
||||
/* Share it with the child process */
|
||||
ASSERT_SUCCESS(hsaKmtShareMemory(toShareLocalBuffer.As<void*>(), size, &sharedHandleLM));
|
||||
|
||||
ASSERT_GE(write(pipefd[1], (void*)&sharedHandleLM, sizeof(sharedHandleLM)), 0);
|
||||
|
||||
/* Wait for the child to finish */
|
||||
waitpid(cpid, &status, 0);
|
||||
|
||||
ASSERT_EQ(WIFEXITED(status), 1);
|
||||
ASSERT_EQ(WEXITSTATUS(status), 0);
|
||||
|
||||
/* Check for the new pattern filled in by child process */
|
||||
sdmaQueue.PlaceAndSubmitPacket(SDMACopyDataPacket(tempSysBuffer.As<HSAuint32*>(),
|
||||
toShareLocalBuffer.As<HSAuint32*>(), size));
|
||||
sdmaQueue.Wait4PacketConsumption();
|
||||
ASSERT_TRUE(WaitOnValue(tempSysBuffer.As<HSAuint32*>(), 0xBBBBBBBB));
|
||||
|
||||
/* Clean up */
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(toShareLocalBuffer.As<void*>()));
|
||||
ASSERT_SUCCESS(sdmaQueue.Destroy());
|
||||
}
|
||||
|
||||
/* Test IPC memory.
|
||||
* 1. Parent Process [Create/Fill] LocalMemory (LM) --share--> Child Process
|
||||
* 2. Child Process import LM and check for the pattern.
|
||||
* 3. Child Process fill in a new pattern and quit.
|
||||
* 4. Parent Process wait for the Child process to finish and then check for
|
||||
* the new pattern in LM
|
||||
*
|
||||
* IPC support is limited to Local Memory.
|
||||
*/
|
||||
|
||||
TEST_F(KFDIPCTest, BasicTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
const std::vector<int>& GpuNodes = m_NodeInfo.GetNodesWithGPU();
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
int pipefd[2];
|
||||
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (!GetVramSize(defaultGPUNode)) {
|
||||
LOG() << "Skip the test because of no VRAM found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Test libhsakmt fork() clean up by defining some buffers. These
|
||||
* buffers gets duplicated in the child process but not are not valid
|
||||
* as it doesn't have proper mapping in GPU. The clean up code in libhsakmt
|
||||
* should handle it
|
||||
*/
|
||||
volatile HSAuint32 stackData[1];
|
||||
HsaMemoryBuffer tmpSysBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
HsaMemoryBuffer tmpUserptrBuffer((void *)&stackData[0], sizeof(HSAuint32));
|
||||
|
||||
/* Create Pipes for communicating shared handles */
|
||||
ASSERT_EQ(pipe(pipefd), 0);
|
||||
|
||||
/* Create a child process and share the above Local Memory with it */
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0)
|
||||
BasicTestChildProcess(defaultGPUNode, pipefd); /* Child Process */
|
||||
else
|
||||
BasicTestParentProcess(defaultGPUNode, m_ChildPid, pipefd); /* Parent proces */
|
||||
|
||||
/* Code path executed by both parent and child with respective fds */
|
||||
close(pipefd[1]);
|
||||
close(pipefd[0]);
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Cross Memory Attach Test. Memory Descriptor Array.
|
||||
* The following 2 2D-arrays describe the source and destination memory arrays used
|
||||
* by CMA test. The entry is only valid if Size != 0. Each of these buffers will be
|
||||
* filled intially with "FillPattern". After the test the srcRange is still expected
|
||||
* to have the same pattern. The dstRange is expected to have srcRange pattern.
|
||||
*
|
||||
* For e.g. for TEST_COUNT = 1,
|
||||
* srcRange has 2 buffers of size 0x1800. Buf1 filled with 0xA5A5A5A5 and Buf2
|
||||
* filled with 0xAAAAAAAA
|
||||
* dstRange has 3 buffers of size 0x1000. All of them filled 0xFFFFFFFF.
|
||||
* After Copy: dstBuf1[0-0x1000] is expected to be 0xA5A5A5A5
|
||||
* dstBuf2[0-0x800] is expected to be 0xA5A5A5A5
|
||||
* dstBuf3[0x800-0x1000] is expected to be 0xAAAAAAAA
|
||||
* and dstBuf4[0x0-0x1000] is expected to be 0xAAAAAAAA
|
||||
*
|
||||
* For this CMA test after copy only the first and the last of dstBuf is checked
|
||||
*/
|
||||
|
||||
static testMemoryDescriptor srcRange[CMA_TEST_COUNT][CMA_MEMORY_TEST_ARRAY_SIZE] = {
|
||||
{ /* Memory Type Size FillPattern FirstItem Last item */
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x801800, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x1800, 0xAAAAAAAA, 0xAAAAAAAA, 0xAAAAAAAA },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x0, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x0, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
},
|
||||
{
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x208000, 0xDEADBEEF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x4000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x6000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x2000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
},
|
||||
{
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x800000, 0xDEADBEEF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xA5A5A5A5, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
}
|
||||
};
|
||||
|
||||
static testMemoryDescriptor dstRange[CMA_TEST_COUNT][CMA_MEMORY_TEST_ARRAY_SIZE] = {
|
||||
{
|
||||
/* Memory Type Size FillPattern FirstItem Last item */
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x801000, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x1000, 0xFFFFFFFF, 0xA5A5A5A5, 0xAAAAAAAA },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x1000, 0xFFFFFFFF, 0xAAAAAAAA, 0xAAAAAAAA },
|
||||
{ CMA_MEM_TYPE_USERPTR, 0x0, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
},
|
||||
{
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x202000, 0xFFFFFFFF, 0xDEADBEEF, 0xDEADBEEF },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x4000, 0xFFFFFFFF, 0xDEADBEEF, 0xDEADBEEF },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x8000, 0xFFFFFFFF, 0xDEADBEEF, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_SYSTEM, 0x6000, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
},
|
||||
{
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x800000, 0xFFFFFFFF, 0xDEADBEEF, 0xDEADBEEF },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
{ CMA_MEM_TYPE_LOCAL_MEM, 0x1000, 0xFFFFFFFF, 0xA5A5A5A5, 0xA5A5A5A5 },
|
||||
}
|
||||
};
|
||||
|
||||
KFDCMAArray::KFDCMAArray() : m_ValidCount(0), m_QueueArray(HSA_QUEUE_SDMA) {
|
||||
memset(m_MemArray, 0, sizeof(m_MemArray));
|
||||
memset(m_HsaMemoryRange, 0, sizeof(m_HsaMemoryRange));
|
||||
}
|
||||
|
||||
CMA_TEST_STATUS KFDCMAArray::Destroy() {
|
||||
for (int i = 0; i < m_ValidCount; i++) {
|
||||
if (m_MemArray[i]) {
|
||||
void *userPtr;
|
||||
|
||||
userPtr = m_MemArray[i]->GetUserPtr();
|
||||
delete m_MemArray[i];
|
||||
|
||||
if (userPtr)
|
||||
free(userPtr);
|
||||
}
|
||||
}
|
||||
|
||||
memset(m_MemArray, 0, sizeof(m_MemArray));
|
||||
memset(m_HsaMemoryRange, 0, sizeof(m_HsaMemoryRange));
|
||||
m_ValidCount = 0;
|
||||
|
||||
return CMA_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Initialize KFDCMAArray based on array of testMemoryDescriptor. Usually testMemoryDescriptor[] is
|
||||
* statically defined array by the user. Only items with non-zero size are considered valid
|
||||
*/
|
||||
CMA_TEST_STATUS KFDCMAArray::Init(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE], int node) {
|
||||
CMA_TEST_STATUS err = CMA_TEST_SUCCESS;
|
||||
memset(m_MemArray, 0, sizeof(m_MemArray));
|
||||
memset(m_HsaMemoryRange, 0, sizeof(m_HsaMemoryRange));
|
||||
|
||||
m_ValidCount = 0;
|
||||
for (int i = 0; i < CMA_MEMORY_TEST_ARRAY_SIZE; i++) {
|
||||
if ((*memDescriptor)[i].m_MemSize == 0)
|
||||
continue;
|
||||
|
||||
switch ((*memDescriptor)[i].m_MemType) {
|
||||
case CMA_MEM_TYPE_SYSTEM:
|
||||
m_MemArray[i] = new HsaMemoryBuffer((*memDescriptor)[i].m_MemSize, node);
|
||||
break;
|
||||
|
||||
case CMA_MEM_TYPE_USERPTR:
|
||||
{
|
||||
void *userPtr = malloc((*memDescriptor)[i].m_MemSize);
|
||||
m_MemArray[i] = new HsaMemoryBuffer(userPtr, (*memDescriptor)[i].m_MemSize);
|
||||
break;
|
||||
}
|
||||
|
||||
case CMA_MEM_TYPE_LOCAL_MEM:
|
||||
m_MemArray[i] = new HsaMemoryBuffer((*memDescriptor)[i].m_MemSize, node, false, true);
|
||||
break;
|
||||
}
|
||||
|
||||
if (m_MemArray[i]) {
|
||||
m_HsaMemoryRange[i].MemoryAddress = m_MemArray[i]->As<void*>();
|
||||
m_HsaMemoryRange[i].SizeInBytes = m_MemArray[i]->Size();
|
||||
m_ValidCount++;
|
||||
} else {
|
||||
err = CMA_TEST_NOMEM;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
/* Fill each buffer of KFDCMAArray with the pattern described by testMemoryDescriptor[] */
|
||||
void KFDCMAArray::FillPattern(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE]) {
|
||||
SDMAQueue sdmaQueue;
|
||||
bool queueCreated = false;
|
||||
unsigned int queueNode;
|
||||
|
||||
for (int i = 0; i < m_ValidCount; i++) {
|
||||
if (m_MemArray[i]->isLocal())
|
||||
m_MemArray[i]->Fill((*memDescriptor)[i].m_FillPattern, *m_QueueArray.GetQueue(m_MemArray[i]->Node()));
|
||||
else
|
||||
m_MemArray[i]->Fill((*memDescriptor)[i].m_FillPattern);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check the first and last item of each buffer in KFDCMAArray with the pattern described by
|
||||
* testMemoryDescriptor[]. Return 0 on success.
|
||||
*/
|
||||
CMA_TEST_STATUS KFDCMAArray::checkPattern(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE]) {
|
||||
HSAuint64 lastItem;
|
||||
CMA_TEST_STATUS ret = CMA_TEST_SUCCESS;
|
||||
unsigned int queueNode = 0;
|
||||
bool queueCreated = false;
|
||||
HsaMemoryBuffer tmpBuffer(PAGE_SIZE, 0, true /* zero */);
|
||||
volatile HSAuint32 *tmp = tmpBuffer.As<volatile HSAuint32 *>();
|
||||
|
||||
for (int i = 0; i < m_ValidCount; i++) {
|
||||
lastItem = m_MemArray[i]->Size();
|
||||
lastItem -= sizeof(HSAuint32);
|
||||
|
||||
if (m_MemArray[i]->isLocal()) {
|
||||
BaseQueue *sdmaQueue = m_QueueArray.GetQueue(m_MemArray[i]->Node());
|
||||
|
||||
if (!m_MemArray[i]->IsPattern(0, (*memDescriptor)[i].m_CheckFirstWordPattern, *sdmaQueue, tmp) ||
|
||||
!m_MemArray[i]->IsPattern(lastItem, (*memDescriptor)[i].m_CheckLastWordPattern, *sdmaQueue, tmp)) {
|
||||
ret = CMA_CHECK_PATTERN_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
if (!m_MemArray[i]->IsPattern(0, (*memDescriptor)[i].m_CheckFirstWordPattern) ||
|
||||
!m_MemArray[i]->IsPattern(lastItem, (*memDescriptor)[i].m_CheckLastWordPattern)) {
|
||||
ret = CMA_CHECK_PATTERN_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/* Non-blocking read and write to avoid Test from hanging (block indefinitely)
|
||||
* if either server or client process exits due to assert failure
|
||||
*/
|
||||
static int write_non_block(int fd, const void *buf, int size) {
|
||||
int total_bytes = 0, cur_bytes = 0;
|
||||
int retries = 5;
|
||||
struct timespec tm = { 0, 10000000ULL };
|
||||
const char *ptr = (const char *)buf;
|
||||
|
||||
do {
|
||||
cur_bytes = write(fd, ptr, (size - total_bytes));
|
||||
|
||||
if (cur_bytes < 0 && errno != EAGAIN)
|
||||
return cur_bytes;
|
||||
|
||||
if (cur_bytes > 0) {
|
||||
total_bytes += cur_bytes;
|
||||
ptr += cur_bytes;
|
||||
}
|
||||
|
||||
if (total_bytes < size)
|
||||
nanosleep(&tm, NULL);
|
||||
} while (total_bytes < size && retries--);
|
||||
|
||||
/* Check for overflow */
|
||||
if (total_bytes > size)
|
||||
return -1;
|
||||
|
||||
return total_bytes;
|
||||
}
|
||||
|
||||
static int read_non_block(int fd, void *buf, int size) {
|
||||
int total_bytes = 0, cur_bytes = 0;
|
||||
int retries = 5;
|
||||
struct timespec tm = { 0, 100000000ULL };
|
||||
char *ptr = (char *)buf;
|
||||
|
||||
do {
|
||||
cur_bytes = read(fd, ptr, (size - total_bytes));
|
||||
|
||||
if (cur_bytes < 0 && errno != EAGAIN)
|
||||
return cur_bytes;
|
||||
|
||||
if (cur_bytes > 0) {
|
||||
total_bytes += cur_bytes;
|
||||
ptr += cur_bytes;
|
||||
}
|
||||
|
||||
if (total_bytes < size)
|
||||
nanosleep(&tm, NULL);
|
||||
} while (total_bytes < size && retries--);
|
||||
|
||||
if (total_bytes > size)
|
||||
return -1;
|
||||
|
||||
return total_bytes;
|
||||
}
|
||||
|
||||
|
||||
/* Send HsaMemoryRange to another process that is connected via writePipe */
|
||||
CMA_TEST_STATUS KFDCMAArray::sendCMAArray(int writePipe) {
|
||||
if (write_non_block(writePipe, (void*)&m_HsaMemoryRange, sizeof(m_HsaMemoryRange)) !=
|
||||
sizeof(m_HsaMemoryRange))
|
||||
return CMA_IPC_PIPE_ERROR;
|
||||
return CMA_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
/* Send HsaMemoryRange from another process and initialize KFDCMAArray */
|
||||
CMA_TEST_STATUS KFDCMAArray::recvCMAArray(int readPipe) {
|
||||
int i;
|
||||
|
||||
if (read_non_block(readPipe, (void*)&m_HsaMemoryRange, sizeof(m_HsaMemoryRange)) !=
|
||||
sizeof(m_HsaMemoryRange))
|
||||
return CMA_IPC_PIPE_ERROR;
|
||||
|
||||
for (i = 0; i < CMA_MEMORY_TEST_ARRAY_SIZE; i++) {
|
||||
if (m_HsaMemoryRange[i].SizeInBytes)
|
||||
m_ValidCount++;
|
||||
}
|
||||
return CMA_TEST_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
CMA_TEST_STATUS KFDIPCTest::CrossMemoryAttachChildProcess(int defaultGPUNode, int writePipe,
|
||||
int readPipe, CMA_TEST_TYPE testType) {
|
||||
KFDCMAArray cmaLocalArray;
|
||||
char msg[16];
|
||||
int testNo;
|
||||
CMA_TEST_STATUS status;
|
||||
|
||||
/* Initialize and fill Local Buffer Array with a pattern.
|
||||
* READ_TEST: Send the Array to parent process. Wait for the parent
|
||||
* to finish reading and checking. Then move to next text case or
|
||||
* quit if last one.
|
||||
* WRITE_TEST: Send Local Buffer Array to parent process and and wait
|
||||
* for parent to write to it. Check for new pattern. Then move to next
|
||||
* case or quit if last one.
|
||||
*/
|
||||
for (testNo = 0; testNo < CMA_TEST_COUNT; testNo++) {
|
||||
if (testType == CMA_READ_TEST) {
|
||||
cmaLocalArray.Init(&srcRange[testNo], defaultGPUNode);
|
||||
cmaLocalArray.FillPattern(&srcRange[testNo]);
|
||||
} else {
|
||||
cmaLocalArray.Init(&dstRange[testNo], defaultGPUNode);
|
||||
cmaLocalArray.FillPattern(&dstRange[testNo]);
|
||||
}
|
||||
|
||||
if (cmaLocalArray.sendCMAArray(writePipe) < 0) {
|
||||
status = CMA_IPC_PIPE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Wait till the test is over */
|
||||
memset(msg, 0, sizeof(msg));
|
||||
if (read_non_block(readPipe, msg, 4) < 0) {
|
||||
status = CMA_IPC_PIPE_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
if (!strcmp(msg, "CHCK"))
|
||||
status = cmaLocalArray.checkPattern(&dstRange[testNo]);
|
||||
else if (!strcmp(msg, "NEXT"))
|
||||
status = CMA_TEST_SUCCESS;
|
||||
else if (!strcmp(msg, "EXIT"))
|
||||
status = CMA_TEST_ABORT;
|
||||
else
|
||||
status = CMA_PARENT_FAIL;
|
||||
|
||||
cmaLocalArray.Destroy();
|
||||
if (status != CMA_TEST_SUCCESS)
|
||||
break;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
CMA_TEST_STATUS KFDIPCTest::CrossMemoryAttachParentProcess(int defaultGPUNode, pid_t cid,
|
||||
int writePipe, int readPipe,
|
||||
CMA_TEST_TYPE testType) {
|
||||
KFDCMAArray cmaLocalArray, cmaRemoteArray;
|
||||
HSAuint64 copied = 0;
|
||||
int testNo;
|
||||
CMA_TEST_STATUS status;
|
||||
|
||||
/* Recevie buffer array from child and then initialize and fill in Local Buffer Array.
|
||||
* READ_TEST: Copy remote buffer array into Local Buffer Array and then check
|
||||
* for the new pattern.
|
||||
* WRITE_TEST: Write Local Buffer Array into remote buffer array. Notify child to
|
||||
* to check for the new pattern.
|
||||
*/
|
||||
for (testNo = 0; testNo < CMA_TEST_COUNT; testNo++) {
|
||||
status = cmaRemoteArray.recvCMAArray(readPipe);
|
||||
if (status != CMA_TEST_SUCCESS)
|
||||
break;
|
||||
|
||||
if (testType == CMA_READ_TEST) {
|
||||
status = cmaLocalArray.Init(&dstRange[testNo], defaultGPUNode);
|
||||
if (status != CMA_TEST_SUCCESS)
|
||||
break;
|
||||
cmaLocalArray.FillPattern(&dstRange[testNo]);
|
||||
|
||||
if (hsaKmtProcessVMRead(cid, cmaLocalArray.getMemoryRange(),
|
||||
cmaLocalArray.getValidRangeCount(),
|
||||
cmaRemoteArray.getMemoryRange(),
|
||||
cmaRemoteArray.getValidRangeCount(),
|
||||
&copied) != HSAKMT_STATUS_SUCCESS) {
|
||||
status = CMA_TEST_HSA_READ_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
status = cmaLocalArray.checkPattern(&dstRange[testNo]);
|
||||
if (status != CMA_TEST_SUCCESS)
|
||||
break;
|
||||
|
||||
cmaLocalArray.Destroy();
|
||||
cmaRemoteArray.Destroy();
|
||||
|
||||
if (write_non_block(writePipe, "NEXT", 4) < 0) {
|
||||
status = CMA_IPC_PIPE_ERROR;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
status = cmaLocalArray.Init(&srcRange[testNo], defaultGPUNode);
|
||||
if (status != CMA_TEST_SUCCESS)
|
||||
break;
|
||||
cmaLocalArray.FillPattern(&srcRange[testNo]);
|
||||
|
||||
if (hsaKmtProcessVMWrite(cid, cmaLocalArray.getMemoryRange(),
|
||||
cmaLocalArray.getValidRangeCount(),
|
||||
cmaRemoteArray.getMemoryRange(),
|
||||
cmaRemoteArray.getValidRangeCount(),
|
||||
&copied) != HSAKMT_STATUS_SUCCESS) {
|
||||
status = CMA_TEST_HSA_WRITE_FAIL;
|
||||
break;
|
||||
}
|
||||
|
||||
cmaLocalArray.Destroy();
|
||||
cmaRemoteArray.Destroy();
|
||||
if (write_non_block(writePipe, "CHCK", 4) < 0) {
|
||||
status = CMA_IPC_PIPE_ERROR;
|
||||
break;
|
||||
}
|
||||
}
|
||||
} /* for loop */
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
/* Test Cross Memory Attach
|
||||
* hsaKmtProcessVMRead and hsaKmtProcessVMWrite are GPU address equivalent to
|
||||
* process_vm_readv and process_vm_writev. These calls transfer data between
|
||||
* the address space of the calling process ("the local process") and the process
|
||||
* identified by pid ("the remote process").
|
||||
*
|
||||
* In the tests parent process will be the local process and child will be
|
||||
* the remote.
|
||||
*/
|
||||
TEST_F(KFDIPCTest, CrossMemoryAttachTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
int pipeCtoP[2], pipePtoC[2];
|
||||
int status;
|
||||
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (!GetVramSize(defaultGPUNode)) {
|
||||
LOG() << "Skip the test because of no VRAM found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Create Pipes for communicating shared handles */
|
||||
ASSERT_EQ(pipe2(pipeCtoP, O_NONBLOCK), 0);
|
||||
ASSERT_EQ(pipe2(pipePtoC, O_NONBLOCK), 0);
|
||||
|
||||
/* Create a child process and share the above Local Memory with it */
|
||||
|
||||
m_ChildPid = fork();
|
||||
if (m_ChildPid == 0 && hsaKmtOpenKFD() == HSAKMT_STATUS_SUCCESS) {
|
||||
/* Child Process */
|
||||
status = CrossMemoryAttachChildProcess(defaultGPUNode, pipeCtoP[1],
|
||||
pipePtoC[0], CMA_READ_TEST);
|
||||
ASSERT_EQ(status, CMA_TEST_SUCCESS) << "Child: Read Test Fail";
|
||||
status = CrossMemoryAttachChildProcess(defaultGPUNode, pipeCtoP[1],
|
||||
pipePtoC[0], CMA_WRITE_TEST);
|
||||
ASSERT_EQ(status, CMA_TEST_SUCCESS) << "Child: Write Test Fail";
|
||||
} else {
|
||||
int childStatus;
|
||||
|
||||
status = CrossMemoryAttachParentProcess(defaultGPUNode, m_ChildPid,
|
||||
pipePtoC[1], pipeCtoP[0], CMA_READ_TEST); /* Parent proces */
|
||||
ASSERT_EQ(status, CMA_TEST_SUCCESS) << "Parent: Read Test Fail";
|
||||
status = CrossMemoryAttachParentProcess(defaultGPUNode, m_ChildPid,
|
||||
pipePtoC[1], pipeCtoP[0], CMA_WRITE_TEST);
|
||||
ASSERT_EQ(status, CMA_TEST_SUCCESS) << "Parent: Write Test Fail";
|
||||
|
||||
waitpid(m_ChildPid, &childStatus, 0);
|
||||
ASSERT_EQ(WIFEXITED(childStatus), true);
|
||||
ASSERT_EQ(WEXITSTATUS(childStatus), 0);
|
||||
}
|
||||
|
||||
/* Code path executed by both parent and child with respective fds */
|
||||
close(pipeCtoP[1]);
|
||||
close(pipeCtoP[0]);
|
||||
close(pipePtoC[1]);
|
||||
close(pipePtoC[0]);
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Test Cross Memory Attach
|
||||
*
|
||||
* hsaKmtProcessVMRead and hsaKmtProcessVMWrite are GPU address equivalent to
|
||||
* process_vm_readv and process_vm_writev. These calls are used to transfer data
|
||||
* between the address space of the calling process ("the local process") and the process
|
||||
* identified by pid ("the remote process"). However, these functions should also work
|
||||
* with a single process and single BO.
|
||||
*/
|
||||
TEST_F(KFDIPCTest, CMABasicTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
HSAuint64 size = PAGE_SIZE;
|
||||
SDMAQueue sdmaQueue;
|
||||
HsaMemoryRange srcRange, dstRange;
|
||||
HSAuint64 copied;
|
||||
const int PATTERN1 = 0xA5A5A5A5, PATTERN2 = 0xFFFFFFFF;
|
||||
HSAKMT_STATUS status;
|
||||
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (!GetVramSize(defaultGPUNode)) {
|
||||
LOG() << "Skip the test because of no VRAM found" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT_SUCCESS(sdmaQueue.Create(defaultGPUNode));
|
||||
HsaMemoryBuffer tmpBuffer(PAGE_SIZE, 0, true /* zero */);
|
||||
volatile HSAuint32 *tmp = tmpBuffer.As<volatile HSAuint32 *>();
|
||||
|
||||
/* Initialize test buffer. Fill first half and second half with
|
||||
* different pattern
|
||||
*/
|
||||
HsaMemoryBuffer testLocalBuffer(size, defaultGPUNode, false, true);
|
||||
testLocalBuffer.Fill(PATTERN1, sdmaQueue, 0, size/2);
|
||||
testLocalBuffer.Fill(PATTERN2, sdmaQueue, size/2, size/2);
|
||||
|
||||
/* Test1. Copy (or overwrite) buffer onto itself */
|
||||
srcRange.MemoryAddress = testLocalBuffer.As<void*>();
|
||||
srcRange.SizeInBytes = size;
|
||||
dstRange.MemoryAddress = testLocalBuffer.As<void*>();
|
||||
dstRange.SizeInBytes = size;
|
||||
ASSERT_SUCCESS(hsaKmtProcessVMRead(getpid(), &dstRange, 1, &srcRange, 1, &copied));
|
||||
ASSERT_EQ(copied, size);
|
||||
|
||||
ASSERT_TRUE(testLocalBuffer.IsPattern(0, PATTERN1, sdmaQueue, tmp));
|
||||
ASSERT_TRUE(testLocalBuffer.IsPattern(size - 4, PATTERN2, sdmaQueue, tmp));
|
||||
|
||||
|
||||
/* Test2. Test unaligned byte copy. Write 3 bytes to an unaligned destination address */
|
||||
const int unaligned_offset = 1;
|
||||
const int unaligned_size = 3;
|
||||
const int unaligned_mask = (((1 << (unaligned_size * 8)) - 1) << (unaligned_offset * 8));
|
||||
HSAuint32 expected_pattern;
|
||||
|
||||
srcRange.MemoryAddress = testLocalBuffer.As<void*>();
|
||||
srcRange.SizeInBytes = size; /* Deliberately set to value > unaligned_size. Only unaligned_size
|
||||
* should be copied since dstRange.SizeInBytes == unaligned_size
|
||||
*/
|
||||
dstRange.MemoryAddress = (void *)(testLocalBuffer.As<char*>() + (size / 2) + unaligned_offset);
|
||||
dstRange.SizeInBytes = unaligned_size;
|
||||
ASSERT_SUCCESS(hsaKmtProcessVMRead(getpid(), &dstRange, 1, &srcRange, 1, &copied));
|
||||
ASSERT_EQ(copied, unaligned_size);
|
||||
|
||||
expected_pattern = (PATTERN2 & ~unaligned_mask | (PATTERN1 & unaligned_mask));
|
||||
ASSERT_TRUE(testLocalBuffer.IsPattern(size/2, expected_pattern, sdmaQueue, tmp));
|
||||
|
||||
|
||||
/* Test3. Test overflow and expect failure */
|
||||
srcRange.MemoryAddress = testLocalBuffer.As<void*>();
|
||||
srcRange.SizeInBytes = size;
|
||||
dstRange.MemoryAddress = (void *)(testLocalBuffer.As<char*>() + 4);
|
||||
dstRange.SizeInBytes = size; /* This should overflow since offset is VA + 4 */
|
||||
status = hsaKmtProcessVMRead(getpid(), &dstRange, 1, &srcRange, 1, &copied);
|
||||
EXPECT_NE(status, HSAKMT_STATUS_SUCCESS);
|
||||
EXPECT_LE(copied, (size - 4));
|
||||
|
||||
ASSERT_SUCCESS(sdmaQueue.Destroy());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
* Copyright (C) 2017-2018 Advanced Micro Devices, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
#include "BaseQueue.hpp"
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
#ifndef __KFD_MEMORY_TEST__H__
|
||||
#define __KFD_MEMORY_TEST__H__
|
||||
|
||||
#define CMA_MEMORY_TEST_ARRAY_SIZE 4
|
||||
#define CMA_TEST_COUNT 3
|
||||
|
||||
enum CMA_MEM_TYPE {
|
||||
CMA_MEM_TYPE_SYSTEM = 0,
|
||||
CMA_MEM_TYPE_USERPTR,
|
||||
CMA_MEM_TYPE_LOCAL_MEM,
|
||||
};
|
||||
|
||||
enum CMA_TEST_TYPE {
|
||||
CMA_READ_TEST = 0,
|
||||
CMA_WRITE_TEST
|
||||
};
|
||||
|
||||
enum CMA_TEST_STATUS {
|
||||
CMA_TEST_SUCCESS = 0,
|
||||
CMA_IPC_PIPE_ERROR = 1,
|
||||
CMA_CHECK_PATTERN_ERROR,
|
||||
CMA_TEST_ABORT,
|
||||
CMA_TEST_NOMEM,
|
||||
CMA_PARENT_FAIL,
|
||||
CMA_TEST_HSA_READ_FAIL,
|
||||
CMA_TEST_HSA_WRITE_FAIL
|
||||
};
|
||||
|
||||
// @struct testMemoryDescriptor
|
||||
// Describes test buffers for Cross Memory Attach Test.
|
||||
struct testMemoryDescriptor {
|
||||
CMA_MEM_TYPE m_MemType;
|
||||
HSAuint64 m_MemSize;
|
||||
/* The buffer will be initialized with this pattern */
|
||||
HSAuint32 m_FillPattern;
|
||||
/* After CMA test, this pattern is expected in the first word */
|
||||
HSAuint32 m_CheckFirstWordPattern;
|
||||
/* After CMA test, this pattern is expected in the last word */
|
||||
HSAuint32 m_CheckLastWordPattern;
|
||||
|
||||
testMemoryDescriptor(CMA_MEM_TYPE memType, HSAuint64 memSize,
|
||||
HSAuint32 fillPattern, HSAuint32 firstCheckPattern,
|
||||
HSAuint32 lastCheckPattern) :
|
||||
m_MemType(memType),
|
||||
m_MemSize(memSize),
|
||||
m_FillPattern(fillPattern),
|
||||
m_CheckFirstWordPattern(firstCheckPattern),
|
||||
m_CheckLastWordPattern(lastCheckPattern) {}
|
||||
~testMemoryDescriptor(){}
|
||||
};
|
||||
|
||||
// @class KFDCMAArray
|
||||
// Array of buffers that will be passed between the parent and child
|
||||
// process for Cross memory read and write tests
|
||||
class KFDCMAArray {
|
||||
/* Used to store the actual buffer array */
|
||||
HsaMemoryBuffer* m_MemArray[CMA_MEMORY_TEST_ARRAY_SIZE];
|
||||
/* Used for passing to thunk CMA functions */
|
||||
HsaMemoryRange m_HsaMemoryRange[CMA_MEMORY_TEST_ARRAY_SIZE];
|
||||
/* Though previous arrays are fixed sizes only m_ValidCount
|
||||
* ones are valid
|
||||
*/
|
||||
HSAuint64 m_ValidCount;
|
||||
QueueArray m_QueueArray;
|
||||
|
||||
public:
|
||||
KFDCMAArray();
|
||||
~KFDCMAArray() {
|
||||
Destroy();
|
||||
}
|
||||
|
||||
CMA_TEST_STATUS Init(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE], int node);
|
||||
CMA_TEST_STATUS Destroy();
|
||||
|
||||
HsaMemoryRange* getMemoryRange() { return m_HsaMemoryRange; }
|
||||
HSAuint64 getValidRangeCount() { return m_ValidCount; }
|
||||
void FillPattern(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE]);
|
||||
CMA_TEST_STATUS checkPattern(testMemoryDescriptor(*memDescriptor)[CMA_MEMORY_TEST_ARRAY_SIZE]);
|
||||
CMA_TEST_STATUS sendCMAArray(int writePipe);
|
||||
CMA_TEST_STATUS recvCMAArray(int readPipe);
|
||||
};
|
||||
|
||||
|
||||
// @class KFDIPCTest
|
||||
class KFDIPCTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDIPCTest(void) : m_ChildPid(-1) {}
|
||||
~KFDIPCTest(void);
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
/* For IPC testing */
|
||||
void BasicTestChildProcess(int defaultGPUNode, int *pipefd);
|
||||
void BasicTestParentProcess(int defaultGPUNode, pid_t childPid, int *pipefd);
|
||||
|
||||
/* For CMA testing */
|
||||
CMA_TEST_STATUS CrossMemoryAttachChildProcess(int defaultGPUNode, int writePipe,
|
||||
int readPipe, CMA_TEST_TYPE testType);
|
||||
CMA_TEST_STATUS CrossMemoryAttachParentProcess(int defaultGPUNode, pid_t cid,
|
||||
int writePipe, int readPipe, CMA_TEST_TYPE testType);
|
||||
protected:
|
||||
pid_t m_ChildPid;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@@ -0,0 +1,528 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDLocalMemoryTest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
// All tests are marked by their serial number in the QCM FDD
|
||||
|
||||
void KFDLocalMemoryTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
m_pIsaGen = IsaGenerator::Create(m_FamilyId);
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDLocalMemoryTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
if (m_pIsaGen)
|
||||
delete m_pIsaGen;
|
||||
m_pIsaGen = NULL;
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(KFDLocalMemoryTest, BasicTest) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
PM4Queue queue;
|
||||
HSAuint64 AlternateVAGPU;
|
||||
unsigned int BufferSize = PAGE_SIZE;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (!GetVramSize(defaultGPUNode)) {
|
||||
LOG() << "No VRAM found, skipping the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
HsaMemoryBuffer srcSysBuffer(BufferSize, defaultGPUNode, false);
|
||||
HsaMemoryBuffer destSysBuffer(BufferSize, defaultGPUNode);
|
||||
HsaMemoryBuffer srcLocalBuffer(BufferSize, defaultGPUNode, false, true);
|
||||
HsaMemoryBuffer dstLocalBuffer(BufferSize, defaultGPUNode, false, true);
|
||||
|
||||
srcSysBuffer.Fill(0x01010101);
|
||||
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(srcLocalBuffer.As<void*>(), srcLocalBuffer.Size(), &AlternateVAGPU));
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(dstLocalBuffer.As<void*>(), dstLocalBuffer.Size(), &AlternateVAGPU));
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
queue.SetSkipWaitConsump(0);
|
||||
|
||||
Dispatch dispatch(isaBuffer);
|
||||
|
||||
dispatch.SetArgs(srcSysBuffer.As<void*>(), srcLocalBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
dispatch.SetArgs(srcLocalBuffer.As<void*>(), dstLocalBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
dispatch.SetArgs(dstLocalBuffer.As<void*>(), destSysBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(srcLocalBuffer.As<void*>()));
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(dstLocalBuffer.As<void*>()));
|
||||
ASSERT_EQ(destSysBuffer.As<unsigned int*>()[0], 0x01010101);
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDLocalMemoryTest, VerifyContentsAfterUnmapAndMap) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
PM4Queue queue;
|
||||
HSAuint64 AlternateVAGPU;
|
||||
unsigned int BufferSize = PAGE_SIZE;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
if (!GetVramSize(defaultGPUNode)) {
|
||||
LOG() << "No VRAM found, skipping the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
HsaMemoryBuffer SysBufferA(BufferSize, defaultGPUNode, false);
|
||||
HsaMemoryBuffer SysBufferB(BufferSize, defaultGPUNode, true);
|
||||
HsaMemoryBuffer LocalBuffer(BufferSize, defaultGPUNode, true, true);
|
||||
|
||||
SysBufferA.Fill(0x01010101);
|
||||
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
queue.SetSkipWaitConsump(0);
|
||||
|
||||
if (!is_dgpu())
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(LocalBuffer.As<void*>(), LocalBuffer.Size(), &AlternateVAGPU));
|
||||
|
||||
Dispatch dispatch(isaBuffer);
|
||||
|
||||
dispatch.SetArgs(SysBufferA.As<void*>(), LocalBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(LocalBuffer.As<void*>()));
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(LocalBuffer.As<void*>(), LocalBuffer.Size(), &AlternateVAGPU));
|
||||
|
||||
dispatch.SetArgs(LocalBuffer.As<void*>(), SysBufferB.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
ASSERT_EQ(SysBufferB.As<unsigned int*>()[0], 0x01010101);
|
||||
if (!is_dgpu())
|
||||
ASSERT_SUCCESS(hsaKmtUnmapMemoryToGPU(LocalBuffer.As<void*>()));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
/* Deliberately fragment GPUVM aperture to fill up address space
|
||||
*
|
||||
* General idea: Allocate buffers, but don't map them to GPU. This
|
||||
* will reserve virtual address space without pinning physical
|
||||
* memory. It should allow using more address space than physically
|
||||
* available memory.
|
||||
*
|
||||
* Even without pinning memory, TTM will still commit memory at
|
||||
* allocation time and swap out movable buffers to system memory or
|
||||
* even the hard drive, if it needs to. So we can't allocate arbitrary
|
||||
* amounts of virtual memory.
|
||||
*
|
||||
* Strategy to maximize the amount of allocated, fragmented address
|
||||
* space while keeping the amount of committed memory bounded at all
|
||||
* times:
|
||||
*
|
||||
* 1. Allocate N blocks of a given size, initially 1 page
|
||||
* 2. Free every other block, creating holes in the address space.
|
||||
* This frees up half the memory
|
||||
* 3. Allocate N/4 blocks of 2-pages each. This requires as much
|
||||
* memory as was freed in step 2. The block size is bigger than
|
||||
* the 1-page holes, so new address space will be used.
|
||||
* 4. Free half the blocks just allocated, and half of the
|
||||
* remaining blocks of step 1. This creates 3-page holes between
|
||||
* the 1-page blocks from step 1, and 2-page holes between the
|
||||
* 2-page blocks from step 3. It frees up half of the total
|
||||
* memory.
|
||||
* 5. Double the block size to 4, devide number of blocks by 2.
|
||||
* Again, this will require the amount of memory freed in step 4.
|
||||
* The block size 4 is bigger than the biggest hole (3 pages).
|
||||
* 6. Free half the memory again, creating 7-page holes between
|
||||
* 1-page blocks, 6-page holes between 2-page blocks, and 4-page
|
||||
* holes between 4-page blocks.
|
||||
*
|
||||
* Repeat, doubling block size and halving number of blocks in each
|
||||
* iteration. Each iteration starts and ends with half the total
|
||||
* memory free. Because the block size is always bigger than the
|
||||
* biggest hole, each iteration increases the amount of address space
|
||||
* occupied by half the total memory size. Once the block size reaches
|
||||
* half of the free memory (1/4 of total memory) the limit is reached.
|
||||
*
|
||||
* With 2^n pages available memory, n * 2^(n-1) pages of address space
|
||||
* can be reserved. At the end of that process, half the memory will
|
||||
* be free.
|
||||
*
|
||||
* Total memory | Fragmented address space
|
||||
* order | pages | size | pages | size | ratio
|
||||
* ------+-------+------+-------+-------+-------
|
||||
* 2 | 4 | 16K | 4 | 16K | 1
|
||||
* 3 | 8 | 32K | 12 | 48K | 1.5
|
||||
* 4 | 16 | 64K | 32 | 128K | 2
|
||||
* 5 | 32 | 128K | 80 | 320K | 2.5
|
||||
* 6 | 64 | 256K | 192 | 768K | 3
|
||||
* 7 | 128 | 512K | 448 | 1.75M | 3.5
|
||||
* 8 | 256 | 1M | 1M | 4M | 4
|
||||
* 9 | 512 | 2M | 2.25M | 9M | 4.5
|
||||
* 10 | 1K | 4M | 5M | 20M | 5
|
||||
* 11 | 2K | 8M | 11M | 44M | 5.5
|
||||
* 12 | 4K | 16M | 24M | 96M | 6
|
||||
* 13 | 8K | 32M | 52M | 208M | 6.5
|
||||
* 14 | 16K | 64M | 112M | 448M | 7
|
||||
* 15 | 32K | 128M | 240M | 960M | 7.5
|
||||
* 16 | 64K | 256M | 512M | 2G | 8
|
||||
* 17 | 128K | 512M | 1088M | 4.25G | 8.5
|
||||
* 18 | 256K | 1G | 2.25G | 9G | 9
|
||||
* 19 | 512K | 2G | 4.75G | 19G | 9.5
|
||||
* 20 | 1M | 4G | 10G | 40G | 10
|
||||
*/
|
||||
TEST_F(KFDLocalMemoryTest, Fragmentation) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
HSAuint64 fbSize;
|
||||
|
||||
fbSize = GetVramSize(defaultGPUNode);
|
||||
|
||||
if (!fbSize) {
|
||||
LOG() << "No VRAM found, skipping test." << std::endl;
|
||||
return;
|
||||
} else {
|
||||
LOG() << "Found VRAM of " << std::dec << (fbSize >> 20) << "MB." << std::endl;
|
||||
}
|
||||
|
||||
/* Use up to half of available memory. Using more results in
|
||||
* excessive memory movement in TTM and slows down the test too
|
||||
* much. maxOrder is the size of the biggest block that will be
|
||||
* allocated. It's 1/4 of the usable memory, so 1/8 the total FB
|
||||
* size in pages.
|
||||
*
|
||||
* Use 8x bigger page size on dGPU to match Tonga alignment
|
||||
* workaround. Also nicely matches the 8x bigger GPUVM address
|
||||
* space on AMDGPU compared to RADEON.
|
||||
*/
|
||||
unsigned pageSize = is_dgpu() ? PAGE_SIZE*8 : PAGE_SIZE;
|
||||
fbSize /= pageSize;
|
||||
unsigned maxOrder = 0;
|
||||
// Limit maxOrder up to 14 so this test doesn't run longer than 10 mins
|
||||
while (((fbSize >> maxOrder) >= 16) && (maxOrder < 14))
|
||||
maxOrder++;
|
||||
|
||||
/* Queue and memory used by the shader copy tests */
|
||||
HsaMemoryBuffer sysBuffer(PAGE_SIZE, defaultGPUNode, false);
|
||||
PM4Queue queue;
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
|
||||
/* Allocate and test memory using the strategy explained at the top */
|
||||
HSAKMT_STATUS status;
|
||||
HsaMemFlags memFlags = {0};
|
||||
memFlags.ui32.PageSize = HSA_PAGE_SIZE_4KB;
|
||||
memFlags.ui32.HostAccess = 0;
|
||||
memFlags.ui32.NonPaged = 1;
|
||||
struct {
|
||||
void **pointers;
|
||||
unsigned long nPages;
|
||||
} pages[maxOrder+1];
|
||||
unsigned order, o;
|
||||
unsigned long p;
|
||||
HSAuint64 size;
|
||||
unsigned value = 0;
|
||||
memset(pages, 0, sizeof(pages));
|
||||
for (order = 0; order <= maxOrder; order++) {
|
||||
// At maxOrder, block sizes is 1/4 of available memory
|
||||
pages[order].nPages = 1UL << (maxOrder - order + 2);
|
||||
// At order != 0, 1/2 the memory is already allocated
|
||||
if (order > 0)
|
||||
pages[order].nPages >>= 1;
|
||||
// Allocate page pointers
|
||||
pages[order].pointers = new void *[pages[order].nPages];
|
||||
EXPECT_NE((void **)NULL, pages[order].pointers)
|
||||
<< "Couldn't allocate memory for " << pages[order].nPages
|
||||
<< " pointers at order " << order << std::endl;
|
||||
if (!pages[order].pointers) {
|
||||
pages[order].nPages = 0;
|
||||
break;
|
||||
}
|
||||
/* Allocate buffers and access the start and end of every one:
|
||||
* 1. Copy from sysBuffer[0] to start of block
|
||||
* 2. Copy from start of block to end of block
|
||||
* 3. Copy from end of block to sysBuffer[1]
|
||||
* 4. Compare results */
|
||||
size = (HSAuint64)(1 << order) * pageSize;
|
||||
LOG() << std::dec << "Trying to allocate " << pages[order].nPages
|
||||
<< " order " << order << " blocks " << std::endl;
|
||||
for (p = 0; p < pages[order].nPages; p++) {
|
||||
status = hsaKmtAllocMemory(defaultGPUNode, size,
|
||||
memFlags, &pages[order].pointers[p]);
|
||||
if (status != HSAKMT_STATUS_SUCCESS) {
|
||||
EXPECT_EQ(HSAKMT_STATUS_NO_MEMORY, status);
|
||||
pages[order].nPages = p;
|
||||
break;
|
||||
}
|
||||
|
||||
void *bufferEnd = (void *)((unsigned long)pages[order].pointers[p]
|
||||
+ size - sizeof(unsigned));
|
||||
sysBuffer.As<unsigned *>()[0] = ++value;
|
||||
|
||||
status = hsaKmtMapMemoryToGPU(pages[order].pointers[p],
|
||||
size, NULL);
|
||||
if (status != HSAKMT_STATUS_SUCCESS) {
|
||||
ASSERT_SUCCESS(hsaKmtFreeMemory(pages[order].pointers[p],
|
||||
size));
|
||||
pages[order].nPages = p;
|
||||
break;
|
||||
}
|
||||
Dispatch dispatch1(isaBuffer);
|
||||
dispatch1.SetArgs(sysBuffer.As<void*>(), pages[order].pointers[p]);
|
||||
dispatch1.Submit(queue);
|
||||
// no sync needed for multiple GPU dispatches to the same queue
|
||||
|
||||
Dispatch dispatch2(isaBuffer);
|
||||
dispatch2.SetArgs(pages[order].pointers[p], bufferEnd);
|
||||
dispatch2.Submit(queue);
|
||||
// no sync needed for multiple GPU dispatches to the same queue
|
||||
|
||||
Dispatch dispatch3(isaBuffer);
|
||||
dispatch3.SetArgs(bufferEnd,
|
||||
(void *)&(sysBuffer.As<unsigned*>()[1]));
|
||||
dispatch3.Submit(queue);
|
||||
dispatch3.Sync(g_TestTimeOut);
|
||||
EXPECT_EQ(value, sysBuffer.As<unsigned *>()[1]);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtUnmapMemoryToGPU(pages[order].pointers[p]));
|
||||
}
|
||||
LOG() << " Got " << pages[order].nPages
|
||||
<< ", end of last block addr: "
|
||||
<< (void *)((unsigned long)pages[order].pointers[p-1] + size - 1)
|
||||
<< std::endl;
|
||||
|
||||
// Now free half the memory
|
||||
for (o = 0; o <= order; o++) {
|
||||
unsigned long step = 1UL << (order - o + 1);
|
||||
unsigned long offset = (step >> 1) - 1;
|
||||
size = (HSAuint64)(1 << o) * pageSize;
|
||||
LOG() << " Freeing every " << step << "th order "
|
||||
<< o << " block starting with " << offset << std::endl;
|
||||
for (p = offset; p < pages[o].nPages; p += step) {
|
||||
ASSERT_NE((void **)NULL, pages[o].pointers[p]);
|
||||
EXPECT_SUCCESS(hsaKmtFreeMemory(pages[o].pointers[p], size));
|
||||
pages[o].pointers[p] = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Clean up */
|
||||
for (order = 0; order <= maxOrder; order++) {
|
||||
if (pages[order].pointers == NULL)
|
||||
continue;
|
||||
|
||||
size = (HSAuint64)(1 << order) * pageSize;
|
||||
for (p = 0; p < pages[order].nPages; p++)
|
||||
if (pages[order].pointers[p] != NULL)
|
||||
EXPECT_SUCCESS(hsaKmtFreeMemory(pages[order].pointers[p], size));
|
||||
|
||||
delete[] pages[order].pointers;
|
||||
}
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDLocalMemoryTest, CheckZeroInitializationVram) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
/* Testing VRAM */
|
||||
HSAuint64 vramSizeMB = GetVramSize(defaultGPUNode) >> 20;
|
||||
|
||||
if (!vramSizeMB) {
|
||||
LOG() << "No VRAM found, skipping the test" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
HSAuint64 vramBufSizeMB = vramSizeMB >> 2;
|
||||
/* limit the buffer size in order not to overflow the SDMA queue buffer. */
|
||||
if (vramBufSizeMB > 1024) {
|
||||
vramBufSizeMB = 1024;
|
||||
}
|
||||
HSAuint64 vramBufSize = vramBufSizeMB * 1024 * 1024;
|
||||
|
||||
/* Make sure the entire VRAM is used at least once */
|
||||
int count = (vramSizeMB + vramBufSizeMB - 1) / vramBufSizeMB + 1;
|
||||
|
||||
LOG() << "Using " << std::dec << vramBufSizeMB
|
||||
<< "MB VRAM buffer to test " << std::dec << count
|
||||
<< " times"<< std::endl;
|
||||
|
||||
SDMAQueue sdmaQueue;
|
||||
ASSERT_SUCCESS(sdmaQueue.Create(defaultGPUNode, 8 * PAGE_SIZE));
|
||||
|
||||
HsaMemoryBuffer tmpBuffer(PAGE_SIZE, 0, true /* zero */);
|
||||
volatile HSAuint32 *tmp = tmpBuffer.As<volatile HSAuint32 *>();
|
||||
|
||||
unsigned int offset = 2060; // a constant offset, should be 4 aligned.
|
||||
|
||||
while (count--) {
|
||||
HsaMemoryBuffer localBuffer(vramBufSize, defaultGPUNode, false, true);
|
||||
|
||||
EXPECT_TRUE(localBuffer.IsPattern(0, 0, sdmaQueue, tmp));
|
||||
|
||||
for (HSAuint64 i = offset; i < vramBufSize;) {
|
||||
EXPECT_TRUE(localBuffer.IsPattern(i, 0, sdmaQueue, tmp));
|
||||
i += 4096;
|
||||
}
|
||||
|
||||
/* Checking last 4 bytes */
|
||||
EXPECT_TRUE(localBuffer.IsPattern(vramBufSize - 4, 0, sdmaQueue, tmp));
|
||||
|
||||
localBuffer.Fill(0xABCDEFFF, sdmaQueue);
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDLocalMemoryTest, MapVramToGPUNodesTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
HSAint32 src_node;
|
||||
HSAint32 dst_node;
|
||||
HsaPointerInfo info;
|
||||
|
||||
const std::vector<int> gpuNodes = m_NodeInfo.GetNodesWithGPU();
|
||||
if (gpuNodes.size() < 2) {
|
||||
LOG() << "Skipping test: Need at least two GPUs" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (g_TestDstNodeId != -1 && g_TestNodeId != -1) {
|
||||
src_node = g_TestNodeId;
|
||||
dst_node = g_TestDstNodeId;
|
||||
} else {
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
|
||||
dst_node = m_NodeInfo.FindLargeBarGPUNode();
|
||||
if (dst_node < 0) {
|
||||
LOG() << "Skipping test: Need at least one large bar GPU" << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (dst_node != defaultGPUNode) {
|
||||
/* at least one node should be defaultGPUNode */
|
||||
src_node = defaultGPUNode;
|
||||
} else {
|
||||
for (auto node : gpuNodes) {
|
||||
if (node != dst_node) {
|
||||
src_node = node;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LOG() << "Testing from GPU " << src_node << " to GPU " << dst_node << std::endl;
|
||||
|
||||
void *shared_addr;
|
||||
HSAuint32 nodes[] = { (HSAuint32)src_node, (HSAuint32)dst_node };
|
||||
HsaMemFlags memFlags = {0};
|
||||
memFlags.ui32.PageSize = HSA_PAGE_SIZE_4KB;
|
||||
memFlags.ui32.HostAccess = 1;
|
||||
memFlags.ui32.NonPaged = 1;
|
||||
memFlags.ui32.ExecuteAccess = 1;
|
||||
|
||||
HsaMemMapFlags mapFlags = {0};
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtAllocMemory(nodes[1], PAGE_SIZE, memFlags, &shared_addr));
|
||||
EXPECT_SUCCESS(hsaKmtRegisterMemoryToNodes(shared_addr, PAGE_SIZE, 2, nodes));
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPUNodes(shared_addr, PAGE_SIZE, NULL, mapFlags, 2, nodes));
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo(shared_addr, &info));
|
||||
EXPECT_EQ(info.NRegisteredNodes, 2);
|
||||
EXPECT_EQ(info.NMappedNodes, 2);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPUNodes(shared_addr, PAGE_SIZE, NULL, mapFlags, 1, &nodes[0]));
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo(shared_addr, &info));
|
||||
EXPECT_EQ(info.NRegisteredNodes, 2);
|
||||
EXPECT_EQ(info.NMappedNodes, 1);
|
||||
EXPECT_EQ(info.MappedNodes[0], nodes[0]);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPUNodes(shared_addr, PAGE_SIZE, NULL, mapFlags, 1, &nodes[1]));
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo(shared_addr, &info));
|
||||
EXPECT_EQ(info.NRegisteredNodes, 2);
|
||||
EXPECT_EQ(info.NMappedNodes, 1);
|
||||
EXPECT_EQ(info.MappedNodes[0], nodes[1]);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtUnmapMemoryToGPU(shared_addr));
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo(shared_addr, &info));
|
||||
EXPECT_EQ(info.NRegisteredNodes, 2);
|
||||
EXPECT_EQ(info.NMappedNodes, 0);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPUNodes(shared_addr, PAGE_SIZE, NULL, mapFlags, 1, &nodes[0]));
|
||||
EXPECT_SUCCESS(hsaKmtQueryPointerInfo(shared_addr, &info));
|
||||
EXPECT_EQ(info.NRegisteredNodes, 2);
|
||||
EXPECT_EQ(info.NMappedNodes, 1);
|
||||
EXPECT_EQ(info.MappedNodes[0], nodes[0]);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtUnmapMemoryToGPU(shared_addr));
|
||||
EXPECT_SUCCESS(hsaKmtFreeMemory(shared_addr, PAGE_SIZE));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_LOCALMEMORY_TEST__H__
|
||||
#define __KFD_LOCALMEMORY_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDLocalMemoryTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDLocalMemoryTest() :m_pIsaGen(NULL) {}
|
||||
~KFDLocalMemoryTest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected: // members
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __KFD_LOCALMEMORY_TEST__H__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
#include "IsaGenerator.hpp"
|
||||
|
||||
#ifndef __KFD_MEMORY_TEST__H__
|
||||
#define __KFD_MEMORY_TEST__H__
|
||||
|
||||
// @class KFDTopologyTest
|
||||
// this class has no additional features to KFDBaseComponentTest
|
||||
// the separation was made so we are able to goup all memeory tests together
|
||||
class KFDMemoryTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDMemoryTest(void) :m_pIsaGen(NULL) {}
|
||||
~KFDMemoryTest(void) {}
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
IsaGenerator* m_pIsaGen;
|
||||
|
||||
void BigBufferVRAM(int defaultGPUNode, HSAuint64 granularityMB, HSAuint64 *lastSize);
|
||||
void BigBufferSystemMemory(int defaultGPUNode, HSAuint64 granularityMB, HSAuint64 *lastSize);
|
||||
};
|
||||
|
||||
#endif // __KFD_MEMORY_TEST__H__
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDOpenCloseKFDTest.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
// before every test from this class fixture - open KFD
|
||||
void KFDOpenCloseKFDTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtOpenKFD() );
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
// after every test from this class fixture - close KFD
|
||||
void KFDOpenCloseKFDTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtCloseKFD() );
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
// this test does not use class KFDOpenCloseKFDTest but is placed here
|
||||
// since it's testing same topic as other test
|
||||
// verify that calling hsaKmtCloseKFD on a closed KFD will return right status
|
||||
TEST(KFDCloseKFDTest, CloseAClosedKfd ) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
ASSERT_EQ(HSAKMT_STATUS_KERNEL_IO_CHANNEL_NOT_OPENED, hsaKmtCloseKFD());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// verify that calling hsaKmtCloseKFD on an already opened KFD will return
|
||||
// right status
|
||||
TEST_F(KFDOpenCloseKFDTest, OpenAlreadyOpenedKFD ) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
EXPECT_EQ(HSAKMT_STATUS_KERNEL_ALREADY_OPENED, hsaKmtOpenKFD());
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtCloseKFD());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// testing the normal scenario: open followed by close (done in the setup and
|
||||
// teardown functions)
|
||||
TEST_F(KFDOpenCloseKFDTest, OpenCloseKFD ) {
|
||||
}
|
||||
|
||||
TEST_F(KFDOpenCloseKFDTest, InvalidKFDHandleTest ) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
HsaVersionInfo m_VersionInfo;
|
||||
pid_t m_ChildPid = fork();
|
||||
if (m_ChildPid == 0) {
|
||||
EXPECT_EQ(HSAKMT_STATUS_ERROR, hsaKmtGetVersion(&m_VersionInfo));
|
||||
exit(0);
|
||||
} else {
|
||||
int childStatus;
|
||||
EXPECT_EQ(m_ChildPid, waitpid(m_ChildPid, &childStatus, 0));
|
||||
EXPECT_NE(0, WIFEXITED(childStatus));
|
||||
EXPECT_EQ(0, WEXITSTATUS(childStatus));
|
||||
}
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "hsakmt.h"
|
||||
|
||||
#ifndef __KFD_OPEN_CLOSE_KFD_TEST__H__
|
||||
#define __KFD_OPEN_CLOSE_KFD_TEST__H__
|
||||
|
||||
// @class KFDOpenCloseKFDTest
|
||||
class KFDOpenCloseKFDTest : public testing::Test {
|
||||
public:
|
||||
KFDOpenCloseKFDTest(void) {}
|
||||
~KFDOpenCloseKFDTest(void) {}
|
||||
|
||||
protected:
|
||||
// @brief SetUp function run before every test that uses KFDOpenCloseKFDTest class fixture, sets all common settings for the tests.
|
||||
virtual void SetUp();
|
||||
// @brief TearDown function run after every test that uses KFDOpenCloseKFDTest class fixture.
|
||||
virtual void TearDown();
|
||||
};
|
||||
|
||||
#endif // __KFD_OPEN_CLOSE_KFD_TEST__H__
|
||||
@@ -0,0 +1,122 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDPMTest.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "hsakmt.h"
|
||||
|
||||
bool KFDPMTest::m_SetupSuccess = false;
|
||||
|
||||
void KFDPMTest::SetUpTestCase() {
|
||||
ROUTINE_START
|
||||
|
||||
m_SetupSuccess = false;
|
||||
AcquirePrivilege(OS_SUSPEND);
|
||||
|
||||
// if AcquirePrivilege fails, it will throw and we will not reach here.
|
||||
m_SetupSuccess = true;
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDPMTest::TearDownTestCase() {
|
||||
}
|
||||
|
||||
|
||||
void KFDPMTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDPMTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPMTest, SuspendWithActiveProcess) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
ASSERT_EQ(true, SuspendAndWakeUp());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPMTest, SuspendWithIdleQueue) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
PM4Queue queue;
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
|
||||
ASSERT_EQ(true, SuspendAndWakeUp());
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPMTest, SuspendWithIdleQueueAfterWork) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
PM4Queue queue;
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
HsaMemoryBuffer destBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4WriteDataPacket(destBuffer.As<unsigned int*>(), 0x1, 0x2));
|
||||
queue.Wait4PacketConsumption();
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[0]), 0x1);
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[1]), 0x2);
|
||||
|
||||
destBuffer.Fill(0);
|
||||
|
||||
ASSERT_EQ(true, SuspendAndWakeUp());
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4WriteDataPacket(&(destBuffer.As<unsigned int*>()[2]), 0x3, 0x4));
|
||||
queue.Wait4PacketConsumption();
|
||||
|
||||
ASSERT_EQ(destBuffer.As<unsigned int*>()[0], 0);
|
||||
ASSERT_EQ(destBuffer.As<unsigned int*>()[1], 0);
|
||||
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[2]), 0x3);
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[3]), 0x4);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// TODO suspend while workload is being executed by a queue
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFDPMTEST_HPP__
|
||||
#define __KFDPMTEST_HPP__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDPMTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDPMTest() {}
|
||||
~KFDPMTest() {}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
static bool m_SetupSuccess;
|
||||
};
|
||||
|
||||
#endif // __KFDPMTEST_HPP__
|
||||
@@ -0,0 +1,99 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDPNPTest.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "hsakmt.h"
|
||||
|
||||
bool KFDPNPTest::m_SetupSuccess = false;
|
||||
|
||||
void KFDPNPTest::SetUpTestCase() {
|
||||
ROUTINE_START
|
||||
|
||||
AcquirePrivilege(OS_DRIVER_OPERATIONS);
|
||||
|
||||
// if AcquirePrivilege fails, it will throw and we will not reach here.
|
||||
m_SetupSuccess = true;
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDPNPTest::TearDownTestCase() {
|
||||
}
|
||||
|
||||
|
||||
void KFDPNPTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
ASSERT_TRUE(m_SetupSuccess);
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDPNPTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPNPTest, DisableWithActiveProcess) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
DisableKfd();
|
||||
EnableKfd();
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPNPTest, DisableAndCreateQueue) {
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
|
||||
PM4Queue queue;
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
HsaMemoryBuffer destBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
|
||||
queue.PlaceAndSubmitPacket(PM4WriteDataPacket(destBuffer.As<unsigned int*>(), 0x1, 0x2));
|
||||
queue.Wait4PacketConsumption();
|
||||
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[0]), 0x1);
|
||||
WaitOnValue(&(destBuffer.As<unsigned int*>()[1]), 0x2);
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
DisableKfd();
|
||||
EnableKfd();
|
||||
|
||||
ASSERT_NE(HSAKMT_STATUS_SUCCESS, queue.Create(defaultGPUNode)) << "Queue creation should fail after a topology change.";
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_PNP_TEST__H__
|
||||
#define __KFD_PNP_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
|
||||
class KFDPNPTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDPNPTest() {}
|
||||
~KFDPNPTest() {}
|
||||
|
||||
protected:
|
||||
static void SetUpTestCase();
|
||||
static void TearDownTestCase();
|
||||
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected:
|
||||
static bool m_SetupSuccess;
|
||||
};
|
||||
|
||||
#endif // __KFD_PNP_TEST__H__
|
||||
@@ -0,0 +1,281 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDPerfCounters.hpp"
|
||||
|
||||
void KFDPerfCountersTest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void KFDPerfCountersTest::TearDown() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
static struct block_name_table {
|
||||
char name[32];
|
||||
HSA_UUID uuid;
|
||||
} block_lookup_table[] = {
|
||||
{"CB ", {0x9ba429c6, 0xaf2d, 0x4b38, 0xb3, 0x49, 0x15, 0x72, 0x71, 0xbe, 0xac, 0x6a}},
|
||||
{"CPF ", {0x2b0ad2b5, 0x1c43, 0x4f46, 0xa7, 0xbc, 0xe1, 0x19, 0x41, 0x1e, 0xa6, 0xc9}},
|
||||
{"CPG ", {0x590ec94d, 0x20f0, 0x448f, 0x8d, 0xff, 0x31, 0x6c, 0x67, 0x9d, 0xe7, 0xff}},
|
||||
{"DB ", {0x3d1a47fc, 0x0013, 0x4ed4, 0x83, 0x06, 0x82, 0x2c, 0xa0, 0xb7, 0xa6, 0xc2}},
|
||||
{"GDS ", {0xf59276ec, 0x2526, 0x4bf8, 0x8e, 0xc0, 0x11, 0x8f, 0x77, 0x70, 0x0d, 0xc9}},
|
||||
{"GRBM ", {0x8f00933c, 0xc33d, 0x4801, 0x97, 0xb7, 0x70, 0x07, 0xf7, 0x85, 0x73, 0xad}},
|
||||
{"GRBMSE ", {0x34ebd8d7, 0x7c8b, 0x4d15, 0x88, 0xfa, 0x0e, 0x4e, 0x4a, 0xf5, 0x9a, 0xc1}},
|
||||
{"IA ", {0x34276944, 0x4264, 0x4fcd, 0x9d, 0x6e, 0xae, 0x26, 0x45, 0x82, 0xec, 0x51}},
|
||||
{"MC ", {0x13900b57, 0x4956, 0x4d98, 0x81, 0xd0, 0x68, 0x52, 0x19, 0x37, 0xf5, 0x9c}},
|
||||
{"PASC ", {0xb0e7fb5d, 0x0efc, 0x4744, 0xb5, 0x16, 0x5d, 0x23, 0xdc, 0x1f, 0xd5, 0x6c}},
|
||||
{"PASU ", {0x9a152b6a, 0x1fad, 0x45f2, 0xa5, 0xbf, 0xf1, 0x63, 0x82, 0x6b, 0xd0, 0xcd}},
|
||||
{"SPI ", {0xeda81044, 0xd62c, 0x47eb, 0xaf, 0x89, 0x4f, 0x6f, 0xbf, 0x3b, 0x38, 0xe0}},
|
||||
{"SRBM ", {0x9f8040e0, 0x6830, 0x4019, 0xac, 0xc8, 0x46, 0x3c, 0x9e, 0x44, 0x5b, 0x89}},
|
||||
{"SQ ", {0xb5c396b6, 0xd310, 0x47e4, 0x86, 0xfc, 0x5c, 0xc3, 0x4, 0x3a, 0xf5, 0x8}},
|
||||
{"SX ", {0xbdb8d737, 0x43cc, 0x4162, 0xbe, 0x52, 0x51, 0xcf, 0xb8, 0x47, 0xbe, 0xaf}},
|
||||
{"TA ", {0xc01ee43d, 0xad92, 0x44b1, 0x8a, 0xb9, 0xbe, 0x5e, 0x69, 0x6c, 0xee, 0xa7}},
|
||||
{"TCA ", {0x333e393f, 0xe147, 0x4f49, 0xa6, 0xd1, 0x60, 0x91, 0x4c, 0x70, 0x86, 0xb0}},
|
||||
{"TCC ", {0x848ce855, 0xd805, 0x4566, 0xa8, 0xab, 0x73, 0xe8, 0x84, 0xcc, 0x6b, 0xff}},
|
||||
{"TCP ", {0xe10a013b, 0x17d4, 0x4bf5, 0xb0, 0x89, 0x42, 0x95, 0x91, 0x05, 0x9b, 0x60}},
|
||||
{"TCS ", {0x4126245c, 0x4d96, 0x4d1a, 0x8a, 0xed, 0xa9, 0x39, 0xd4, 0xcc, 0x8e, 0xc9}},
|
||||
{"TD ", {0x7d7c0fe4, 0xfe41, 0x4fea, 0x92, 0xc9, 0x45, 0x44, 0xd7, 0x70, 0x6d, 0xc6}},
|
||||
{"VGT ", {0x0b6a8cb7, 0x7a01, 0x409f, 0xa2, 0x2c, 0x30, 0x14, 0x85, 0x4f, 0x13, 0x59}},
|
||||
{"WD ", {0x0e176789, 0x46ed, 0x4b02, 0x97, 0x2a, 0x91, 0x6d, 0x2f, 0xac, 0x24, 0x4a}},
|
||||
{"IOMMUV2", {0x80969879, 0xb0f6, 0x4be6, 0x97, 0xf6, 0x6a, 0x63, 0x0, 0xf5, 0x10, 0x1d}},
|
||||
{"DRIVER ", {0xea9b5ae1, 0x6c3f, 0x44b3, 0x89, 0x54, 0xda, 0xf0, 0x75, 0x65, 0xa9, 0xa}}
|
||||
};
|
||||
|
||||
void KFDPerfCountersTest::GetBlockName(HSA_UUID uuid, char *name, uint32_t name_len, char *uuid_str, uint32_t uuid_str_len) {
|
||||
uint32_t i, table_size;
|
||||
|
||||
table_size = sizeof(block_lookup_table) / sizeof(struct block_name_table);
|
||||
|
||||
snprintf(name, name_len, "unknown");
|
||||
for (i = 0; i < table_size; i++) {
|
||||
if (!memcmp(&block_lookup_table[i].uuid, &uuid, sizeof(HSA_UUID))) {
|
||||
if (name)
|
||||
snprintf(name, name_len, "%s", block_lookup_table[i].name);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (uuid_str)
|
||||
snprintf(uuid_str, uuid_str_len,
|
||||
"%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x",
|
||||
uuid.Data1, uuid.Data2, uuid.Data3,
|
||||
uuid.Data4[0], uuid.Data4[1], uuid.Data4[2],
|
||||
uuid.Data4[3], uuid.Data4[4], uuid.Data4[5],
|
||||
uuid.Data4[6], uuid.Data4[7]);
|
||||
}
|
||||
|
||||
TEST_F(KFDPerfCountersTest, GetCounterProperties) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
HsaCounterProperties* pProps = NULL;
|
||||
ASSERT_SUCCESS(hsaKmtPmcGetCounterProperties(defaultGPUNode, &pProps));
|
||||
/* Verifying that there is at least one block */
|
||||
ASSERT_NE(0, pProps->NumBlocks) << "No performance counters blocks";
|
||||
|
||||
LOG() << std::dec << pProps->NumBlocks << " blocks found." << std::endl;
|
||||
|
||||
HsaCounterBlockProperties *block;
|
||||
block = &pProps->Blocks[0];
|
||||
for (HSAuint32 i = 0; i < pProps->NumBlocks; i++) {
|
||||
char uuid_string[37] = "";
|
||||
char name[32] = "";
|
||||
GetBlockName(block->BlockId, name, 32, uuid_string, 37);
|
||||
|
||||
char type[32];
|
||||
switch (block->Counters[0].Type) {
|
||||
case HSA_PROFILE_TYPE_PRIVILEGED_IMMEDIATE:
|
||||
snprintf(type, sizeof(type), "Priv Immediate");
|
||||
break;
|
||||
case HSA_PROFILE_TYPE_PRIVILEGED_STREAMING:
|
||||
snprintf(type, sizeof(type), "Priv Streaming");
|
||||
break;
|
||||
case HSA_PROFILE_TYPE_NONPRIV_IMMEDIATE:
|
||||
snprintf(type, sizeof(type), "Non-priv Immediate");
|
||||
break;
|
||||
case HSA_PROFILE_TYPE_NONPRIV_STREAMING:
|
||||
snprintf(type, sizeof(type), "Non-priv Immediate");
|
||||
break;
|
||||
default:
|
||||
snprintf(type, sizeof(type), "Unknown");
|
||||
break;
|
||||
}
|
||||
|
||||
LOG() << name << " (" << uuid_string << "): " << type << ", " <<
|
||||
block->NumCounters << " counter IDs" << std::endl;
|
||||
block = (HsaCounterBlockProperties *)&block->Counters[block->NumCounters];
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPerfCountersTest, RegisterTrace) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
HsaCounterProperties* pProps;
|
||||
|
||||
HsaPmcTraceRoot root;
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
pProps = NULL;
|
||||
ASSERT_SUCCESS(hsaKmtPmcGetCounterProperties(defaultGPUNode, &pProps));
|
||||
|
||||
/* Verifying that there is at least one block */
|
||||
ASSERT_NE(0, pProps->NumBlocks) << "No performance counters blocks";
|
||||
|
||||
HsaCounterBlockProperties *block = &pProps->Blocks[0];
|
||||
bool priv_block_found = false;
|
||||
for (HSAuint32 i = 0; i < pProps->NumBlocks; i++) {
|
||||
if (block->Counters[0].Type <= HSA_PROFILE_TYPE_PRIVILEGED_STREAMING) {
|
||||
priv_block_found = true;
|
||||
break;
|
||||
}
|
||||
block = (HsaCounterBlockProperties *)&block->Counters[block->NumCounters];
|
||||
}
|
||||
|
||||
if (!priv_block_found) {
|
||||
LOG() << "No privileged block is found. Skipping RegisterTrace test."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Registering trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcRegisterTrace(defaultGPUNode,
|
||||
block->NumConcurrent,
|
||||
block->Counters,
|
||||
&root));
|
||||
ASSERT_SUCCESS(hsaKmtPmcUnregisterTrace(defaultGPUNode, root.TraceId));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPerfCountersTest, StartStopQueryTrace) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
HsaPmcTraceRoot root;
|
||||
HsaCounterProperties* pProps;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
pProps = NULL;
|
||||
ASSERT_SUCCESS(hsaKmtPmcGetCounterProperties(defaultGPUNode, &pProps));
|
||||
|
||||
/* Verifying that there is at least one block */
|
||||
ASSERT_NE(0, pProps->NumBlocks) << "No performance counters blocks";
|
||||
|
||||
HsaCounterBlockProperties *block = &pProps->Blocks[0];
|
||||
bool priv_block_found = false;
|
||||
for (HSAuint32 i = 0; i < pProps->NumBlocks; i++) {
|
||||
if (block->Counters[0].Type <= HSA_PROFILE_TYPE_PRIVILEGED_STREAMING) {
|
||||
priv_block_found = true;
|
||||
break;
|
||||
}
|
||||
block = (HsaCounterBlockProperties *)&block->Counters[block->NumCounters];
|
||||
}
|
||||
|
||||
if (!priv_block_found) {
|
||||
LOG() << "No privileged block is found. Skipping StartStopQuery test."
|
||||
<< std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
if (getuid()) { /* Non-root */
|
||||
LOG() << "Privileged counters requires the user as root." << std::endl
|
||||
<< "Skipping StartStopQuery test." << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
/* Registering trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcRegisterTrace(defaultGPUNode,
|
||||
block->NumConcurrent,
|
||||
block->Counters,
|
||||
&root));
|
||||
|
||||
/* Acquiring access for the trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcAcquireTraceAccess(defaultGPUNode, root.TraceId));
|
||||
|
||||
/* Allocating memory buffer for the trace */
|
||||
HsaMemoryBuffer membuf(PAGE_SIZE, defaultGPUNode);
|
||||
|
||||
/* Starting the trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcStartTrace(root.TraceId,
|
||||
membuf.As<void*>(),
|
||||
membuf.Size()));
|
||||
|
||||
/* Delay between START and STOP tracing */
|
||||
Delay(START_STOP_DELAY);
|
||||
|
||||
/* Stopping th trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcStopTrace(root.TraceId));
|
||||
|
||||
/* Querying the trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcQueryTrace(root.TraceId));
|
||||
uint64_t *buf = membuf.As<uint64_t*>();
|
||||
for (uint32_t i = 0; i < block->NumConcurrent; i++, buf++)
|
||||
LOG() << "Counter " << std::dec << i << ": " << *buf << std::endl;
|
||||
|
||||
/* Releasing the trace */
|
||||
ASSERT_SUCCESS(hsaKmtPmcReleaseTraceAccess(0, root.TraceId));
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtPmcUnregisterTrace(defaultGPUNode, root.TraceId));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
TEST_F(KFDPerfCountersTest, ClockCountersBasicTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
HsaClockCounters counters1;
|
||||
HsaClockCounters counters2;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtGetClockCounters(defaultGPUNode, &counters1));
|
||||
|
||||
Delay(100);
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtGetClockCounters(defaultGPUNode, &counters2));
|
||||
|
||||
EXPECT_NE(0, counters1.GPUClockCounter);
|
||||
EXPECT_NE(0, counters2.GPUClockCounter);
|
||||
EXPECT_NE(0, counters1.SystemClockCounter);
|
||||
EXPECT_NE(0, counters2.SystemClockCounter);
|
||||
|
||||
EXPECT_GT(counters2.GPUClockCounter, counters1.GPUClockCounter);
|
||||
EXPECT_GT(counters2.SystemClockCounter, counters1.SystemClockCounter);
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFDPERFCOUNTERS_HPP__
|
||||
#define __KFDPERFCOUNTERS_HPP__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class KFDPerfCountersTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDPerfCountersTest() {}
|
||||
~KFDPerfCountersTest() {}
|
||||
|
||||
static const unsigned int START_STOP_DELAY = 10000; // 10 sec tracing
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
void GetBlockName(HSA_UUID uuid, char *name, uint32_t name_len,
|
||||
char *uuid_str, uint32_t uuid_str_len);
|
||||
};
|
||||
|
||||
#endif // __KFDPERFCOUNTERS_HPP__
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_QCM_TEST__H__
|
||||
#define __KFD_QCM_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "PM4Queue.hpp"
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
|
||||
class KFDQMTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDQMTest():m_pIsaGen(NULL) {}
|
||||
|
||||
~KFDQMTest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
void SyncDispatch(const HsaMemoryBuffer& isaBuffer, void* pSrcBuf, void* pDstBuf, int node = -1);
|
||||
// void SyncDispatchWithSleep(const HsaMemoryBuffer& isaBuffer, void* pSrcBuf, void* pDstBuf);
|
||||
long long TimeConsumedwithCUMask(int node, uint32_t *mask, uint32_t mask_count);
|
||||
long long GetAverageTimeConsumedwithCUMask(int node, uint32_t *mask, uint32_t mask_count, int iterations);
|
||||
protected: // members
|
||||
/* Acceptable performance for CU Masking should be within 5% of linearly-predicted performance */
|
||||
const double CuVariance = 0.15;
|
||||
const double CuNegVariance = 1.0 - CuVariance;
|
||||
const double CuPosVariance = 1.0 + CuVariance;
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __KFD_QCM_TEST__H__
|
||||
@@ -0,0 +1,65 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_TEST_FLAGS__H__
|
||||
#define __KFD_TEST_FLAGS__H__
|
||||
|
||||
extern unsigned int g_TestRunProfile;
|
||||
extern unsigned int g_TestENVCaps;
|
||||
extern unsigned int g_TestTimeOut;
|
||||
extern int g_TestNodeId;
|
||||
extern int g_TestDstNodeId;
|
||||
extern bool g_IsChildProcess;
|
||||
extern unsigned int g_TestGPUFamilyId;
|
||||
|
||||
// each test should call TEST_START with the test custome profile and HW scheduling
|
||||
|
||||
enum TESTPROFILE{
|
||||
TESTPROFILE_DEV = 0x1,
|
||||
TESTPROFILE_PROMO = 0x2,
|
||||
// 0x4 - 0x8000 - unsed flags
|
||||
// can add any flag that will mark only part of the tests to run
|
||||
TESTPROFILE_RUNALL = 0xFFFF
|
||||
};
|
||||
|
||||
enum ENVCAPS{
|
||||
ENVCAPS_NOADDEDCAPS = 0x0,
|
||||
ENVCAPS_HWSCHEDULING = 0x1,
|
||||
ENVCAPS_16BITPASID = 0x2,
|
||||
ENVCAPS_32BITLINUX = 0x4,
|
||||
ENVCAPS_64BITLINUX = 0x8
|
||||
// 0x8 - 0x8000 - unsed flags
|
||||
// can add any flag that will mark specific hw limitation \ capability
|
||||
};
|
||||
|
||||
enum KfdFamilyId {
|
||||
FAMILY_UNKNOWN = 0,
|
||||
FAMILY_CI, // Sea Islands: Hawaii (P), Maui (P), Bonaire (M)
|
||||
FAMILY_KV, // Fusion Kaveri: Spectre, Spooky; Fusion Kabini: Kalindi
|
||||
FAMILY_VI, // Volcanic Islands: Iceland (V), Tonga (M)
|
||||
FAMILY_CZ, // Carrizo, Nolan, Amur
|
||||
FAMILY_AI, // Arctic Islands
|
||||
FAMILY_RV, // Raven
|
||||
};
|
||||
|
||||
#endif // __KFD_TEST_FLAGS__H__
|
||||
@@ -0,0 +1,92 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "gtest/gtest.h"
|
||||
#include "KFDTestFlags.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
#include "GoogleTestExtension.hpp"
|
||||
#include "OSWrapper.hpp"
|
||||
|
||||
#define KFD_TEST_DEFAULT_TIMEOUT 2000
|
||||
|
||||
std::ostream& operator << (std::ostream& out, TESTPROFILE profile) {
|
||||
switch (profile) {
|
||||
case TESTPROFILE_DEV:
|
||||
out << "Developer Test";
|
||||
break;
|
||||
case TESTPROFILE_PROMO:
|
||||
out << "Promotion Test";
|
||||
break;
|
||||
case TESTPROFILE_RUNALL:
|
||||
out << "Full Test";
|
||||
break;
|
||||
default:
|
||||
out << "INVALID";
|
||||
};
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
unsigned int g_TestRunProfile;
|
||||
unsigned int g_TestENVCaps;
|
||||
unsigned int g_TestTimeOut;
|
||||
int g_TestNodeId;
|
||||
int g_TestDstNodeId;
|
||||
bool g_IsChildProcess;
|
||||
unsigned int g_TestGPUFamilyId;
|
||||
|
||||
GTEST_API_ int main(int argc, char **argv) {
|
||||
// default values for run parameters
|
||||
g_TestRunProfile = TESTPROFILE_RUNALL;
|
||||
g_TestENVCaps = ENVCAPS_NOADDEDCAPS | ENVCAPS_64BITLINUX;
|
||||
g_TestTimeOut = KFD_TEST_DEFAULT_TIMEOUT;
|
||||
|
||||
// every fatal fail ( = assert that failed ) will throw an exption
|
||||
testing::GTEST_FLAG(throw_on_failure) = true;
|
||||
testing::InitGoogleTest(&argc, argv);
|
||||
|
||||
CommandLineArguments args;
|
||||
memset(&args, 0, sizeof(args));
|
||||
|
||||
bool success = GetCommandLineArguments(argc, argv, args);
|
||||
|
||||
if (success) {
|
||||
if ((GetHwCapabilityHWS() || args.HwsEnabled == HWCAP__FORCE_ENABLED) && (args.HwsEnabled != HWCAP__FORCE_DISABLED))
|
||||
g_TestENVCaps |= ENVCAPS_HWSCHEDULING;
|
||||
|
||||
g_TestRunProfile = args.TestProfile;
|
||||
g_IsChildProcess = args.ChildProcess;
|
||||
|
||||
if ( args.TimeOut > 0 )
|
||||
g_TestTimeOut = args.TimeOut;
|
||||
|
||||
// If --node is not specified, then args.NodeId == -1
|
||||
g_TestNodeId = args.NodeId;
|
||||
g_TestDstNodeId = args.DstNodeId;
|
||||
|
||||
LOG() << "Profile: " << (TESTPROFILE)g_TestRunProfile << std::endl;
|
||||
LOG() << "HW capabilities: 0x" << std::hex << g_TestENVCaps << std::endl;
|
||||
|
||||
return RUN_ALL_TESTS();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include "BaseQueue.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
|
||||
bool WaitOnValue(const volatile unsigned int *buf, unsigned int value) {
|
||||
unsigned int timeOut = g_TestTimeOut;
|
||||
|
||||
while (timeOut > 0 && *buf != value) {
|
||||
Delay(1);
|
||||
|
||||
if (timeOut != HSA_EVENTTIMEOUT_INFINITE)
|
||||
timeOut--;
|
||||
}
|
||||
|
||||
return *buf == value;
|
||||
}
|
||||
|
||||
void SplitU64(const unsigned long long value, unsigned int& rLoPart, unsigned int& rHiPart) {
|
||||
rLoPart = static_cast<unsigned int>(value);
|
||||
rHiPart = static_cast<unsigned int>(value >> 32);
|
||||
}
|
||||
|
||||
bool GetHwCapabilityHWS() {
|
||||
unsigned int value = 0;
|
||||
bool valExists = ReadDriverConfigValue(CONFIG_HWS, value);
|
||||
|
||||
/* HWS is enabled by default, so... */
|
||||
return ( (!valExists) || ( value > 0));
|
||||
}
|
||||
|
||||
HSAKMT_STATUS CreateQueueTypeEvent(
|
||||
bool ManualReset, // IN
|
||||
bool IsSignaled, // IN
|
||||
unsigned int NodeId, // IN
|
||||
HsaEvent** Event // OUT
|
||||
) {
|
||||
HsaEventDescriptor Descriptor;
|
||||
|
||||
// TODO Create per-OS header with this sort of definitions
|
||||
#ifdef _WIN32
|
||||
Descriptor.EventType = HSA_EVENTTYPE_QUEUE_EVENT;
|
||||
#else
|
||||
Descriptor.EventType = HSA_EVENTTYPE_SIGNAL;
|
||||
#endif
|
||||
Descriptor.SyncVar.SyncVar.UserData = (void*)0xABCDABCD;
|
||||
Descriptor.NodeId = NodeId;
|
||||
|
||||
return hsaKmtCreateEvent(&Descriptor, ManualReset, IsSignaled, Event);
|
||||
}
|
||||
|
||||
static bool is_dgpu_dev = false;
|
||||
|
||||
bool is_dgpu() {
|
||||
return is_dgpu_dev;
|
||||
}
|
||||
|
||||
unsigned int FamilyIdFromNode(const HsaNodeProperties *props) {
|
||||
unsigned int familyId = FAMILY_UNKNOWN;
|
||||
|
||||
switch (props->EngineId.ui32.Major) {
|
||||
case 7:
|
||||
if (props->EngineId.ui32.Minor == 0) {
|
||||
if (props->EngineId.ui32.Stepping == 0)
|
||||
familyId = FAMILY_KV;
|
||||
else
|
||||
familyId = FAMILY_CI;
|
||||
}
|
||||
break;
|
||||
case 8:
|
||||
familyId = FAMILY_VI;
|
||||
if (props->EngineId.ui32.Stepping == 1)
|
||||
familyId = FAMILY_CZ;
|
||||
break;
|
||||
case 9:
|
||||
familyId = FAMILY_AI;
|
||||
if (props->EngineId.ui32.Stepping == 2)
|
||||
familyId = FAMILY_RV;
|
||||
break;
|
||||
}
|
||||
|
||||
if (familyId == FAMILY_KV || familyId == FAMILY_CZ || familyId == FAMILY_RV)
|
||||
is_dgpu_dev = false;
|
||||
else
|
||||
is_dgpu_dev = true;
|
||||
|
||||
return familyId;
|
||||
}
|
||||
|
||||
bool isTonga(const HsaNodeProperties *props) {
|
||||
/* Tonga has some workarounds in the thunk that cause certain failures */
|
||||
if (props->EngineId.ui32.Major == 8 && props->EngineId.ui32.Stepping == 2) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const HsaMemoryBuffer HsaMemoryBuffer::Null;
|
||||
|
||||
HsaMemoryBuffer::HsaMemoryBuffer(HSAuint64 size, unsigned int node, bool zero, bool isLocal, bool isExec, bool isScratch, bool isReadOnly)
|
||||
:m_Size(size),
|
||||
m_pUser(NULL),
|
||||
m_pBuf(NULL),
|
||||
m_Local(isLocal),
|
||||
m_Node(node) {
|
||||
m_Flags.Value = 0;
|
||||
|
||||
if (isScratch) {
|
||||
m_Flags.ui32.Scratch = 1;
|
||||
m_Flags.ui32.HostAccess = 1;
|
||||
} else {
|
||||
m_Flags.ui32.PageSize = HSA_PAGE_SIZE_4KB;
|
||||
|
||||
if (isLocal) {
|
||||
m_Flags.ui32.HostAccess = 0;
|
||||
m_Flags.ui32.NonPaged = 1;
|
||||
} else {
|
||||
m_Flags.ui32.HostAccess = 1;
|
||||
m_Flags.ui32.NonPaged = 0;
|
||||
}
|
||||
|
||||
if (isExec)
|
||||
m_Flags.ui32.ExecuteAccess = 1;
|
||||
}
|
||||
if (isReadOnly)
|
||||
m_Flags.ui32.ReadOnly = 1;
|
||||
|
||||
EXPECT_SUCCESS(hsaKmtAllocMemory( m_Node, m_Size, m_Flags, &m_pBuf));
|
||||
if (is_dgpu()) {
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPU(m_pBuf, m_Size, NULL));
|
||||
m_MappedNodes = 1 << m_Node;
|
||||
}
|
||||
|
||||
if (zero && !isLocal)
|
||||
Fill(0);
|
||||
}
|
||||
|
||||
HsaMemoryBuffer::HsaMemoryBuffer(void *addr, HSAuint64 size):
|
||||
m_Size(size),
|
||||
m_pUser(addr),
|
||||
m_pBuf(NULL),
|
||||
m_Local(false),
|
||||
m_Node(0) {
|
||||
HSAuint64 gpuva = 0;
|
||||
EXPECT_SUCCESS(hsaKmtRegisterMemory(m_pUser, m_Size));
|
||||
EXPECT_SUCCESS(hsaKmtMapMemoryToGPU(m_pUser, m_Size, &gpuva));
|
||||
m_pBuf = gpuva ? (void *)gpuva : m_pUser;
|
||||
}
|
||||
|
||||
HsaMemoryBuffer::HsaMemoryBuffer()
|
||||
:m_Size(0),
|
||||
m_pBuf(NULL) {
|
||||
}
|
||||
|
||||
void HsaMemoryBuffer::Fill(unsigned char value, HSAuint64 offset, HSAuint64 size) {
|
||||
HSAuint32 uiValue;
|
||||
|
||||
EXPECT_EQ(m_Local, 0) << "Local Memory. Call Fill(HSAuint32 value, BaseQueue& baseQueue)";
|
||||
|
||||
size = size ? size : m_Size;
|
||||
ASSERT_TRUE(size + offset <= m_Size) << "Buffer Overflow" << std::endl;
|
||||
|
||||
if (m_pUser != NULL)
|
||||
memset((char *)m_pUser + offset, value, size);
|
||||
else if (m_pBuf != NULL)
|
||||
memset((char *)m_pBuf + offset, value, size);
|
||||
else
|
||||
ASSERT_TRUE(0) << "Invalid HsaMemoryBuffer";
|
||||
}
|
||||
|
||||
/* Fill CPU accessible buffer with the value. */
|
||||
void HsaMemoryBuffer::Fill(HSAuint32 value, HSAuint64 offset, HSAuint64 size) {
|
||||
HSAuint64 i;
|
||||
HSAuint32 *ptr = NULL;
|
||||
|
||||
EXPECT_EQ(m_Local, 0) << "Local Memory. Call Fill(HSAuint32 value, BaseQueue& baseQueue)";
|
||||
size = size ? size : m_Size;
|
||||
EXPECT_EQ((size & (sizeof(HSAuint32) - 1)), 0) << "Not word aligned. Call Fill(unsigned char)";
|
||||
ASSERT_TRUE(size + offset <= m_Size) << "Buffer Overflow" << std::endl;
|
||||
|
||||
if (m_pUser != NULL)
|
||||
ptr = (HSAuint32 *)((char *)m_pUser + offset);
|
||||
else if (m_pBuf != NULL)
|
||||
ptr = (HSAuint32 *)((char *)m_pBuf + offset);
|
||||
|
||||
ASSERT_NOTNULL(ptr);
|
||||
|
||||
for (i = 0; i < size / sizeof(HSAuint32); i++)
|
||||
ptr[i] = value;
|
||||
}
|
||||
|
||||
/* Fill GPU only accessible Local memory with @value using SDMA Constant Fill Command */
|
||||
void HsaMemoryBuffer::Fill(HSAuint32 value, BaseQueue& baseQueue, HSAuint64 offset, HSAuint64 size) {
|
||||
HsaEvent* event = NULL;
|
||||
|
||||
EXPECT_NE(m_Local, 0) << "Not Local Memory. Call Fill(HSAuint32 value)";
|
||||
|
||||
ASSERT_SUCCESS(CreateQueueTypeEvent(false, false, m_Node, &event));
|
||||
ASSERT_EQ(baseQueue.GetQueueType(), HSA_QUEUE_SDMA) << "Only SDMA queues supported";
|
||||
|
||||
size = size ? size : m_Size;
|
||||
ASSERT_TRUE(size + offset <= m_Size) << "Buffer Overflow" << std::endl;
|
||||
|
||||
baseQueue.PlacePacket(SDMAFillDataPacket((void *)(this->As<char*>() + offset), value, size));
|
||||
baseQueue.PlacePacket(SDMAFencePacket((void*)event->EventData.HWData2, event->EventId));
|
||||
baseQueue.PlaceAndSubmitPacket(SDMATrapPacket(event->EventId));
|
||||
ASSERT_SUCCESS(hsaKmtWaitOnEvent(event, g_TestTimeOut));
|
||||
|
||||
hsaKmtDestroyEvent(event);
|
||||
}
|
||||
|
||||
/* Check if HsaMemoryBuffer[location] has the pattern specified.
|
||||
* Return TRUE if correct pattern else return FALSE
|
||||
* HsaMemoryBuffer has to be CPU accessible
|
||||
*/
|
||||
bool HsaMemoryBuffer::IsPattern(HSAuint64 location, HSAuint32 pattern) {
|
||||
HSAuint32 *ptr = NULL;
|
||||
|
||||
EXPECT_EQ(m_Local, 0) << "Local Memory. Call IsPattern(..baseQueue& baseQueue)";
|
||||
|
||||
if (location >= m_Size) /* Out of bounds */
|
||||
return false;
|
||||
|
||||
if (m_pUser != NULL)
|
||||
ptr = (HSAuint32 *)m_pUser;
|
||||
else if (m_pBuf != NULL)
|
||||
ptr = (HSAuint32 *)m_pBuf;
|
||||
else
|
||||
return false;
|
||||
|
||||
if (ptr)
|
||||
return (ptr[location/sizeof(HSAuint32)] == pattern);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Check if HsaMemoryBuffer[location] has the pattern specified.
|
||||
* Return TRUE if correct pattern else return FALSE
|
||||
* HsaMemoryBuffer is supposed to be only GPU accessible
|
||||
* Use @baseQueue to copy the HsaMemoryBuffer[location] to stack and check the value
|
||||
*/
|
||||
|
||||
bool HsaMemoryBuffer::IsPattern(HSAuint64 location, HSAuint32 pattern, BaseQueue& baseQueue, volatile HSAuint32 *tmp) {
|
||||
HsaEvent* event = NULL;
|
||||
int ret;
|
||||
|
||||
EXPECT_NE(m_Local, 0) << "Not Local Memory. Call IsPattern(HSAuint64 location, HSAuint32 pattern)";
|
||||
EXPECT_EQ(baseQueue.GetQueueType(), HSA_QUEUE_SDMA) << "Only SDMA queues supported";
|
||||
|
||||
if (location >= m_Size) /* Out of bounds */
|
||||
return false;
|
||||
|
||||
ret = CreateQueueTypeEvent(false, false, m_Node, &event);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
*tmp = ~pattern;
|
||||
baseQueue.PlacePacket(SDMACopyDataPacket((void *)tmp,
|
||||
(void *)(this->As<HSAuint64>() + location),
|
||||
sizeof(HSAuint32)));
|
||||
baseQueue.PlacePacket(SDMAFencePacket((void*)event->EventData.HWData2,
|
||||
event->EventId));
|
||||
baseQueue.PlaceAndSubmitPacket(SDMATrapPacket(event->EventId));
|
||||
|
||||
ret = hsaKmtWaitOnEvent(event, g_TestTimeOut);
|
||||
hsaKmtDestroyEvent(event);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
return WaitOnValue(tmp, pattern);
|
||||
}
|
||||
|
||||
unsigned int HsaMemoryBuffer::Size() {
|
||||
return m_Size;
|
||||
}
|
||||
|
||||
HsaMemFlags HsaMemoryBuffer::Flags() {
|
||||
return m_Flags;
|
||||
}
|
||||
|
||||
unsigned int HsaMemoryBuffer::Node() const {
|
||||
return m_Node;
|
||||
}
|
||||
|
||||
int HsaMemoryBuffer::MapMemToNodes(unsigned int *nodes, unsigned int nodes_num) {
|
||||
int ret, bit;
|
||||
|
||||
ret = hsaKmtRegisterMemoryToNodes(m_pBuf, m_Size, nodes_num, nodes);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
ret = hsaKmtMapMemoryToGPU(m_pBuf, m_Size, NULL);
|
||||
if (ret != 0) {
|
||||
hsaKmtDeregisterMemory(m_pBuf);
|
||||
return ret;
|
||||
}
|
||||
|
||||
for (unsigned int i = 0; i < nodes_num; i++) {
|
||||
bit = 1 << nodes[i];
|
||||
m_MappedNodes |= bit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int HsaMemoryBuffer::UnmapMemToNodes(unsigned int *nodes, unsigned int nodes_num) {
|
||||
int ret, bit;
|
||||
|
||||
ret = hsaKmtUnmapMemoryToGPU(m_pBuf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
hsaKmtDeregisterMemory(m_pBuf);
|
||||
for (unsigned int i = 0; i < nodes_num; i++) {
|
||||
bit = 1 << nodes[i];
|
||||
m_MappedNodes &= ~bit;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void HsaMemoryBuffer::UnmapAllNodes() {
|
||||
unsigned int *Arr, size, i, j;
|
||||
int bit;
|
||||
|
||||
size = 0;
|
||||
for (i = 0; i < 8; i++) {
|
||||
bit = 1 << i;
|
||||
if (m_MappedNodes & bit)
|
||||
size++;
|
||||
}
|
||||
|
||||
Arr = (unsigned int *)malloc(sizeof(unsigned int) * size);
|
||||
if (!Arr)
|
||||
return;
|
||||
|
||||
for (i = 0, j =0; i < 8; i++) {
|
||||
bit = 1 << i;
|
||||
if (m_MappedNodes & bit)
|
||||
Arr[j++] = i;
|
||||
}
|
||||
|
||||
/*
|
||||
* TODO: when thunk will be updated use hsaKmtRegisterToNodes. and then nodes will be used
|
||||
*/
|
||||
hsaKmtUnmapMemoryToGPU(m_pBuf);
|
||||
hsaKmtDeregisterMemory(m_pBuf);
|
||||
|
||||
m_MappedNodes = 0;
|
||||
|
||||
free(Arr);
|
||||
}
|
||||
|
||||
HsaMemoryBuffer::~HsaMemoryBuffer() {
|
||||
if (m_pUser != NULL) {
|
||||
hsaKmtUnmapMemoryToGPU(m_pUser);
|
||||
hsaKmtDeregisterMemory(m_pUser);
|
||||
} else if (m_pBuf != NULL) {
|
||||
if (is_dgpu()) {
|
||||
if (m_MappedNodes) {
|
||||
hsaKmtUnmapMemoryToGPU(m_pBuf);
|
||||
hsaKmtDeregisterMemory(m_pBuf);
|
||||
}
|
||||
}
|
||||
hsaKmtFreeMemory(m_pBuf, m_Size);
|
||||
}
|
||||
m_pBuf = NULL;
|
||||
}
|
||||
|
||||
HsaInteropMemoryBuffer::HsaInteropMemoryBuffer(unsigned long long device_handle, unsigned long long buffer_handle, unsigned long long size, unsigned int node)
|
||||
:m_Size(0),
|
||||
m_pBuf(NULL),
|
||||
m_graphic_handle(0),
|
||||
m_Node(node) {
|
||||
HSAuint64 flat_address;
|
||||
EXPECT_SUCCESS(hsaKmtMapGraphicHandle(m_Node, device_handle, buffer_handle, 0, size, &flat_address));
|
||||
m_pBuf = (void*)flat_address;
|
||||
}
|
||||
|
||||
HsaInteropMemoryBuffer::~HsaInteropMemoryBuffer() {
|
||||
hsaKmtUnmapGraphicHandle(m_Node, (HSAuint64)m_pBuf, m_Size);
|
||||
}
|
||||
|
||||
|
||||
HsaNodeInfo::HsaNodeInfo() {
|
||||
}
|
||||
|
||||
// Init - Get and store information about all the HSA nodes from the Thunk Library.
|
||||
// @NumOfNodes - Number to system nodes returned by hsaKmtAcquireSystemProperties
|
||||
// @Return - false: if no node information is available
|
||||
//
|
||||
bool HsaNodeInfo::Init(int NumOfNodes) {
|
||||
HsaNodeProperties *nodeProperties;
|
||||
_HSAKMT_STATUS status;
|
||||
bool ret = false;
|
||||
|
||||
for (int i = 0; i < NumOfNodes; i++) {
|
||||
nodeProperties = new HsaNodeProperties();
|
||||
|
||||
status = hsaKmtGetNodeProperties(i, nodeProperties);
|
||||
/* this is not a fatal test (not using assert), since even when it fails for one node
|
||||
* we want to get information regarding others. */
|
||||
EXPECT_SUCCESS(status) << "Node index: " << i << "hsaKmtGetNodeProperties returned status " << status;
|
||||
|
||||
if (status == HSAKMT_STATUS_SUCCESS) {
|
||||
m_HsaNodeProps.push_back(nodeProperties);
|
||||
ret = true; // Return true if atleast one information is available
|
||||
|
||||
if (nodeProperties->NumFComputeCores)
|
||||
m_NodesWithGPU.push_back(i);
|
||||
else
|
||||
m_NodesWithoutGPU.push_back(i);
|
||||
} else {
|
||||
delete nodeProperties;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
HsaNodeInfo::~HsaNodeInfo() {
|
||||
const HsaNodeProperties *nodeProperties;
|
||||
|
||||
for (unsigned int i = 0; i < m_HsaNodeProps.size(); i++)
|
||||
delete m_HsaNodeProps.at(i);
|
||||
|
||||
m_HsaNodeProps.clear();
|
||||
}
|
||||
|
||||
const std::vector<int>& HsaNodeInfo::GetNodesWithGPU() const {
|
||||
return m_NodesWithGPU;
|
||||
}
|
||||
|
||||
const HsaNodeProperties* HsaNodeInfo::GetNodeProperties(int NodeNum) const {
|
||||
return m_HsaNodeProps.at(NodeNum);
|
||||
}
|
||||
|
||||
const HsaNodeProperties* HsaNodeInfo::HsaDefaultGPUNodeProperties() const {
|
||||
int NodeNum = HsaDefaultGPUNode();
|
||||
if (NodeNum < 0)
|
||||
return NULL;
|
||||
return GetNodeProperties(NodeNum);
|
||||
}
|
||||
|
||||
const int HsaNodeInfo::HsaDefaultGPUNode() const {
|
||||
if (m_NodesWithGPU.size() == 0)
|
||||
return -1;
|
||||
|
||||
if (g_TestNodeId >= 0) {
|
||||
// Check if this is a valid Id, if so use this else use first
|
||||
// available
|
||||
for (unsigned int i = 0; i < m_NodesWithGPU.size(); i++) {
|
||||
if (g_TestNodeId == m_NodesWithGPU.at(i))
|
||||
return g_TestNodeId;
|
||||
}
|
||||
}
|
||||
|
||||
return m_NodesWithGPU.at(0);
|
||||
}
|
||||
|
||||
void HsaNodeInfo::PrintNodeInfo() const {
|
||||
const HsaNodeProperties *nodeProperties;
|
||||
|
||||
for (unsigned int i = 0; i < m_HsaNodeProps.size(); i++) {
|
||||
nodeProperties = m_HsaNodeProps.at(i);
|
||||
|
||||
LOG() << "***********************************" << std::endl;
|
||||
LOG() << "Node " << i << std::endl;
|
||||
LOG() << "NumCPUCores=\t" << nodeProperties->NumCPUCores << std::endl;
|
||||
LOG() << "NumFComputeCores=\t" << nodeProperties->NumFComputeCores << std::endl;
|
||||
LOG() << "NumMemoryBanks=\t" << nodeProperties->NumMemoryBanks << std::endl;
|
||||
LOG() << "VendorId=\t" << nodeProperties->VendorId << std::endl;
|
||||
LOG() << "DeviceId=\t" << nodeProperties->DeviceId << std::endl;
|
||||
LOG() << "***********************************" << std::endl;
|
||||
}
|
||||
|
||||
LOG() << "Default GPU NODE " << HsaDefaultGPUNode() << std::endl;
|
||||
}
|
||||
|
||||
const bool HsaNodeInfo::IsGPUNodeLargeBar(int node) const {
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
|
||||
pNodeProperties = GetNodeProperties(node);
|
||||
if (pNodeProperties) {
|
||||
HsaMemoryProperties *memoryProperties =
|
||||
new HsaMemoryProperties[pNodeProperties->NumMemoryBanks];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeMemoryProperties(node,
|
||||
pNodeProperties->NumMemoryBanks, memoryProperties));
|
||||
for (unsigned bank = 0; bank < pNodeProperties->NumMemoryBanks; bank++)
|
||||
if (memoryProperties[bank].HeapType ==
|
||||
HSA_HEAPTYPE_FRAME_BUFFER_PUBLIC) {
|
||||
delete [] memoryProperties;
|
||||
return true;
|
||||
}
|
||||
delete [] memoryProperties;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
const int HsaNodeInfo::FindLargeBarGPUNode() const {
|
||||
const std::vector<int> gpuNodes = GetNodesWithGPU();
|
||||
|
||||
for (unsigned i = 0; i < gpuNodes.size(); i++)
|
||||
if (IsGPUNodeLargeBar(gpuNodes.at(i)))
|
||||
return gpuNodes.at(i);
|
||||
|
||||
return -1;
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD__TEST__UTIL__H__
|
||||
#define __KFD__TEST__UTIL__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <vector>
|
||||
#include "OSWrapper.hpp"
|
||||
#include "GoogleTestExtension.hpp"
|
||||
#include "hsakmt.h"
|
||||
|
||||
class BaseQueue;
|
||||
#define ARRAY_SIZE(_x) (sizeof(_x)/sizeof(_x[0]))
|
||||
|
||||
// @brief: waits until the value is written to the buffer or until time out if received through args
|
||||
bool WaitOnValue(const volatile unsigned int *buf, unsigned int value);
|
||||
|
||||
void SplitU64(const unsigned long long value, unsigned int& rLoPart, unsigned int& rHiPart);
|
||||
|
||||
bool GetHwCapabilityHWS();
|
||||
|
||||
HSAKMT_STATUS CreateQueueTypeEvent(bool ManualReset, bool IsSignaled, unsigned int NodeId, HsaEvent** Event);
|
||||
|
||||
bool is_dgpu();
|
||||
bool isTonga(const HsaNodeProperties *props);
|
||||
unsigned int FamilyIdFromNode(const HsaNodeProperties * props);
|
||||
|
||||
|
||||
class HsaMemoryBuffer {
|
||||
public:
|
||||
static const HsaMemoryBuffer Null;
|
||||
|
||||
public:
|
||||
HsaMemoryBuffer(HSAuint64 size, unsigned int node, bool zero = true, bool isLocal = false,
|
||||
bool isExec = false, bool isScratch = false, bool isReadOnly = false);
|
||||
HsaMemoryBuffer(void *addr, HSAuint64 size);
|
||||
template<typename RetType>
|
||||
RetType As() {
|
||||
return reinterpret_cast<RetType>(m_pBuf);
|
||||
}
|
||||
|
||||
template<typename RetType>
|
||||
const RetType As() const {
|
||||
return reinterpret_cast<const RetType>(m_pBuf);
|
||||
}
|
||||
|
||||
/* Fill @size bytes of buffer with @value starting from @offset
|
||||
* If @size is 0, the whole buffer is filled with @value
|
||||
*/
|
||||
void Fill(unsigned char value, HSAuint64 offset = 0, HSAuint64 size = 0);
|
||||
void Fill(HSAuint32 value, HSAuint64 offset = 0, HSAuint64 size = 0);
|
||||
void Fill(int value, HSAuint64 offset = 0, HSAuint64 size = 0) {
|
||||
Fill((HSAuint32)value, offset, size);
|
||||
}
|
||||
void Fill(HSAuint32 value, BaseQueue& baseQueue,
|
||||
HSAuint64 offset = 0, HSAuint64 size = 0);
|
||||
|
||||
bool IsPattern(HSAuint64 location, HSAuint32 pattern);
|
||||
bool IsPattern(HSAuint64 location, HSAuint32 pattern,
|
||||
BaseQueue& baseQueue, volatile HSAuint32 *tmp);
|
||||
|
||||
unsigned int Size();
|
||||
HsaMemFlags Flags();
|
||||
unsigned int Node() const;
|
||||
|
||||
int MapMemToNodes(unsigned int *nodes, unsigned int nodes_num);
|
||||
int UnmapMemToNodes(unsigned int *nodes, unsigned int nodes_num);
|
||||
|
||||
void *GetUserPtr() { return m_pUser; }
|
||||
bool isLocal() { return m_Local; }
|
||||
~HsaMemoryBuffer();
|
||||
|
||||
private:
|
||||
// disable copy
|
||||
HsaMemoryBuffer(const HsaMemoryBuffer&);
|
||||
const HsaMemoryBuffer& operator=(const HsaMemoryBuffer&);
|
||||
|
||||
void UnmapAllNodes();
|
||||
HsaMemoryBuffer();
|
||||
|
||||
private:
|
||||
HsaMemFlags m_Flags;
|
||||
HSAuint64 m_Size;
|
||||
void* m_pUser;
|
||||
void* m_pBuf;
|
||||
bool m_Local;
|
||||
unsigned int m_Node;
|
||||
unsigned short m_MappedNodes;
|
||||
};
|
||||
|
||||
|
||||
|
||||
class HsaInteropMemoryBuffer {
|
||||
public:
|
||||
HsaInteropMemoryBuffer(unsigned long long device_handle, unsigned long long buffer_handle, unsigned long long size, unsigned int node);
|
||||
|
||||
template<typename RetType>
|
||||
RetType As() {
|
||||
return reinterpret_cast<RetType>(m_pBuf);
|
||||
}
|
||||
|
||||
template<typename RetType>
|
||||
const RetType As() const {
|
||||
return reinterpret_cast<const RetType>(m_pBuf);
|
||||
}
|
||||
|
||||
unsigned int Size();
|
||||
|
||||
~HsaInteropMemoryBuffer();
|
||||
|
||||
private:
|
||||
// disable copy
|
||||
HsaInteropMemoryBuffer(const HsaInteropMemoryBuffer&);
|
||||
const HsaInteropMemoryBuffer& operator=(const HsaInteropMemoryBuffer&);
|
||||
|
||||
private:
|
||||
unsigned long long m_Size;
|
||||
void* m_pBuf;
|
||||
unsigned long long m_graphic_handle;
|
||||
unsigned int m_Node;
|
||||
};
|
||||
|
||||
// Class HsaNodeInfo - Gather and store all HSA node information from Thunk.
|
||||
//
|
||||
class HsaNodeInfo {
|
||||
// List containing HsaNodeProperties of all Nodes available
|
||||
std::vector<HsaNodeProperties*> m_HsaNodeProps;
|
||||
|
||||
// List of HSA Nodes that contain a GPU. This includes both APU and dGPU
|
||||
std::vector<int> m_NodesWithGPU;
|
||||
|
||||
// List of HSA Nodes with CPU only
|
||||
std::vector<int> m_NodesWithoutGPU;
|
||||
|
||||
public:
|
||||
HsaNodeInfo();
|
||||
~HsaNodeInfo();
|
||||
|
||||
bool Init(int NumOfNodes);
|
||||
|
||||
// This function should be soon depricated. This for transistion purpose only
|
||||
// Currently, KfdTest is designed to test only ONE node. This function acts
|
||||
// as transistion.
|
||||
const HsaNodeProperties* HsaDefaultGPUNodeProperties() const;
|
||||
const int HsaDefaultGPUNode() const;
|
||||
|
||||
// Future use the following two functions to support multi-GPU.
|
||||
// const std::vector<int>& GpuNodes = GetNodesWithGPU()
|
||||
// for (..GpuNodes.size()..) GetNodeProperties(GpuNodes.at(i))
|
||||
//
|
||||
const std::vector<int>& GetNodesWithGPU() const;
|
||||
|
||||
// @param node index of the node we are looking at
|
||||
// @param nodeProperties HsaNodeProperties returned
|
||||
const HsaNodeProperties* GetNodeProperties(int NodeNum) const;
|
||||
|
||||
void PrintNodeInfo() const;
|
||||
const bool IsGPUNodeLargeBar(int node) const;
|
||||
// @brief Find the first available Large-BAR GPU node
|
||||
// @return: Node ID if successful or -1
|
||||
const int FindLargeBarGPUNode() const;
|
||||
};
|
||||
|
||||
#endif // __KFD__TEST__UTIL__H__
|
||||
@@ -0,0 +1,220 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDTopologyTest.hpp"
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
// @todo complete topology test according to whats in: hsathk\source\windows\kmt_topology.cpp
|
||||
|
||||
const unsigned long long KFDTopologyTest::c_4Gigabyte = (1ull << 32) - 1;
|
||||
const unsigned long long KFDTopologyTest::c_40BitAddressSpace = (1ull << 40);
|
||||
|
||||
TEST_F(KFDTopologyTest , BasicTest) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
|
||||
// goes over all nodes in the sytem properties and check the basic info received
|
||||
for (unsigned node = 0; node < m_SystemProperties.NumNodes; node++) {
|
||||
pNodeProperties = m_NodeInfo.GetNodeProperties(node);
|
||||
if (pNodeProperties != NULL) {
|
||||
// checking for cpu core only if it's a cpu only node or if its KAVERY apu.
|
||||
if (pNodeProperties->DeviceId == 0 || FamilyIdFromNode(pNodeProperties) == FAMILY_KV) {
|
||||
EXPECT_GT(pNodeProperties->NumCPUCores, HSAuint32(0)) << "Node index: " << node << " No CPUs core are connected for node index";
|
||||
}
|
||||
|
||||
// if it's not a cpu only node, look for a gpu core
|
||||
if (pNodeProperties->DeviceId != 0) {
|
||||
EXPECT_GT(pNodeProperties->NumFComputeCores, HSAuint32(0)) << "Node index: " << node << "No GPUs core are connected.";
|
||||
// EngineId only applies to GPU, not CPU-only nodes
|
||||
EXPECT_GT(pNodeProperties->EngineId.ui32.uCode, 0) << "uCode version is 0";
|
||||
EXPECT_GE(pNodeProperties->EngineId.ui32.Major, 7) << "Major Version is less than 7";
|
||||
EXPECT_LT(pNodeProperties->EngineId.ui32.Minor, 10) << "Minor Version is greater than 9";
|
||||
EXPECT_LT(pNodeProperties->EngineId.ui32.Stepping, 10) << "Stepping is greater than 9";
|
||||
EXPECT_GT(pNodeProperties->uCodeEngineVersions.uCodeSDMA, 0) << "sDMA firmware version is 0";
|
||||
}
|
||||
EXPECT_GT(pNodeProperties->NumMemoryBanks, HSAuint32(0)) << "Node index: " << node << "No MemoryBanks.";
|
||||
EXPECT_GT(pNodeProperties->NumCaches, HSAuint32(0)) << "Node index: " << node << "No Caches.";
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// this test verify failure status on hsaKmtGetNodeProperties with invalid params
|
||||
TEST_F(KFDTopologyTest, GetNodePropertiesInvalidParams) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
EXPECT_EQ(HSAKMT_STATUS_INVALID_PARAMETER, hsaKmtGetNodeProperties(0, NULL));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// this test verify failure status on hsaKmtGetNodeProperties with invalid params
|
||||
TEST_F(KFDTopologyTest, GetNodePropertiesInvalidNodeNum) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
HsaNodeProperties nodeProperties;
|
||||
memset(&nodeProperties, 0, sizeof(nodeProperties));
|
||||
EXPECT_EQ(HSAKMT_STATUS_INVALID_PARAMETER, hsaKmtGetNodeProperties(m_SystemProperties.NumNodes, &nodeProperties));
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// test that we can get memory property successfully per node
|
||||
// @todo check validity of values returned
|
||||
TEST_F(KFDTopologyTest, GetNodeMemoryProperties) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
|
||||
for (unsigned node = 0; node < m_SystemProperties.NumNodes; node++) {
|
||||
pNodeProperties = m_NodeInfo.GetNodeProperties(node);
|
||||
|
||||
if (pNodeProperties != NULL) {
|
||||
HsaMemoryProperties *memoryProperties = new HsaMemoryProperties[pNodeProperties->NumMemoryBanks];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeMemoryProperties(node, pNodeProperties->NumMemoryBanks, memoryProperties));
|
||||
delete [] memoryProperties;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
|
||||
// test the GPU local memory aperture is valid.
|
||||
TEST_F(KFDTopologyTest, GpuvmApertureValidate) {
|
||||
TEST_REQUIRE_NO_ENV_CAPABILITIES(ENVCAPS_32BITLINUX);
|
||||
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
const std::vector<int> GpuNodes = m_NodeInfo.GetNodesWithGPU();
|
||||
|
||||
for (unsigned i = 0; i < GpuNodes.size(); i++) {
|
||||
pNodeProperties = m_NodeInfo.GetNodeProperties(GpuNodes.at(i));
|
||||
if (pNodeProperties != NULL) {
|
||||
if (!is_dgpu() && !(FamilyIdFromNode(pNodeProperties) == FAMILY_KV)) {
|
||||
LOG() << "Skipping test: GPUVM framebuffer heap not exposed on APU except Kaveri" << std::endl;
|
||||
return;
|
||||
}
|
||||
HsaMemoryProperties *memoryProperties = new HsaMemoryProperties[pNodeProperties->NumMemoryBanks];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeMemoryProperties(GpuNodes.at(i), pNodeProperties->NumMemoryBanks, memoryProperties));
|
||||
bool GpuVMHeapFound = false;
|
||||
for (unsigned int bank = 0 ; bank < pNodeProperties->NumMemoryBanks ; bank++) {
|
||||
// Check for either private (small-bar/APU) or public (large-bar)
|
||||
if ((HSA_HEAPTYPE_FRAME_BUFFER_PRIVATE == memoryProperties[bank].HeapType) ||
|
||||
(HSA_HEAPTYPE_FRAME_BUFFER_PUBLIC == memoryProperties[bank].HeapType))
|
||||
GpuVMHeapFound = true;
|
||||
}
|
||||
EXPECT_TRUE(GpuVMHeapFound);
|
||||
delete [] memoryProperties;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// test that we can get cache property successfully per node
|
||||
// @todo check validity of values returned
|
||||
TEST_F(KFDTopologyTest, GetNodeCacheProperties) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
|
||||
for (unsigned node = 0; node < m_SystemProperties.NumNodes; node++) {
|
||||
pNodeProperties = m_NodeInfo.GetNodeProperties(node);
|
||||
if (pNodeProperties != NULL) {
|
||||
HsaCacheProperties *cacheProperties = new HsaCacheProperties[pNodeProperties->NumCaches];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeCacheProperties(node, pNodeProperties->CComputeIdLo, pNodeProperties->NumCaches, cacheProperties));
|
||||
if (pNodeProperties->NumCPUCores > 0) { // this is a CPU node
|
||||
LOG() << "CPU Node " << std::dec << node << ": " << pNodeProperties->NumCaches << " caches" << std::endl;
|
||||
for (unsigned n = 0; n < pNodeProperties->NumCaches; n++) {
|
||||
LOG()<< n << " - Level " << cacheProperties[n].CacheLevel <<
|
||||
" Type " << cacheProperties[n].CacheType.Value <<
|
||||
" Size " << (cacheProperties[n].CacheSize >> 10) << "K " <<
|
||||
" Associativity " << cacheProperties[n].CacheAssociativity <<
|
||||
" LineSize " << cacheProperties[n].CacheLineSize <<
|
||||
" LinesPerTag " << cacheProperties[n].CacheLinesPerTag << std::endl;
|
||||
char string[1024] = "";
|
||||
char sibling[5] = "";
|
||||
for (unsigned i = 0; i < 256; i++) {
|
||||
if (cacheProperties[n].SiblingMap[i]) {
|
||||
sprintf(sibling, "%d,", i);
|
||||
strcat(string, sibling);
|
||||
}
|
||||
}
|
||||
LOG() << " ProcIdLow " << cacheProperties[n].ProcessorIdLow <<
|
||||
" SiblingMap " << string << std::endl;
|
||||
}
|
||||
}
|
||||
delete [] cacheProperties;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
|
||||
// test that we can get NodeIoLink property successfully per node
|
||||
// @todo check validity of values returned
|
||||
// GetNodeIoLinkProperties is disabled for now, test fails due to bug in BIOS
|
||||
TEST_F(KFDTopologyTest, GetNodeIoLinkProperties) {
|
||||
TEST_START(TESTPROFILE_RUNALL)
|
||||
const HsaNodeProperties *pNodeProperties;
|
||||
int linkId;
|
||||
char c;
|
||||
|
||||
LOG() << "Topology. [FromNode]--(Weight)-->[ToNode]" << std::endl;
|
||||
|
||||
for (unsigned node = 0; node < m_SystemProperties.NumNodes; node++) {
|
||||
pNodeProperties = m_NodeInfo.GetNodeProperties(node);
|
||||
|
||||
if (pNodeProperties != NULL) {
|
||||
HsaIoLinkProperties *IolinkProperties = new HsaIoLinkProperties[pNodeProperties->NumIOLinks];
|
||||
EXPECT_SUCCESS(hsaKmtGetNodeIoLinkProperties(node, pNodeProperties->NumIOLinks, IolinkProperties));
|
||||
if (pNodeProperties->NumIOLinks == 0) {
|
||||
// No io_links. Just Print the node
|
||||
LOG() << "[" << node << "]" << std::endl;
|
||||
continue;
|
||||
}
|
||||
|
||||
for (linkId = 0; linkId < pNodeProperties->NumIOLinks; linkId++) {
|
||||
if (linkId == 0) {
|
||||
// First io_link. Print Parent Node and io_link Node
|
||||
LOG() << "[" << node << "]--(" << IolinkProperties[linkId].Weight << ")-->" <<
|
||||
"[" << IolinkProperties[linkId].NodeTo << "]" << std::endl;
|
||||
continue;
|
||||
}
|
||||
if (linkId == (pNodeProperties->NumIOLinks - 1))
|
||||
c = '`'; // last node
|
||||
else
|
||||
c = '|';
|
||||
LOG() << " " << c << "--(" << IolinkProperties[linkId].Weight << ")-->" <<
|
||||
"[" << IolinkProperties[linkId].NodeTo << "]" << std::endl;
|
||||
}
|
||||
LOG() << std::endl;
|
||||
delete [] IolinkProperties;
|
||||
}
|
||||
}
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
#ifndef __KFD_TOPOLOGY_TEST__H__
|
||||
#define __KFD_TOPOLOGY_TEST__H__
|
||||
|
||||
// @class KFDTopologyTest
|
||||
// this class has no additional features to KFDBaseComponentTest
|
||||
// the separation was made so we are able to goup all topology tests together
|
||||
class KFDTopologyTest : public KFDBaseComponentTest {
|
||||
public:
|
||||
KFDTopologyTest(void) {}
|
||||
~KFDTopologyTest(void) {}
|
||||
static const unsigned long long c_4Gigabyte;
|
||||
static const unsigned long long c_40BitAddressSpace;
|
||||
};
|
||||
|
||||
#endif // __KFD_TOPOLOGY_TEST__H__
|
||||
@@ -0,0 +1,240 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef WIN32
|
||||
|
||||
#include "OSWrapper.hpp"
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <getopt.h>
|
||||
#include <drm.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <string.h>
|
||||
#include <sys/mman.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/time.h>
|
||||
|
||||
static int protection_flags[8] = {int(PROT_NONE), int(PROT_READ), int(PROT_WRITE), int(PROT_READ | PROT_WRITE), int(PROT_EXEC), int(PROT_EXEC | PROT_READ), int(PROT_EXEC | PROT_WRITE), int(PROT_EXEC | PROT_WRITE | PROT_READ)};
|
||||
|
||||
void SetConsoleTextColor(TEXTCOLOR color) {
|
||||
// TODO complete
|
||||
}
|
||||
|
||||
void Delay(int delayCount) {
|
||||
// usleeps accept time in microseconds
|
||||
usleep(delayCount * 1000);
|
||||
}
|
||||
|
||||
void *VirtualAllocMemory(void *address, unsigned int size, int memProtection ) {
|
||||
void *ptr;
|
||||
|
||||
ptr = mmap(address, size, protection_flags[memProtection], MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
|
||||
|
||||
if (ptr == MAP_FAILED)
|
||||
ptr = NULL;
|
||||
return ptr;
|
||||
}
|
||||
|
||||
bool VirtualFreeMemory(void *address, unsigned int size) {
|
||||
if (munmap(address, size) == 0)
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long GetLastErrorNo() {
|
||||
return errno;
|
||||
}
|
||||
|
||||
bool MultiProcessTest(const char *testToRun, int numOfProcesses, int runsPerProcess) {
|
||||
// TODO IMPLEMENT
|
||||
return false;
|
||||
}
|
||||
|
||||
unsigned long long GetSystemTickCountInMicroSec() {
|
||||
struct timeval t;
|
||||
gettimeofday(&t, 0);
|
||||
return t.tv_sec * 1000000ULL + t.tv_usec;
|
||||
}
|
||||
|
||||
bool SuspendAndWakeUp() {
|
||||
// TODO IMPLEMENT
|
||||
return false;
|
||||
}
|
||||
|
||||
void AcquirePrivilege(OS_PRIVILEGE priv) {
|
||||
// TODO IMPLEMENT
|
||||
}
|
||||
|
||||
void DisableKfd() {
|
||||
// TODO IMPLEMENT
|
||||
}
|
||||
|
||||
void EnableKfd() {
|
||||
// TODO IMPLEMENT
|
||||
}
|
||||
|
||||
bool ReadDriverConfigValue(CONFIG_VALUE config, unsigned int& rValue) {
|
||||
return false;
|
||||
}
|
||||
|
||||
void ComandLineArgumentsUsage() {
|
||||
printf("Invalid option value\n");
|
||||
printf("\t--hws arg\t - Force HW capability\n");
|
||||
printf("\t--profile arg\t - Test profile\n");
|
||||
printf("\t--child arg\t - Child Process\n");
|
||||
printf("\t--timeout arg\t - Time Out\n");
|
||||
printf("\t--dst_node\t - For testing multiple nodes");
|
||||
}
|
||||
|
||||
bool GetCommandLineArguments(int argc, char **argv, CommandLineArguments& rArgs) {
|
||||
int option_index = 0;
|
||||
|
||||
/* Make getop silent */
|
||||
opterr = 0;
|
||||
static struct option long_options[] = {
|
||||
{ "hws", required_argument, 0, 0 },
|
||||
{ "profile", required_argument, 0, 0},
|
||||
{ "child", required_argument, 0, 0},
|
||||
{ "timeout", required_argument, 0, 0},
|
||||
{ "node", required_argument, 0, 0 },
|
||||
{ "dst_node", required_argument, 0, 0 },
|
||||
{ 0, 0, 0, 0 }
|
||||
};
|
||||
|
||||
rArgs.HwsEnabled = HWCAP__DEFAULT;
|
||||
rArgs.TestProfile = TESTPROFILE_RUNALL;
|
||||
rArgs.ChildProcess = false;
|
||||
rArgs.TimeOut = 0;
|
||||
rArgs.NodeId = -1;
|
||||
rArgs.DstNodeId = -1;
|
||||
|
||||
while (true) {
|
||||
int c = getopt_long(argc, argv, "", long_options, &option_index);
|
||||
|
||||
/* Detect the end of the options. */
|
||||
if (c != 0)
|
||||
break;
|
||||
|
||||
/* If this option set a flag, do nothing else now. */
|
||||
if (long_options[option_index].flag != 0)
|
||||
continue;
|
||||
|
||||
if (optarg == NULL) {
|
||||
ComandLineArgumentsUsage();
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (option_index) {
|
||||
/* HWS case */
|
||||
case 0:
|
||||
if (!strcmp(optarg, "disable")) {
|
||||
rArgs.HwsEnabled = HWCAP__FORCE_DISABLED;
|
||||
} else if (!strcmp(optarg, "enable")) {
|
||||
rArgs.HwsEnabled = HWCAP__FORCE_ENABLED;
|
||||
} else {
|
||||
ComandLineArgumentsUsage();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
/* TEST PROFILE */
|
||||
case 1:
|
||||
if (!strcmp(optarg, "dev")) {
|
||||
rArgs.TestProfile = TESTPROFILE_DEV;
|
||||
} else if (!strcmp(optarg, "promo")) {
|
||||
rArgs.TestProfile = TESTPROFILE_PROMO;
|
||||
} else if (!strcmp(optarg, "all")) {
|
||||
rArgs.TestProfile = TESTPROFILE_RUNALL;
|
||||
} else {
|
||||
ComandLineArgumentsUsage();
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
rArgs.ChildProcess = true;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
{
|
||||
int timeOut = atoi(optarg);
|
||||
if (timeOut > 0)
|
||||
rArgs.TimeOut = timeOut;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
{
|
||||
int nodeId = atoi(optarg);
|
||||
if (nodeId >= 0)
|
||||
rArgs.NodeId = nodeId;
|
||||
}
|
||||
break;
|
||||
case 5:
|
||||
{
|
||||
int dstNodeId = atoi(optarg);
|
||||
if (dstNodeId >= 0)
|
||||
rArgs.DstNodeId = dstNodeId;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void HWMemoryBarrier() {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
bool StartThread(unsigned int (*thread_func)(void*), void* param, uint64_t& thread_id) {
|
||||
pthread_t id;
|
||||
bool ret = false;
|
||||
typedef void* (*pthread_func_t)(void*);
|
||||
|
||||
if (!pthread_create(&id, NULL, (pthread_func_t)thread_func, param)) {
|
||||
thread_id = (pthread_t)id;
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool WaitForThread(uint64_t threadId) {
|
||||
return 0 == pthread_join((pthread_t)threadId, NULL);
|
||||
}
|
||||
|
||||
long AtomicInc(volatile long* pValue) {
|
||||
return __sync_add_and_fetch(pValue, 1);
|
||||
}
|
||||
|
||||
void MemoryBarrier() {
|
||||
__sync_synchronize();
|
||||
}
|
||||
|
||||
#endif // !WIN32
|
||||
@@ -0,0 +1,117 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <string>
|
||||
|
||||
#include "KFDTestFlags.hpp"
|
||||
|
||||
#ifndef __OS__WRAPPER__H__
|
||||
#define __OS__WRAPPER__H__
|
||||
|
||||
#ifndef PAGE_SIZE
|
||||
#define PAGE_SIZE (1<<12)
|
||||
#define PAGE_SHIFT (12)
|
||||
#endif
|
||||
|
||||
enum TEXTCOLOR {
|
||||
TEXTCOLOR_WHITE,
|
||||
TEXTCOLOR_GREEN,
|
||||
TEXTCOLOR_YELLOW
|
||||
};
|
||||
|
||||
enum OS_PRIVILEGE {
|
||||
OS_DRIVER_OPERATIONS,
|
||||
OS_SUSPEND
|
||||
};
|
||||
|
||||
enum CONFIG_VALUE {
|
||||
CONFIG_HWS
|
||||
};
|
||||
|
||||
enum HwCapabilityStatus {
|
||||
HWCAP__FORCE_DISABLED,
|
||||
HWCAP__DEFAULT,
|
||||
HWCAP__FORCE_ENABLED
|
||||
};
|
||||
|
||||
struct CommandLineArguments {
|
||||
HwCapabilityStatus HwsEnabled;
|
||||
TESTPROFILE TestProfile;
|
||||
bool ChildProcess;
|
||||
unsigned int TimeOut;
|
||||
int NodeId;
|
||||
int DstNodeId;
|
||||
};
|
||||
|
||||
// It is either MEM_NONE or the bitwise OR of one or more of the following flags
|
||||
#define MEM_NONE 0x00
|
||||
#define MEM_READ 0x01
|
||||
#define MEM_WRITE 0x02
|
||||
#define MEM_EXECUTE 0x4
|
||||
|
||||
|
||||
|
||||
// @brief change console text color
|
||||
void SetConsoleTextColor(TEXTCOLOR color);
|
||||
// @params delayCount : delay time in milliseconds
|
||||
void Delay(int delayCount);
|
||||
// @brief replacement for windows VirtualAlloc func
|
||||
void *VirtualAllocMemory(void *address, unsigned int size, int memProtection = MEM_READ | MEM_WRITE);
|
||||
// @brief replacement for windows FreeVirtual func
|
||||
bool VirtualFreeMemory(void *address, unsigned int size);
|
||||
// @brief retrieve the last error number
|
||||
unsigned long GetLastErrorNo();
|
||||
|
||||
long AtomicInc(volatile long* pValue);
|
||||
|
||||
void MemoryBarrier();
|
||||
|
||||
// @brief: runs the selected test case number of times required, each in a separate process
|
||||
// @params testToRun : can be a specific test testcase like TestCase.TestName or if you want to run all tests in a test case: TestCase.* and so on
|
||||
// @params numOfProcesses : how many processes to run in parallel
|
||||
// @params runsPerProcess : how many iteration a test should do per process, must be a positive number
|
||||
bool MultiProcessTest(const char *testToRun, int numOfProcesses, int runsPerProcess = 1);
|
||||
|
||||
unsigned long long GetSystemTickCountInMicroSec();
|
||||
|
||||
/**Put the system to S3/S4 power state and bring it back to S0.
|
||||
@return 'true' on success, 'false' on failure.
|
||||
*/
|
||||
bool SuspendAndWakeUp();
|
||||
|
||||
void AcquirePrivilege(OS_PRIVILEGE priv);
|
||||
|
||||
void DisableKfd();
|
||||
void EnableKfd();
|
||||
|
||||
bool ReadDriverConfigValue(CONFIG_VALUE config, unsigned int& rValue);
|
||||
|
||||
bool GetCommandLineArguments(int argc, char **argv, CommandLineArguments& rArgs);
|
||||
|
||||
void HWMemoryBarrier();
|
||||
bool StartThread(unsigned int (*)(void*), void* pParam, uint64_t& threadId);
|
||||
bool WaitForThread(uint64_t threadId);
|
||||
|
||||
#endif // __OS__WRAPPER__H__
|
||||
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PM4Packet.hpp"
|
||||
#include "hsakmttypes.h"
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "asic_reg/gfx_7_2_enum.h"
|
||||
|
||||
unsigned int PM4Packet::CalcCountValue() const {
|
||||
return (SizeInDWords() - (sizeof(PM4_TYPE_3_HEADER) / sizeof(uint32_t)) - 1);
|
||||
}
|
||||
|
||||
void PM4Packet::InitPM4Header(PM4_TYPE_3_HEADER &header, it_opcode_type opCode) {
|
||||
header.count = CalcCountValue();
|
||||
header.opcode = opCode;
|
||||
header.type = PM4_TYPE_3;
|
||||
header.shaderType = 1; // compute
|
||||
header.predicate = 0;
|
||||
header.reserved1 = 0;
|
||||
}
|
||||
|
||||
PM4WriteDataPacket::~PM4WriteDataPacket(void) {
|
||||
if (m_pPacketData)
|
||||
free(m_pPacketData);
|
||||
}
|
||||
|
||||
unsigned int PM4WriteDataPacket::SizeInBytes() const {
|
||||
return (offsetof(PM4WRITE_DATA_CI, data) + m_ndw*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
void PM4WriteDataPacket::InitPacket(unsigned int *destBuf, void *data) {
|
||||
m_pPacketData = (PM4WRITE_DATA_CI *)calloc(1, SizeInBytes());
|
||||
// verify that the memory is allocated successfully, cannot use assert here
|
||||
EXPECT_NOTNULL(m_pPacketData);
|
||||
|
||||
InitPM4Header(m_pPacketData->header, IT_WRITE_DATA);
|
||||
|
||||
m_pPacketData->bitfields2.dst_sel = dst_sel_mec_write_data_MEMORY_5; // memory-async
|
||||
m_pPacketData->bitfields2.addr_incr = addr_incr_mec_write_data_INCREMENT_ADDR_0; // increment addr
|
||||
m_pPacketData->bitfields2.wr_confirm = wr_confirm_mec_write_data_WAIT_FOR_CONFIRMATION_1;
|
||||
m_pPacketData->bitfields2.atc = is_dgpu() ?
|
||||
atc_write_data_NOT_USE_ATC_0 : atc_write_data_USE_ATC_1;
|
||||
m_pPacketData->bitfields2.cache_policy = cache_policy_mec_write_data_BYPASS_2;
|
||||
|
||||
m_pPacketData->dst_addr_lo = static_cast<uint32_t>(
|
||||
reinterpret_cast<uint64_t>(destBuf)); // byte addr
|
||||
m_pPacketData->dst_address_hi = static_cast<uint32_t>(
|
||||
reinterpret_cast<uint64_t>(destBuf) >> 32);
|
||||
|
||||
memcpy(m_pPacketData->data, data, m_ndw * sizeof(uint32_t));
|
||||
}
|
||||
|
||||
PM4ReleaseMemoryPacket::~PM4ReleaseMemoryPacket(void) {
|
||||
if (m_pPacketData)
|
||||
free(m_pPacketData);
|
||||
}
|
||||
|
||||
void PM4ReleaseMemoryPacket::InitPacket(bool isPolling, uint64_t address,
|
||||
uint64_t data, bool is64bit, bool isTimeStamp) {
|
||||
if (g_TestGPUFamilyId < FAMILY_AI) {
|
||||
PM4_RELEASE_MEM_CI *pkt;
|
||||
|
||||
m_packetSize = sizeof(PM4_RELEASE_MEM_CI);
|
||||
pkt = (PM4_RELEASE_MEM_CI *)calloc(1, m_packetSize);
|
||||
m_pPacketData = pkt;
|
||||
EXPECT_NOTNULL(m_pPacketData);
|
||||
|
||||
InitPM4Header(pkt->header, IT_RELEASE_MEM);
|
||||
|
||||
pkt->bitfields2.event_type = 0x14;
|
||||
pkt->bitfields2.event_index = event_index_mec_release_mem_EVENT_WRITE_EOP_5;
|
||||
// Possible values:
|
||||
// 0101(5): EVENT_WRITE_EOP event types
|
||||
// 0110(6): Reserved for EVENT_WRITE_EOS packet.
|
||||
// 0111(7): Reserved (previously) for EVENT_WRITE packet.
|
||||
pkt->bitfields2.l2_wb = 1;
|
||||
pkt->bitfields2.l2_inv = 1;
|
||||
pkt->bitfields2.cache_policy = cache_policy_mec_release_mem_BYPASS_2;
|
||||
pkt->bitfields2.atc = is_dgpu() ?
|
||||
atc_mec_release_mem_ci_NOT_USE_ATC_0 :
|
||||
atc_mec_release_mem_ci_USE_ATC_1; // ATC setting for fences and timestamps to the MC or TCL2.
|
||||
pkt->bitfields3.dst_sel = dst_sel_mec_release_mem_MEMORY_CONTROLLER_0;
|
||||
// Possible values:
|
||||
// 0 - memory_controller.
|
||||
// 1 - tc_l2.
|
||||
if (address) {
|
||||
pkt->bitfields3.int_sel = (isPolling ?
|
||||
int_sel_mec_release_mem_SEND_DATA_AFTER_WRITE_CONFIRM_3 :
|
||||
int_sel_mec_release_mem_SEND_INTERRUPT_AFTER_WRITE_CONFIRM_2);
|
||||
// Possible values:
|
||||
// 0 - None (Do not send an interrupt).
|
||||
// 1 - Send Interrupt Only. Program DATA_SEL 0".
|
||||
// 2 - Send Interrupt when Write Confirm (WC) is received from the MC.
|
||||
// 3 - Wait for WC, but dont send interrupt (applicable to 7.3+) [g73_1]
|
||||
// 4 - Reserved for INTERRUPT packet
|
||||
if (isTimeStamp && is64bit)
|
||||
pkt->bitfields3.data_sel = data_sel_mec_release_mem_SEND_GPU_CLOCK_COUNTER_3;
|
||||
else
|
||||
pkt->bitfields3.data_sel = is64bit ?
|
||||
data_sel_mec_release_mem_SEND_64_BIT_DATA_2 :
|
||||
data_sel_mec_release_mem_SEND_32_BIT_LOW_1;
|
||||
// Possible values:
|
||||
// 0 - None, i.e., Discard Data.
|
||||
// 1 - Send 32-bit Data Low (Discard Data High).
|
||||
// 2 - Send 64-bit Data.
|
||||
// 3 - Send current value of the 64 bit global GPU clock counter.
|
||||
// 4 - Send current value of the 64 bit system clock counter.
|
||||
// 5 - Store GDS Data to memory.
|
||||
// 6 - Reserved for use by the CP for Signal Semaphore.
|
||||
// 7 - Reserved for use by the CP for Wait Semaphore.
|
||||
} else {
|
||||
pkt->bitfields3.int_sel = (isPolling ?
|
||||
int_sel_mec_release_mem_NONE_0 :
|
||||
int_sel_mec_release_mem_SEND_INTERRUPT_ONLY_1);
|
||||
pkt->bitfields3.data_sel = data_sel_mec_release_mem_NONE_0;
|
||||
}
|
||||
|
||||
pkt->bitfields4a.address_lo_dword_aligned = static_cast<uint32_t>((address&0xffffffff) >> 2);
|
||||
pkt->addr_hi = static_cast<uint32_t>(address>>32);
|
||||
|
||||
pkt->data_lo = static_cast<uint32_t>(data);
|
||||
pkt->data_hi = static_cast<uint32_t>(data >> 32);
|
||||
} else {
|
||||
PM4MEC_RELEASE_MEM_AI *pkt;
|
||||
|
||||
m_packetSize = sizeof(PM4MEC_RELEASE_MEM_AI);
|
||||
pkt = (PM4MEC_RELEASE_MEM_AI *)calloc(1, m_packetSize);
|
||||
m_pPacketData = pkt;
|
||||
EXPECT_NOTNULL(m_pPacketData);
|
||||
|
||||
InitPM4Header(pkt->header, IT_RELEASE_MEM);
|
||||
|
||||
pkt->bitfields2.event_type = 0x14;
|
||||
pkt->bitfields2.event_index = event_index__mec_release_mem__end_of_pipe;
|
||||
pkt->bitfields2.tc_wb_action_ena = 1;
|
||||
pkt->bitfields2.tc_action_ena = 1;
|
||||
pkt->bitfields2.cache_policy = cache_policy__mec_release_mem__lru;
|
||||
|
||||
pkt->bitfields3.dst_sel = dst_sel__mec_release_mem__memory_controller;
|
||||
|
||||
if (address) {
|
||||
pkt->bitfields3.int_sel = (isPolling ?
|
||||
int_sel__mec_release_mem__send_data_after_write_confirm:
|
||||
int_sel__mec_release_mem__send_interrupt_after_write_confirm);
|
||||
|
||||
if (isTimeStamp && is64bit)
|
||||
pkt->bitfields3.data_sel = data_sel__mec_release_mem__send_gpu_clock_counter;
|
||||
else
|
||||
pkt->bitfields3.data_sel = is64bit ?
|
||||
data_sel__mec_release_mem__send_64_bit_data :
|
||||
data_sel__mec_release_mem__send_32_bit_low;
|
||||
} else {
|
||||
pkt->bitfields3.int_sel = (isPolling ?
|
||||
int_sel__mec_release_mem__none:
|
||||
int_sel__mec_release_mem__send_interrupt_only);
|
||||
pkt->bitfields3.data_sel = data_sel__mec_release_mem__none;
|
||||
}
|
||||
|
||||
pkt->bitfields4a.address_lo_32b = static_cast<uint32_t>((address&0xffffffff) >> 2);
|
||||
pkt->address_hi = static_cast<uint32_t>(address>>32);
|
||||
|
||||
pkt->data_lo = static_cast<uint32_t>(data);
|
||||
pkt->data_hi = static_cast<uint32_t>(data >> 32);
|
||||
|
||||
pkt->int_ctxid = static_cast<uint32_t>(data);
|
||||
}
|
||||
}
|
||||
|
||||
PM4IndirectBufPacket::PM4IndirectBufPacket(IndirectBuffer *pIb) {
|
||||
InitPacket(pIb);
|
||||
}
|
||||
|
||||
unsigned int PM4IndirectBufPacket::SizeInBytes() const {
|
||||
return sizeof(PM4MEC_INDIRECT_BUFFER);
|
||||
}
|
||||
|
||||
void PM4IndirectBufPacket::InitPacket(IndirectBuffer *pIb) {
|
||||
memset(&m_packetData, 0, SizeInBytes());
|
||||
InitPM4Header(m_packetData.header, IT_INDIRECT_BUFFER);
|
||||
|
||||
m_packetData.bitfields2.ib_base_lo = static_cast<HSAuint32>((reinterpret_cast<HSAuint64>(pIb->Addr()))) >> 2;
|
||||
m_packetData.bitfields3.ib_base_hi = reinterpret_cast<HSAuint64>(pIb->Addr()) >> 32;
|
||||
m_packetData.bitfields4.ib_size = pIb->SizeInDWord();
|
||||
m_packetData.bitfields4.chain = 0;
|
||||
m_packetData.bitfields4.offload_polling = 0;
|
||||
m_packetData.bitfields4.volatile_setting = 0;
|
||||
m_packetData.bitfields4.valid = 1;
|
||||
m_packetData.bitfields4.vmid = 0; // in iommutest: vmid = queueParams.VMID;
|
||||
m_packetData.bitfields4.cache_policy = cache_policy_indirect_buffer_BYPASS_2;
|
||||
}
|
||||
|
||||
PM4AcquireMemoryPacket::PM4AcquireMemoryPacket(void) {
|
||||
memset(&m_packetData, 0, SizeInBytes());
|
||||
InitPM4Header(m_packetData.header, IT_ACQUIRE_MEM);
|
||||
|
||||
m_packetData.bitfields2.coher_cntl = 0x28c00000; // copied from the way the HSART does this.
|
||||
m_packetData.bitfields2.engine = engine_acquire_mem_PFP_0;
|
||||
m_packetData.coher_size = 0xFFFFFFFF;
|
||||
m_packetData.bitfields3.coher_size_hi = 0;
|
||||
m_packetData.coher_base_lo = 0;
|
||||
m_packetData.bitfields4.coher_base_hi = 0;
|
||||
m_packetData.bitfields5.poll_interval = 4; // copied from the way the HSART does this.
|
||||
}
|
||||
|
||||
unsigned int PM4AcquireMemoryPacket::SizeInBytes() const {
|
||||
return sizeof(PM4ACQUIRE_MEM);
|
||||
}
|
||||
|
||||
PM4SetShaderRegPacket::PM4SetShaderRegPacket(void)
|
||||
: m_packetDataAllocated(false) {
|
||||
}
|
||||
|
||||
PM4SetShaderRegPacket::PM4SetShaderRegPacket(unsigned int baseOffset, const unsigned int regValues[], unsigned int numRegs)
|
||||
: m_packetDataAllocated(false) {
|
||||
InitPacket(baseOffset, regValues, numRegs);
|
||||
}
|
||||
|
||||
PM4SetShaderRegPacket::~PM4SetShaderRegPacket(void) {
|
||||
if (m_packetDataAllocated)
|
||||
free(m_pPacketData);
|
||||
}
|
||||
|
||||
void PM4SetShaderRegPacket::InitPacket(unsigned int baseOffset, const unsigned int regValues[], unsigned int numRegs) {
|
||||
m_packetSize = sizeof(PM4SET_SH_REG) + (numRegs-1)*sizeof(uint32_t); // 1st register is a part of the packet struct.
|
||||
|
||||
// allocating the size of the packet, since the packet is assembled from a struct followed by an additional DWORD data
|
||||
m_pPacketData = (PM4SET_SH_REG *)malloc(m_packetSize);
|
||||
|
||||
ASSERT_NOTNULL(m_pPacketData);
|
||||
|
||||
m_packetDataAllocated = true;
|
||||
|
||||
memset(m_pPacketData, 0, m_packetSize);
|
||||
|
||||
InitPM4Header(m_pPacketData->header, IT_SET_SH_REG);
|
||||
|
||||
m_pPacketData->bitfields2.reg_offset = baseOffset - PERSISTENT_SPACE_START;
|
||||
|
||||
memcpy(m_pPacketData->reg_data, regValues, numRegs*sizeof(uint32_t));
|
||||
}
|
||||
|
||||
PM4DispatchDirectPacket::PM4DispatchDirectPacket(unsigned int dimX, unsigned int dimY, unsigned int dimZ, unsigned int dispatchInit) {
|
||||
InitPacket(dimX, dimY, dimZ, dispatchInit);
|
||||
}
|
||||
|
||||
void PM4DispatchDirectPacket::InitPacket(unsigned int dimX, unsigned int dimY, unsigned int dimZ, unsigned int dispatchInit) {
|
||||
memset(&m_packetData, 0, SizeInBytes());
|
||||
InitPM4Header(m_packetData.header, IT_DISPATCH_DIRECT);
|
||||
|
||||
m_packetData.dim_x = dimX;
|
||||
m_packetData.dim_y = dimY;
|
||||
m_packetData.dim_z = dimZ;
|
||||
m_packetData.dispatch_initiator = dispatchInit;
|
||||
}
|
||||
|
||||
unsigned int PM4DispatchDirectPacket::SizeInBytes() const {
|
||||
return sizeof(PM4DISPATCH_DIRECT);
|
||||
}
|
||||
|
||||
PM4PartialFlushPacket::PM4PartialFlushPacket(void) {
|
||||
memset(&m_packetData, 0, SizeInBytes());
|
||||
InitPM4Header(m_packetData.header, IT_EVENT_WRITE);
|
||||
|
||||
m_packetData.bitfields2.event_index = event_index_event_write_CS_VS_PS_PARTIAL_FLUSH_4;
|
||||
m_packetData.bitfields2.event_type = CS_PARTIAL_FLUSH;
|
||||
}
|
||||
|
||||
unsigned int PM4PartialFlushPacket::SizeInBytes() const {
|
||||
// for PARTIAL_FLUSH_CS packets, the last 2 DWORDS don't exist.
|
||||
return sizeof(PM4EVENT_WRITE) - sizeof(uint32_t)*2;
|
||||
}
|
||||
|
||||
PM4NopPacket::PM4NopPacket(void) {
|
||||
InitPM4Header(m_packetData, IT_NOP);
|
||||
}
|
||||
|
||||
unsigned int PM4NopPacket::SizeInBytes() const {
|
||||
return sizeof(m_packetData);
|
||||
}
|
||||
@@ -0,0 +1,221 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_PM4_PACKET__H__
|
||||
#define __KFD_PM4_PACKET__H__
|
||||
|
||||
#include "BasePacket.hpp"
|
||||
#include "kfd_pm4_opcodes.h"
|
||||
#include "pm4_pkt_struct_common.h"
|
||||
#include "pm4_pkt_struct_ci.h"
|
||||
#include "pm4_pkt_struct_ai.h"
|
||||
#include "IndirectBuffer.hpp"
|
||||
|
||||
// @class PM4Packet: marks a group of all PM4 packets
|
||||
class PM4Packet : public BasePacket {
|
||||
public:
|
||||
PM4Packet(void) {}
|
||||
virtual ~PM4Packet(void) {}
|
||||
|
||||
virtual PACKETTYPE PacketType() const { return PACKETTYPE_PM4; }
|
||||
unsigned int CalcCountValue() const;
|
||||
|
||||
protected:
|
||||
void InitPM4Header(PM4_TYPE_3_HEADER &header, it_opcode_type opCode);
|
||||
};
|
||||
|
||||
// @class PM4WriteDataPacket
|
||||
class PM4WriteDataPacket : public PM4Packet {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
PM4WriteDataPacket(void): m_ndw(0), m_pPacketData(NULL) {}
|
||||
// this contructor will also init the packet, no need for additional calls
|
||||
PM4WriteDataPacket(unsigned int *destBuf, unsigned int data1):
|
||||
m_ndw(1), m_pPacketData(NULL) {InitPacket(destBuf, &data1);}
|
||||
PM4WriteDataPacket(unsigned int *destBuf, unsigned int data1, unsigned int data2):
|
||||
m_ndw(2), m_pPacketData(NULL) {
|
||||
unsigned int data[2] = {data1, data2};
|
||||
InitPacket(destBuf, data);
|
||||
}
|
||||
|
||||
virtual ~PM4WriteDataPacket(void);
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return m_pPacketData; }
|
||||
// @brief initialise the packet
|
||||
void InitPacket(unsigned int *destBuf, unsigned int data1) {
|
||||
m_ndw = 1;
|
||||
InitPacket(destBuf, &data1);
|
||||
}
|
||||
void InitPacket(unsigned int *destBuf, unsigned int data1, unsigned int data2) {
|
||||
unsigned int data[2] = {data1, data2};
|
||||
m_ndw = 2;
|
||||
InitPacket(destBuf, data);
|
||||
}
|
||||
void InitPacket(unsigned int *destBuf, void *data);
|
||||
|
||||
protected:
|
||||
unsigned int m_ndw;
|
||||
// PM4WRITE_DATA_CI struct contains all the packets data
|
||||
PM4WRITE_DATA_CI *m_pPacketData;
|
||||
};
|
||||
|
||||
// @class PM4ReleaseMemoryPacket
|
||||
class PM4ReleaseMemoryPacket : public PM4Packet {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
PM4ReleaseMemoryPacket(void): m_pPacketData(NULL) {}
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
PM4ReleaseMemoryPacket(bool isPolling, uint64_t address, uint64_t data,
|
||||
bool is64bit = false, bool isTimeStamp = false): m_pPacketData(NULL) {
|
||||
InitPacket(isPolling, address, data, is64bit, isTimeStamp);
|
||||
}
|
||||
|
||||
virtual ~PM4ReleaseMemoryPacket(void);
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return m_packetSize; }
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return m_pPacketData; }
|
||||
// @brief initialise the packet
|
||||
void InitPacket(bool isPolling, uint64_t address, uint64_t data,
|
||||
bool is64bit = false, bool isTimeStamp = false);
|
||||
|
||||
private:
|
||||
void *m_pPacketData;
|
||||
unsigned int m_packetSize;
|
||||
};
|
||||
|
||||
// @class PM4IndirectBufPacket
|
||||
class PM4IndirectBufPacket : public PM4Packet {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
PM4IndirectBufPacket(void) {}
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
PM4IndirectBufPacket(IndirectBuffer *pIb);
|
||||
|
||||
virtual ~PM4IndirectBufPacket(void) {}
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &m_packetData; }
|
||||
// @breif initialise the packet
|
||||
void InitPacket(IndirectBuffer *pIb);
|
||||
|
||||
private:
|
||||
// PM4MEC_INDIRECT_BUFFER struct contains all the packets data
|
||||
PM4MEC_INDIRECT_BUFFER m_packetData;
|
||||
};
|
||||
|
||||
// @class PM4AcquireMemoryPacket
|
||||
class PM4AcquireMemoryPacket : public PM4Packet {
|
||||
public:
|
||||
PM4AcquireMemoryPacket(void);
|
||||
virtual ~PM4AcquireMemoryPacket(void) {}
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &m_packetData; }
|
||||
|
||||
private:
|
||||
// PM4ACQUIRE_MEM struct contains all the packets data
|
||||
PM4ACQUIRE_MEM m_packetData;
|
||||
};
|
||||
|
||||
// @class PM4SetShaderRegPacket packet that writes to consecutive registers starting at baseOffset.
|
||||
class PM4SetShaderRegPacket : public PM4Packet {
|
||||
public:
|
||||
PM4SetShaderRegPacket(void);
|
||||
|
||||
PM4SetShaderRegPacket(unsigned int baseOffset, const unsigned int regValues[], unsigned int numRegs);
|
||||
|
||||
virtual ~PM4SetShaderRegPacket(void);
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return m_packetSize; }
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return m_pPacketData; }
|
||||
|
||||
void InitPacket(unsigned int baseOffset, const unsigned int regValues[], unsigned int numRegs);
|
||||
|
||||
private:
|
||||
unsigned int m_packetSize;
|
||||
bool m_packetDataAllocated;
|
||||
// PM4SET_SH_REG struct contains all the packets data
|
||||
PM4SET_SH_REG *m_pPacketData;
|
||||
};
|
||||
|
||||
// @class PM4DispatchDirectPacket
|
||||
class PM4DispatchDirectPacket : public PM4Packet {
|
||||
public:
|
||||
PM4DispatchDirectPacket(void) {}
|
||||
|
||||
PM4DispatchDirectPacket(unsigned int dimX, unsigned int dimY, unsigned int dimZ, unsigned int dispatchInit);
|
||||
|
||||
virtual ~PM4DispatchDirectPacket(void) {}
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &m_packetData; }
|
||||
|
||||
void InitPacket(unsigned int dimX, unsigned int dimY, unsigned int dimZ, unsigned int dispatchInit);
|
||||
|
||||
private:
|
||||
// PM4DISPATCH_DIRECT struct contains all the packets data
|
||||
PM4DISPATCH_DIRECT m_packetData;
|
||||
};
|
||||
|
||||
// @class PM4PartialFlushPacket
|
||||
class PM4PartialFlushPacket : public PM4Packet {
|
||||
public:
|
||||
PM4PartialFlushPacket(void);
|
||||
virtual ~PM4PartialFlushPacket(void) {}
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &m_packetData; }
|
||||
|
||||
private:
|
||||
// PM4EVENT_WRITE struct contains all the packets data
|
||||
PM4EVENT_WRITE m_packetData;
|
||||
};
|
||||
|
||||
// @class PM4NopPacket
|
||||
class PM4NopPacket : public PM4Packet {
|
||||
public:
|
||||
PM4NopPacket(void);
|
||||
virtual ~PM4NopPacket(void) {}
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const;
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &m_packetData; }
|
||||
|
||||
private:
|
||||
PM4_TYPE_3_HEADER m_packetData;
|
||||
};
|
||||
|
||||
#endif // __KFD_PM4_PACKET__H__
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "PM4Queue.hpp"
|
||||
#include "pm4_pkt_struct_common.h"
|
||||
#include "GoogleTestExtension.hpp"
|
||||
#include "kfd_pm4_opcodes.h"
|
||||
|
||||
|
||||
PM4Queue::PM4Queue(void) {
|
||||
CMD_NOP = CMD_NOP_TYPE_3;
|
||||
}
|
||||
|
||||
PM4Queue::~PM4Queue(void) {
|
||||
}
|
||||
|
||||
unsigned int PM4Queue::Wptr() {
|
||||
/* Write pointer in dwords. Simulate 32-bit wptr that wraps at
|
||||
* queue size even on Vega10 and later chips with 64-bit wptr. */
|
||||
return *m_Resources.Queue_write_ptr % (m_QueueBuf->Size() / 4);
|
||||
}
|
||||
|
||||
unsigned int PM4Queue::Rptr() {
|
||||
/* CP read pointer in dwords. It's still 32-bit even on Vega10. */
|
||||
return *m_Resources.Queue_read_ptr;
|
||||
}
|
||||
|
||||
unsigned int PM4Queue::RptrWhenConsumed() {
|
||||
/* On PM4 queues Rptr is always 32-bit in dword units and wraps at
|
||||
* queue size. The expected value when all packets are consumed is
|
||||
* exactly the value returned by Wptr(). */
|
||||
return Wptr();
|
||||
}
|
||||
|
||||
void PM4Queue::SubmitPacket() {
|
||||
// m_pending Wptr is in DWORDs
|
||||
if (g_TestGPUFamilyId < FAMILY_AI) {
|
||||
// Pre-Vega10 uses 32-bit wptr and doorbell
|
||||
MemoryBarrier();
|
||||
*m_Resources.Queue_write_ptr = m_pendingWptr;
|
||||
MemoryBarrier();
|
||||
*(m_Resources.Queue_DoorBell) = m_pendingWptr;
|
||||
} else {
|
||||
// Vega10 and later uses 64-bit wptr and doorbell
|
||||
MemoryBarrier();
|
||||
*m_Resources.Queue_write_ptr_aql = m_pendingWptr64;
|
||||
MemoryBarrier();
|
||||
*(m_Resources.Queue_DoorBell_aql) = m_pendingWptr64;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_PM4_QUEUE__H__
|
||||
#define __KFD_PM4_QUEUE__H__
|
||||
|
||||
#include "BaseQueue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
|
||||
class PM4Queue : public BaseQueue {
|
||||
public:
|
||||
PM4Queue(void);
|
||||
virtual ~PM4Queue(void);
|
||||
|
||||
// @brief update queue write pointer and sets the queue doorbell to the queue write pointer
|
||||
virtual void SubmitPacket();
|
||||
|
||||
// @ return read pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Rptr();
|
||||
// @ return write pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Wptr();
|
||||
// @ return expected m_Resources.Queue_read_ptr when all packets consumed
|
||||
virtual unsigned int RptrWhenConsumed();
|
||||
|
||||
protected:
|
||||
virtual PACKETTYPE PacketTypeSupported() { return PACKETTYPE_PM4; }
|
||||
|
||||
virtual _HSA_QUEUE_TYPE GetQueueType() { return HSA_QUEUE_COMPUTE; }
|
||||
};
|
||||
|
||||
#endif // __KFD_PM4_QUEUE__H__
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "RDMATest.hpp"
|
||||
#include "PM4Queue.hpp"
|
||||
#include "PM4Packet.hpp"
|
||||
#include "SDMAPacket.hpp"
|
||||
#include "SDMAQueue.hpp"
|
||||
#include "Dispatch.hpp"
|
||||
#include "RDMAUtil.hpp"
|
||||
|
||||
void RDMATest::SetUp() {
|
||||
ROUTINE_START
|
||||
|
||||
KFDBaseComponentTest::SetUp();
|
||||
|
||||
m_pIsaGen = IsaGenerator::Create(m_FamilyId);
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
void RDMATest::TearDown() {
|
||||
ROUTINE_START
|
||||
if (m_pIsaGen)
|
||||
delete m_pIsaGen;
|
||||
m_pIsaGen = NULL;
|
||||
|
||||
KFDBaseComponentTest::TearDown();
|
||||
|
||||
ROUTINE_END
|
||||
}
|
||||
|
||||
TEST_F(RDMATest, GPUDirect) {
|
||||
TEST_REQUIRE_ENV_CAPABILITIES(ENVCAPS_64BITLINUX);
|
||||
TEST_START(TESTPROFILE_RUNALL);
|
||||
HSAuint64 AlternateVAGPU;
|
||||
|
||||
PM4Queue queue;
|
||||
unsigned int BufferSize = PAGE_SIZE;
|
||||
int ret;
|
||||
|
||||
int defaultGPUNode = m_NodeInfo.HsaDefaultGPUNode();
|
||||
ASSERT_GE(defaultGPUNode, 0) << "failed to get default GPU Node";
|
||||
|
||||
HsaMemoryBuffer isaBuffer(PAGE_SIZE, defaultGPUNode);
|
||||
HsaMemoryBuffer srcSysBuffer(BufferSize, defaultGPUNode, false);
|
||||
HsaMemoryBuffer srcLocalBuffer(BufferSize, defaultGPUNode, false, true);
|
||||
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(srcSysBuffer.As<void*>(),
|
||||
srcSysBuffer.Size(),
|
||||
&AlternateVAGPU));
|
||||
ASSERT_SUCCESS(hsaKmtMapMemoryToGPU(srcLocalBuffer.As<void*>(),
|
||||
srcLocalBuffer.Size(),
|
||||
&AlternateVAGPU));
|
||||
|
||||
/* Fill up srcSysBuffer */
|
||||
srcSysBuffer.Fill(0xfe);
|
||||
|
||||
/* Put 'copy dword' command to ISA buffer */
|
||||
m_pIsaGen->GetCopyDwordIsa(isaBuffer);
|
||||
|
||||
ASSERT_SUCCESS(queue.Create(defaultGPUNode));
|
||||
Dispatch dispatch(isaBuffer);
|
||||
|
||||
/* Submit the command to GPU so GPU will copy from system memory
|
||||
* (srcSysBuffer) to local memory(srcLocalBuffer)
|
||||
*/
|
||||
dispatch.SetArgs(srcSysBuffer.As<void*>(), srcLocalBuffer.As<void*>());
|
||||
dispatch.Submit(queue);
|
||||
dispatch.Sync(g_TestTimeOut); // GPU executed the command
|
||||
|
||||
ASSERT_SUCCESS(queue.Destroy());
|
||||
|
||||
LocalMemoryAccess Rdma;
|
||||
|
||||
Rdma.Open();
|
||||
ASSERT_GE(Rdma.fd, 0) << "Failed to open RDMA";
|
||||
|
||||
/* GetPages asks the test driver to convert GPU virtual memory to DMA/
|
||||
* Physical memory and save it in the list. rdma_mmap maps the memory to
|
||||
* user space memory.
|
||||
*/
|
||||
ret = Rdma.GetPages((uint64_t)srcLocalBuffer.As<void*>(), PAGE_SIZE);
|
||||
ASSERT_EQ(ret, 0) << "Failed to get pages";
|
||||
|
||||
void *gpuAddr = Rdma.MMap((uint64_t)srcLocalBuffer.As<void*>(), PAGE_SIZE);
|
||||
ASSERT_GE((uint64_t)gpuAddr, 0) << "Failed to map RDMA address.";
|
||||
|
||||
/* Read the memory to confirm that application can read the local memory
|
||||
* correctly from the mapped address.
|
||||
*/
|
||||
ASSERT_EQ(memcmp(gpuAddr, srcSysBuffer.As<void*>(), 4), 0);
|
||||
|
||||
Rdma.UnMap(gpuAddr, PAGE_SIZE);
|
||||
Rdma.Close();
|
||||
|
||||
TEST_END
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RDMA_TEST__H__
|
||||
#define __RDMA_TEST__H__
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "IsaGenerator.hpp"
|
||||
#include "KFDBaseComponentTest.hpp"
|
||||
|
||||
class RDMATest : public KFDBaseComponentTest {
|
||||
public:
|
||||
RDMATest():m_pIsaGen(NULL) {}
|
||||
~RDMATest() {}
|
||||
|
||||
protected:
|
||||
virtual void SetUp();
|
||||
virtual void TearDown();
|
||||
|
||||
protected: // members
|
||||
IsaGenerator* m_pIsaGen;
|
||||
};
|
||||
|
||||
#endif // __RDMA_TEST__H__
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <gtest/gtest.h>
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#include <sys/ioctl.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <fcntl.h>
|
||||
#include <sys/mman.h>
|
||||
#include <string>
|
||||
#include "amdp2ptest.h"
|
||||
#include "RDMAUtil.hpp"
|
||||
|
||||
void LocalMemoryAccess::Open() {
|
||||
fd = open(AMDP2PTEST_DEVICE_PATH, O_RDWR);
|
||||
}
|
||||
|
||||
void LocalMemoryAccess::Close() {
|
||||
close(fd);
|
||||
fd = -1;
|
||||
}
|
||||
|
||||
int LocalMemoryAccess::GetPages(uint64_t gpu_va_addr, uint64_t size) {
|
||||
struct AMDRDMA_IOCTL_GET_PAGES_PARAM param = {0};
|
||||
|
||||
if (fd <= 0)
|
||||
return -1;
|
||||
|
||||
param.addr = gpu_va_addr;
|
||||
param.length = size;
|
||||
|
||||
return ioctl(fd, AMD2P2PTEST_IOCTL_GET_PAGES, ¶m);
|
||||
}
|
||||
|
||||
void *LocalMemoryAccess::MMap(uint64_t offset, size_t size) {
|
||||
void *gpuAddr;
|
||||
|
||||
if (fd <= 0)
|
||||
return NULL;
|
||||
|
||||
gpuAddr = mmap(NULL, size, PROT_READ, MAP_PRIVATE, fd, offset);
|
||||
return gpuAddr;
|
||||
}
|
||||
|
||||
void LocalMemoryAccess::UnMap(void *offset, size_t size) {
|
||||
munmap(offset, size);
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (C) 2016-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __RDMA__UTIL__H__
|
||||
#define __RDMA__UTIL__H__
|
||||
|
||||
class LocalMemoryAccess {
|
||||
public:
|
||||
int fd;
|
||||
void Open(void);
|
||||
void Close(void);
|
||||
int GetPages(uint64_t, uint64_t);
|
||||
void *MMap(uint64_t, size_t);
|
||||
void UnMap(void *, size_t);
|
||||
};
|
||||
|
||||
#endif // __RDMA__UTIL__H__
|
||||
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include "SDMAPacket.hpp"
|
||||
#include "KFDTestUtil.hpp"
|
||||
|
||||
/* Byte/dword cound in many SDMA packets is 1-based in AI, meaning a
|
||||
* count of 1 is encoded as 0. */
|
||||
#define SDMA_COUNT(c) (g_TestGPUFamilyId < FAMILY_AI ? (c) : (c)-1)
|
||||
|
||||
SDMAWriteDataPacket::SDMAWriteDataPacket(void):
|
||||
packetData(NULL) {
|
||||
}
|
||||
|
||||
SDMAWriteDataPacket::SDMAWriteDataPacket(void* destAddr, unsigned int data):
|
||||
packetData(NULL) {
|
||||
InitPacket(destAddr, data);
|
||||
}
|
||||
|
||||
SDMAWriteDataPacket::SDMAWriteDataPacket(void* destAddr, unsigned int ndw,
|
||||
void *data):
|
||||
packetData(NULL) {
|
||||
InitPacket(destAddr, ndw, data);
|
||||
}
|
||||
|
||||
SDMAWriteDataPacket::~SDMAWriteDataPacket(void) {
|
||||
if (packetData)
|
||||
free(packetData);
|
||||
}
|
||||
|
||||
void SDMAWriteDataPacket::InitPacket(void* destAddr, unsigned int data) {
|
||||
InitPacket(destAddr, 1, &data);
|
||||
}
|
||||
|
||||
void SDMAWriteDataPacket::InitPacket(void* destAddr, unsigned int ndw,
|
||||
void *data) {
|
||||
packetSize = sizeof(SDMA_PKT_WRITE_UNTILED) +
|
||||
(ndw - 1) * sizeof(unsigned int);
|
||||
packetData = (SDMA_PKT_WRITE_UNTILED *)calloc(1, packetSize);
|
||||
|
||||
packetData->HEADER_UNION.op = SDMA_OP_WRITE;
|
||||
packetData->HEADER_UNION.sub_op = SDMA_SUBOP_WRITE_LINEAR;
|
||||
|
||||
SplitU64(reinterpret_cast<unsigned long long>(destAddr),
|
||||
packetData->DST_ADDR_LO_UNION.DW_1_DATA, // dst_addr_31_0
|
||||
packetData->DST_ADDR_HI_UNION.DW_2_DATA); // dst_addr_63_32
|
||||
|
||||
packetData->DW_3_UNION.count = SDMA_COUNT(ndw);
|
||||
memcpy(&packetData->DATA0_UNION.DW_4_DATA, data, ndw*sizeof(unsigned int));
|
||||
}
|
||||
|
||||
#define TWO_MEG (1 << 21)
|
||||
SDMACopyDataPacket::~SDMACopyDataPacket(void) {
|
||||
free(packetData);
|
||||
}
|
||||
|
||||
SDMACopyDataPacket::SDMACopyDataPacket(void* dst, void *src, unsigned int surfsize) {
|
||||
int32_t size = 0;
|
||||
packetSize = ((surfsize + TWO_MEG - 1) >> 21) * sizeof(SDMA_PKT_COPY_LINEAR);
|
||||
|
||||
SDMA_PKT_COPY_LINEAR *pSDMA = (SDMA_PKT_COPY_LINEAR *)malloc(packetSize);
|
||||
packetData = pSDMA;
|
||||
|
||||
while (surfsize > 0) {
|
||||
/* sdma support maximum 0x3fffe0 byte in one copy, take 2M here */
|
||||
if (surfsize > TWO_MEG)
|
||||
size = TWO_MEG;
|
||||
else
|
||||
size = surfsize;
|
||||
|
||||
memset(pSDMA, 0, sizeof(SDMA_PKT_COPY_LINEAR));
|
||||
pSDMA->HEADER_UNION.op = SDMA_OP_COPY;
|
||||
pSDMA->HEADER_UNION.sub_op = SDMA_SUBOP_COPY_LINEAR;
|
||||
pSDMA->COUNT_UNION.count = SDMA_COUNT(size);
|
||||
SplitU64(reinterpret_cast<unsigned long long>(src),
|
||||
pSDMA->SRC_ADDR_LO_UNION.DW_3_DATA, // src_addr_31_0
|
||||
pSDMA->SRC_ADDR_HI_UNION.DW_4_DATA); // src_addr_63_32
|
||||
SplitU64(reinterpret_cast<unsigned long long>(dst),
|
||||
pSDMA->DST_ADDR_LO_UNION.DW_5_DATA, // dst_addr_31_0
|
||||
pSDMA->DST_ADDR_HI_UNION.DW_6_DATA); // dst_addr_63_32
|
||||
|
||||
pSDMA++;
|
||||
src = (char *)src + size;
|
||||
dst = (char *)dst + size;
|
||||
surfsize -= size;
|
||||
}
|
||||
}
|
||||
|
||||
SDMAFillDataPacket::~SDMAFillDataPacket() {
|
||||
free(m_PacketData);
|
||||
}
|
||||
|
||||
SDMAFillDataPacket::SDMAFillDataPacket(void *dst, unsigned int data, unsigned int size) {
|
||||
unsigned int copy_size;
|
||||
SDMA_PKT_CONSTANT_FILL *pSDMA;
|
||||
|
||||
/* SDMA support maximum 0x3fffe0 byte in one copy. Use 2M copy_size */
|
||||
m_PacketSize = ((size + TWO_MEG - 1) >> 21) * sizeof(SDMA_PKT_CONSTANT_FILL);
|
||||
pSDMA = (SDMA_PKT_CONSTANT_FILL *)calloc(1, m_PacketSize);
|
||||
m_PacketData = pSDMA;
|
||||
|
||||
while (size > 0) {
|
||||
if (size > TWO_MEG)
|
||||
copy_size = TWO_MEG;
|
||||
else
|
||||
copy_size = size;
|
||||
|
||||
pSDMA->HEADER_UNION.op = SDMA_OP_CONST_FILL;
|
||||
pSDMA->HEADER_UNION.sub_op = 0;
|
||||
|
||||
/* If Both size and address are DW aligned, then use DW fill */
|
||||
if (!(copy_size & 0x3) && !((HSAuint64)dst & 0x3))
|
||||
pSDMA->HEADER_UNION.fillsize = 2; /* DW Fill */
|
||||
else
|
||||
pSDMA->HEADER_UNION.fillsize = 0; /* Byte Fill */
|
||||
|
||||
pSDMA->COUNT_UNION.count = SDMA_COUNT(copy_size);
|
||||
|
||||
SplitU64(reinterpret_cast<unsigned long long>(dst),
|
||||
pSDMA->DST_ADDR_LO_UNION.DW_1_DATA, /*dst_addr_31_0*/
|
||||
pSDMA->DST_ADDR_HI_UNION.DW_2_DATA); /*dst_addr_63_32*/
|
||||
|
||||
pSDMA->DATA_UNION.DW_3_DATA = data;
|
||||
pSDMA++;
|
||||
|
||||
dst = (char *)dst + copy_size;
|
||||
size -= copy_size;
|
||||
}
|
||||
}
|
||||
|
||||
SDMAFencePacket::SDMAFencePacket(void) {
|
||||
}
|
||||
|
||||
SDMAFencePacket::SDMAFencePacket(void* destAddr, unsigned int data) {
|
||||
InitPacket(destAddr, data);
|
||||
}
|
||||
|
||||
SDMAFencePacket::~SDMAFencePacket(void) {
|
||||
}
|
||||
|
||||
void SDMAFencePacket::InitPacket(void* destAddr, unsigned int data) {
|
||||
memset(&packetData, 0, SizeInBytes());
|
||||
|
||||
packetData.HEADER_UNION.op = SDMA_OP_FENCE;
|
||||
|
||||
SplitU64(reinterpret_cast<unsigned long long>(destAddr),
|
||||
packetData.ADDR_LO_UNION.DW_1_DATA, /*dst_addr_31_0*/
|
||||
packetData.ADDR_HI_UNION.DW_2_DATA); /*dst_addr_63_32*/
|
||||
|
||||
packetData.DATA_UNION.data = data;
|
||||
}
|
||||
|
||||
|
||||
SDMATrapPacket::SDMATrapPacket(unsigned int eventID) {
|
||||
InitPacket(eventID);
|
||||
}
|
||||
|
||||
SDMATrapPacket::~SDMATrapPacket(void) {
|
||||
}
|
||||
|
||||
void SDMATrapPacket::InitPacket(unsigned int eventID) {
|
||||
memset(&packetData, 0, SizeInBytes());
|
||||
|
||||
packetData.HEADER_UNION.op = SDMA_OP_TRAP;
|
||||
packetData.INT_CONTEXT_UNION.int_context = eventID;
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_SDMA_PACKET__H__
|
||||
#define __KFD_SDMA_PACKET__H__
|
||||
|
||||
#include "BasePacket.hpp"
|
||||
#include "sdma_pkt_struct.h"
|
||||
|
||||
// @class SDMSPacket: marks a group of all SDMA packets
|
||||
class SDMAPacket : public BasePacket {
|
||||
public:
|
||||
SDMAPacket(void) {}
|
||||
virtual ~SDMAPacket(void) {}
|
||||
|
||||
virtual PACKETTYPE PacketType() const { return PACKETTYPE_SDMA; }
|
||||
};
|
||||
|
||||
class SDMAWriteDataPacket : public SDMAPacket {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
SDMAWriteDataPacket(void);
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
SDMAWriteDataPacket(void* destAddr, unsigned int data);
|
||||
SDMAWriteDataPacket(void* destAddr, unsigned int ndw, void *data);
|
||||
|
||||
virtual ~SDMAWriteDataPacket(void);
|
||||
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return packetData; }
|
||||
// @breif initialise the packet
|
||||
void InitPacket(void* destAddr, unsigned int data);
|
||||
void InitPacket(void* destAddr, unsigned int ndw, void *data);
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return packetSize; }
|
||||
|
||||
protected:
|
||||
// SDMA_PKT_WRITE_UNTILED struct contains all the packets data
|
||||
SDMA_PKT_WRITE_UNTILED *packetData;
|
||||
unsigned int packetSize;
|
||||
};
|
||||
|
||||
class SDMACopyDataPacket : public SDMAPacket {
|
||||
public:
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
SDMACopyDataPacket(void *dest, void *src, unsigned int size);
|
||||
|
||||
virtual ~SDMACopyDataPacket(void);
|
||||
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return packetData; }
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return packetSize; }
|
||||
|
||||
protected:
|
||||
// SDMA_PKT_COPY_LINEAR struct contains all the packets data
|
||||
SDMA_PKT_COPY_LINEAR *packetData;
|
||||
|
||||
unsigned int packetSize;
|
||||
};
|
||||
|
||||
class SDMAFillDataPacket : public SDMAPacket {
|
||||
public:
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
SDMAFillDataPacket(void *dest, unsigned int data, unsigned int size);
|
||||
|
||||
virtual ~SDMAFillDataPacket(void);
|
||||
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return m_PacketData; }
|
||||
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return m_PacketSize; }
|
||||
|
||||
protected:
|
||||
// SDMA_PKT_CONSTANT_FILL struct contains all the packets data
|
||||
SDMA_PKT_CONSTANT_FILL *m_PacketData;
|
||||
|
||||
unsigned int m_PacketSize;
|
||||
};
|
||||
|
||||
class SDMAFencePacket : public SDMAPacket {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
SDMAFencePacket(void);
|
||||
// this contructor will also init the packet, no need for adittional calls
|
||||
SDMAFencePacket(void* destAddr, unsigned int data);
|
||||
|
||||
virtual ~SDMAFencePacket(void);
|
||||
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &packetData; }
|
||||
// @brief initialise the packet
|
||||
void InitPacket(void* destAddr, unsigned int data);
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return sizeof(SDMA_PKT_FENCE ); }
|
||||
|
||||
protected:
|
||||
// SDMA_PKT_FENCE struct contains all the packets data
|
||||
SDMA_PKT_FENCE packetData;
|
||||
};
|
||||
|
||||
class SDMATrapPacket : public SDMAPacket {
|
||||
public:
|
||||
// empty constructor, befor using the packet call the init func
|
||||
SDMATrapPacket(unsigned int eventID = 0);
|
||||
|
||||
virtual ~SDMATrapPacket(void);
|
||||
|
||||
// @returns a pointer to the packet
|
||||
virtual const void *GetPacket() const { return &packetData; }
|
||||
// @brief initialise the packet
|
||||
void InitPacket(unsigned int eventID);
|
||||
// @returns the packet size in bytes
|
||||
virtual unsigned int SizeInBytes() const { return sizeof(SDMA_PKT_TRAP); }
|
||||
|
||||
protected:
|
||||
// SDMA_PKT_TRAP struct contains all the packets data
|
||||
SDMA_PKT_TRAP packetData;
|
||||
};
|
||||
|
||||
#endif // __KFD_SDMA_PACKET__H__
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#include "SDMAQueue.hpp"
|
||||
|
||||
SDMAQueue::SDMAQueue(void) {
|
||||
CMD_NOP = 0;
|
||||
}
|
||||
|
||||
SDMAQueue::~SDMAQueue(void) {
|
||||
}
|
||||
|
||||
unsigned int SDMAQueue::Wptr() {
|
||||
/* In SDMA queues write pointers are saved in bytes, convert the
|
||||
* wptr value to DWORD to fit the way BaseQueue works. On Vega10
|
||||
* the write ptr is 64-bit. We only read the low 32 bit (assuming
|
||||
* the queue buffer is smaller than 4GB) and modulo divide by the
|
||||
* queue size to simulate a 32-bit read pointer. */
|
||||
return (*m_Resources.Queue_write_ptr % m_QueueBuf->Size()) /
|
||||
sizeof(unsigned int);
|
||||
}
|
||||
|
||||
unsigned int SDMAQueue::Rptr() {
|
||||
/* In SDMA queues read pointers are saved in bytes, convert the
|
||||
* read value to DWORD to fit the way BaseQueue works. On Vega10
|
||||
* the read ptr is 64-bit. We only read the low 32 bit (assuming
|
||||
* the queue buffer is smaller than 4GB) and modulo divide by the
|
||||
* queue size to simulate a 32-bit read pointer. */
|
||||
return (*m_Resources.Queue_read_ptr % m_QueueBuf->Size()) /
|
||||
sizeof(unsigned int);
|
||||
}
|
||||
|
||||
unsigned int SDMAQueue::RptrWhenConsumed() {
|
||||
/* Rptr is same size and byte units as Wptr. Here we only care
|
||||
* about the low 32-bits. When all packets are consumed, read and
|
||||
* write pointers should have the same value. */
|
||||
return *m_Resources.Queue_write_ptr;
|
||||
}
|
||||
|
||||
void SDMAQueue::SubmitPacket() {
|
||||
// m_pending Wptr is in DWORDs
|
||||
if (g_TestGPUFamilyId < FAMILY_AI) {
|
||||
// Pre-Vega10 uses 32-bit wptr and doorbell
|
||||
unsigned int wPtrInBytes = m_pendingWptr * sizeof(unsigned int);
|
||||
MemoryBarrier();
|
||||
*m_Resources.Queue_write_ptr = wPtrInBytes;
|
||||
MemoryBarrier();
|
||||
*(m_Resources.Queue_DoorBell) = wPtrInBytes;
|
||||
} else {
|
||||
// Vega10 and later uses 64-bit wptr and doorbell
|
||||
HSAuint64 wPtrInBytes = m_pendingWptr64 * sizeof(unsigned int);
|
||||
MemoryBarrier();
|
||||
*m_Resources.Queue_write_ptr_aql = wPtrInBytes;
|
||||
MemoryBarrier();
|
||||
*(m_Resources.Queue_DoorBell_aql) = wPtrInBytes;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* Copyright (C) 2014-2018 Advanced Micro Devices, Inc. All Rights Reserved.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef __KFD_SDMA_QUEUE__H__
|
||||
#define __KFD_SDMA_QUEUE__H__
|
||||
|
||||
#include "BaseQueue.hpp"
|
||||
|
||||
class SDMAQueue : public BaseQueue {
|
||||
public:
|
||||
SDMAQueue(void);
|
||||
virtual ~SDMAQueue(void);
|
||||
|
||||
// @brief update queue write pointer and sets the queue doorbell to the queue write pointer
|
||||
virtual void SubmitPacket();
|
||||
|
||||
protected:
|
||||
// @ return write pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Wptr();
|
||||
// @ return read pointer modulo queue size in DWORDs
|
||||
virtual unsigned int Rptr();
|
||||
// @ return expected m_Resources.Queue_read_ptr when all packets consumed
|
||||
virtual unsigned int RptrWhenConsumed();
|
||||
|
||||
virtual PACKETTYPE PacketTypeSupported() { return PACKETTYPE_SDMA; }
|
||||
|
||||
virtual _HSA_QUEUE_TYPE GetQueueType() { return HSA_QUEUE_SDMA; }
|
||||
};
|
||||
|
||||
#endif // __KFD_SDMA_QUEUE__H__
|
||||
Reference in New Issue
Block a user