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:
Yong Zhao
2018-07-23 14:45:44 -04:00
parent 3719ec2557
commit 6df62c78b8
90 changed files with 70621 additions and 0 deletions
View File
+108
View File
@@ -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)
+85
View File
@@ -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
+76
View File
@@ -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
+107
View File
@@ -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 */
+160
View File
@@ -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__
+129
View File
@@ -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
+316
View File
@@ -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__
+142
View File
@@ -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"
+6
View File
@@ -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})
+57
View File
@@ -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
+590
View File
@@ -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__ */
+52
View File
@@ -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();
}
+50
View File
@@ -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
+37
View File
@@ -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;
}
+57
View File
@@ -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
+200
View File
@@ -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();
}
+134
View File
@@ -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
+221
View File
@@ -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());
}
+75
View File
@@ -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__
+79
View File
@@ -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;
}
+71
View File
@@ -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
+51
View File
@@ -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++;
}
+60
View File
@@ -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__
+118
View File
@@ -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);
}
+53
View File
@@ -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_
+123
View File
@@ -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;
}
+49
View File
@@ -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_
+128
View File
@@ -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;
}
+49
View File
@@ -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_
+113
View File
@@ -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;
}
+49
View File
@@ -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_
+117
View File
@@ -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__
+184
View File
@@ -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
}
+47
View File
@@ -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__
+176
View File
@@ -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
}
+45
View File
@@ -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__
+285
View File
@@ -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;
}
+44
View File
@@ -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__
+454
View File
@@ -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
}
+70
View File
@@ -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__
+355
View File
@@ -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
}
+65
View File
@@ -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__
+317
View File
@@ -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
}
+58
View File
@@ -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
+731
View File
@@ -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
}
+134
View File
@@ -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
+528
View File
@@ -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
}
+45
View File
@@ -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
+48
View File
@@ -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__
+88
View File
@@ -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
}
+43
View File
@@ -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__
+122
View File
@@ -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
+46
View File
@@ -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__
+99
View File
@@ -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
}
+47
View File
@@ -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__
+281
View File
@@ -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
}
+44
View File
@@ -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
+56
View File
@@ -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__
+65
View File
@@ -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__
+92
View File
@@ -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();
}
}
+536
View File
@@ -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;
}
+185
View File
@@ -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__
+220
View File
@@ -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
}
+40
View File
@@ -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__
+240
View File
@@ -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
+117
View File
@@ -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__
+302
View File
@@ -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);
}
+221
View File
@@ -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__
+71
View File
@@ -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;
}
}
+51
View File
@@ -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__
+118
View File
@@ -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
}
+45
View File
@@ -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__
+69
View File
@@ -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, &param);
}
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);
}
+37
View File
@@ -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__
+189
View File
@@ -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;
}
+143
View File
@@ -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__
+78
View File
@@ -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;
}
}
+50
View File
@@ -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__