CodeQL / Analyze (actions) (push) Canceled after 0s
CodeQL / Analyze (python) (push) Canceled after 0s
pre-commit / pre-commit (push) Canceled after 0s
Multi-Arch CI / setup (push) Canceled after 0s
Publish build_manylinux_x86_64 images / publish_build_manylinux_x86_64 (push) Canceled after 0s
Setup (Multi-Arch) / setup (push) Canceled after 0s
Multi-Arch CI / Linux::${{ fromJSON(needs.setup.outputs.linux_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubi10 image / publish_no_rocm_image_ubi10 (push) Canceled after 0s
Multi-Arch CI / Windows::${{ fromJSON(needs.setup.outputs.windows_build_config || '{}').build_variant_label || 'skip' }} (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Multi-Arch CI / Manifest Diff (push) Canceled after 0s
TheRock Manifest Diff Report / Generate Manifest Diff Report (push) Canceled after 0s
Multi-Arch CI / CI Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_ocl_rt images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04_rocgdb images / publish_no_rocm_image_ubuntu24_04_rocgdb (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_ocl_rt (push) Canceled after 0s
Publish TheRock Docker image / build-and-push-image (push) Canceled after 0s
Unit Tests / Unit Tests :: ubuntu-24.04 (push) Canceled after 0s
Unit Tests / Unit Tests :: windows-2022 (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_media (push) Canceled after 0s
Unit Tests / Unit Tests Summary (push) Canceled after 0s
Publish no_rocm_image_ubuntu24_04 images / publish_no_rocm_image_ubuntu24_04_openmpi (push) Canceled after 0s
872 lines
27 KiB
Python
872 lines
27 KiB
Python
"""
|
|
MIT License
|
|
|
|
Copyright (c) 2019 - 2025 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.
|
|
"""
|
|
|
|
import os
|
|
import subprocess # nosec
|
|
import argparse
|
|
import sys
|
|
import datetime
|
|
import shutil
|
|
import signal
|
|
from enum import Enum
|
|
|
|
try:
|
|
from errno import FileExistsError
|
|
except ImportError:
|
|
# Python 2 compatibility
|
|
FileExistsError = OSError
|
|
|
|
|
|
class TestType(Enum):
|
|
"""
|
|
Enum representing different test types.
|
|
"""
|
|
|
|
UNIT_TEST = 0
|
|
PERFORMANCE_TEST = 1
|
|
|
|
|
|
class BitDepthTestMode(Enum):
|
|
"""
|
|
Enum representing bit-depth conversion formats.
|
|
Convention:
|
|
- The first type = input data type
|
|
- The second type = output data type
|
|
"""
|
|
|
|
U8_TO_U8 = 0 # Input: U8 -> Output: U8
|
|
F16_TO_F16 = 1 # Input: F16 -> Output: F16
|
|
F32_TO_F32 = 2 # Input: F32 -> Output: F32
|
|
U8_TO_F16 = 3 # Input: U8 -> Output: F16
|
|
U8_TO_F32 = 4 # Input: U8 -> Output: F32
|
|
I8_TO_I8 = 5 # Input: I8 -> Output: I8
|
|
U8_TO_I8 = 6 # Input: U8 -> Output: I8
|
|
I16_TO_I16 = 7 # Input: I16 -> Output: I16
|
|
U16_TO_U16 = 8 # Input: U16 -> Output: U16
|
|
I32_TO_I32 = 9 # Input: I32 -> Output: I32
|
|
U32_TO_U32 = 10 # Input: U32 -> Output: U32
|
|
I8_TO_F32 = 11 # Input: I8 -> Output: F32
|
|
I16_TO_F32 = 12 # Input: I16 -> Output: F32
|
|
U16_TO_F32 = 13 # Input: U16 -> Output: F32
|
|
U32_TO_F32 = 14 # Input: U32 -> Output: F32
|
|
I32_TO_F32 = 15 # Input: I32 -> Output: F32
|
|
|
|
|
|
bitDepthDict = {
|
|
0: "_u8_",
|
|
1: "_f16_",
|
|
2: "_f32_",
|
|
3: "_u8_f16",
|
|
4: "_u8_f32_",
|
|
5: "_i8_",
|
|
6: "_u8_i8_",
|
|
7: "_i16_",
|
|
8: "_u16_",
|
|
9: "_i32_",
|
|
10: "_u32_",
|
|
11: "_i8_f32_",
|
|
12: "_i16_f32_",
|
|
13: "_u16_f32_",
|
|
14: "_u32_f32_",
|
|
15: "_i32_f32_",
|
|
}
|
|
|
|
|
|
class OutputFormat(Enum):
|
|
NON_TOGGLE = 0
|
|
TOGGLE = 1
|
|
|
|
|
|
class Layout(Enum):
|
|
PKD3 = 0
|
|
PLN3 = 1
|
|
PLN1 = 2
|
|
|
|
|
|
imageAugmentationMap = {
|
|
0: ["brightness", "HOST", "HIP"],
|
|
1: ["gamma_correction", "HOST", "HIP"],
|
|
2: ["blend", "HOST", "HIP"],
|
|
4: ["contrast", "HOST", "HIP"],
|
|
5: ["pixelate", "HOST", "HIP"],
|
|
6: ["jitter", "HOST", "HIP"],
|
|
7: ["snow", "HOST", "HIP"],
|
|
8: ["noise", "HOST", "HIP"],
|
|
10: ["fog", "HOST", "HIP"],
|
|
11: ["rain", "HOST", "HIP"],
|
|
13: ["exposure", "HOST", "HIP"],
|
|
15: ["threshold", "HOST", "HIP"],
|
|
20: ["flip", "HOST", "HIP"],
|
|
21: ["resize", "HOST", "HIP"],
|
|
23: ["rotate", "HOST", "HIP"],
|
|
24: ["warp_affine", "HOST", "HIP"],
|
|
25: ["fisheye", "HOST", "HIP"],
|
|
26: ["lens_correction", "HOST", "HIP"],
|
|
28: ["warp_perspective", "HOST", "HIP"],
|
|
29: ["water", "HOST", "HIP"],
|
|
30: ["non_linear_blend", "HOST", "HIP"],
|
|
31: ["color_cast", "HOST", "HIP"],
|
|
32: ["erase", "HOST", "HIP"],
|
|
33: ["crop_and_patch", "HOST", "HIP"],
|
|
34: ["lut", "HOST", "HIP"],
|
|
35: ["glitch", "HOST", "HIP"],
|
|
36: ["color_twist", "HOST", "HIP"],
|
|
37: ["crop", "HOST", "HIP"],
|
|
38: ["crop_mirror_normalize", "HOST", "HIP"],
|
|
39: ["resize_crop_mirror", "HOST", "HIP"],
|
|
40: ["erode", "HOST", "HIP"],
|
|
41: ["dilate", "HOST", "HIP"],
|
|
42: ["hue", "HOST", "HIP"],
|
|
43: ["saturation", "HOST", "HIP"],
|
|
45: ["color_temperature", "HOST", "HIP"],
|
|
46: ["vignette", "HOST", "HIP"],
|
|
49: ["box_filter", "HIP", "HOST"],
|
|
50: ["sobel_filter", "HOST", "HIP"],
|
|
51: ["median_filter", "HOST", "HIP"],
|
|
54: ["gaussian_filter", "HOST", "HIP"],
|
|
61: ["magnitude", "HOST", "HIP"],
|
|
63: ["phase", "HOST", "HIP"],
|
|
65: ["bitwise_and", "HOST", "HIP"],
|
|
66: ["bitwise_not", "HOST", "HIP"],
|
|
67: ["bitwise_xor", "HOST", "HIP"],
|
|
68: ["bitwise_or", "HOST", "HIP"],
|
|
70: ["copy", "HOST", "HIP"],
|
|
79: ["remap", "HOST", "HIP"],
|
|
80: ["resize_mirror_normalize", "HOST", "HIP"],
|
|
81: ["color_jitter", "HOST"],
|
|
82: ["ricap", "HOST", "HIP"],
|
|
83: ["gridmask", "HOST", "HIP"],
|
|
84: ["spatter", "HOST", "HIP"],
|
|
85: ["channel_permute", "HOST", "HIP"],
|
|
86: ["color_to_greyscale", "HOST", "HIP"],
|
|
87: ["tensor_sum", "HOST", "HIP"],
|
|
88: ["tensor_min", "HOST", "HIP"],
|
|
89: ["tensor_max", "HOST", "HIP"],
|
|
90: ["tensor_mean", "HOST", "HIP"],
|
|
91: ["tensor_stddev", "HOST", "HIP"],
|
|
92: ["slice", "HOST", "HIP"],
|
|
93: ["jpeg_compression_distortion", "HOST", "HIP"],
|
|
94: ["posterize", "HOST", "HIP"],
|
|
95: ["solarize", "HOST", "HIP"],
|
|
96: ["channel_dropout", "HOST", "HIP"],
|
|
97: ["cutout_dropout", "HOST", "HIP"],
|
|
98: ["grid_dropout", "HOST", "HIP"],
|
|
99: ["random_erase", "HOST", "HIP"],
|
|
100: ["coarse_dropout", "HOST", "HIP"],
|
|
101: ["emboss", "HOST", "HIP"],
|
|
102: ["histogram_equalize", "HOST", "HIP"],
|
|
103: ["yuv_to_rgb", "HIP"],
|
|
104: ["yuv_to_rgb_cubic_v", "HIP"],
|
|
105: ["yuv_to_rgb_linear_v", "HIP"],
|
|
}
|
|
|
|
audioAugmentationMap = {
|
|
0: ["non_silent_region_detection", "HOST", "HIP"],
|
|
1: ["to_decibels", "HOST", "HIP"],
|
|
2: ["pre_emphasis_filter", "HOST", "HIP"],
|
|
3: ["down_mixing", "HOST", "HIP"],
|
|
4: ["spectrogram", "HOST", "HIP"],
|
|
5: ["slice", "HOST", "HIP"],
|
|
6: ["resample", "HOST", "HIP"],
|
|
7: ["mel_filter_bank", "HOST", "HIP"],
|
|
8: ["audio_tensor_add_tensor", "HOST", "HIP"],
|
|
9: ["audio_tensor_mul_scalar", "HOST", "HIP"],
|
|
}
|
|
|
|
voxelAugmentationMap = {
|
|
0: ["fused_multiply_add_scalar", "HOST", "HIP"],
|
|
1: ["slice", "HOST", "HIP"],
|
|
2: ["add_scalar", "HOST", "HIP"],
|
|
3: ["subtract_scalar", "HOST", "HIP"],
|
|
4: ["flip_voxel", "HOST", "HIP"],
|
|
5: ["multiply_scalar", "HOST", "HIP"],
|
|
6: ["gaussian_noise_voxel", "HOST", "HIP"],
|
|
}
|
|
|
|
miscAugmentationMap = {
|
|
0: ["transpose", "HOST", "HIP"],
|
|
1: ["normalize", "HOST", "HIP"],
|
|
2: ["log", "HOST", "HIP"],
|
|
3: ["concat", "HOST", "HIP"],
|
|
4: ["log1p", "HOST", "HIP"],
|
|
5: ["tensor_and_tensor", "HOST", "HIP"],
|
|
6: ["tensor_or_tensor", "HOST", "HIP"],
|
|
7: ["tensor_xor_tensor", "HOST", "HIP"],
|
|
8: ["tensor_add_tensor", "HOST", "HIP"],
|
|
9: ["tensor_subtract_tensor", "HOST", "HIP"],
|
|
10: ["tensor_multiply_tensor", "HOST", "HIP"],
|
|
11: ["tensor_divide_tensor", "HOST", "HIP"],
|
|
}
|
|
|
|
# Supported test cases for single image processing
|
|
# Only these cases are implemented in Tensor_single_image_hip.cpp and Tensor_single_image_host.cpp
|
|
SINGLE_IMAGE_SUPPORTED_CASES = {
|
|
0,
|
|
2,
|
|
20,
|
|
21,
|
|
37,
|
|
49,
|
|
51,
|
|
54,
|
|
} # brightness, blend, flip, resize, crop, box_filter, median_filter, gaussian_filter
|
|
|
|
# Only homogeneous bit-depth modes are supported by the single-image API wrappers.
|
|
# Used as an allowlist: any mode not in this set is skipped by the Python runner.
|
|
SINGLE_IMAGE_SUPPORTED_BIT_DEPTHS = {
|
|
BitDepthTestMode.U8_TO_U8,
|
|
BitDepthTestMode.F16_TO_F16,
|
|
BitDepthTestMode.F32_TO_F32,
|
|
BitDepthTestMode.I8_TO_I8,
|
|
}
|
|
|
|
ImageAugmentationGroupMap = {
|
|
"color_augmentations": [
|
|
"brightness",
|
|
"gamma_correction",
|
|
"blend",
|
|
"contrast",
|
|
"exposure",
|
|
"color_cast",
|
|
"lut",
|
|
"color_twist",
|
|
"hue",
|
|
"saturation",
|
|
"color_temperature",
|
|
"color_jitter",
|
|
"histogram_equalize",
|
|
],
|
|
"effects_augmentations": [
|
|
"pixelate",
|
|
"jitter",
|
|
"noise",
|
|
"fog",
|
|
"rain",
|
|
"water",
|
|
"non_linear_blend",
|
|
"erase",
|
|
"glitch",
|
|
"vignette",
|
|
"ricap",
|
|
"gridmask",
|
|
"spatter",
|
|
"posterize",
|
|
"snow",
|
|
"coarse_dropout",
|
|
],
|
|
"geometric_augmentations": [
|
|
"flip",
|
|
"resize",
|
|
"rotate",
|
|
"warp_affine",
|
|
"lens_correction",
|
|
"warp_perspective",
|
|
"crop_and_patch",
|
|
"crop",
|
|
"crop_mirror_normalize",
|
|
"resize_crop_mirror",
|
|
"phase",
|
|
"remap",
|
|
"resize_mirror_normalize",
|
|
"slice",
|
|
"jpeg_compression_distortion",
|
|
"fisheye",
|
|
],
|
|
"filter_augmentations": [
|
|
"box_filter",
|
|
"median_filter",
|
|
"gaussian_filter",
|
|
"sobel_filter",
|
|
"emboss",
|
|
],
|
|
"morphological_operations": ["erode", "dilate"],
|
|
"arithmetic_operations": ["magnitude"],
|
|
"logical_operations": ["bitwise_and", "bitwise_not", "bitwise_xor", "bitwise_or"],
|
|
"data_exchange_operations": [
|
|
"copy",
|
|
"channel_permute",
|
|
"color_to_greyscale",
|
|
"yuv_to_rgb",
|
|
],
|
|
"statistical_operations": [
|
|
"threshold",
|
|
"tensor_sum",
|
|
"tensor_min",
|
|
"tensor_max",
|
|
"tensor_mean",
|
|
"tensor_stddev",
|
|
],
|
|
}
|
|
|
|
voxelAugmentationGroupMap = {
|
|
"arithmetic_operations": [
|
|
"fused_multiply_add_scalar",
|
|
"add_scalar",
|
|
"subtract_scalar",
|
|
"multiply_scalar",
|
|
],
|
|
"effects_augmentations": ["gaussian_noise_voxel"],
|
|
"geometric_augmentations": ["slice", "flip_voxel"],
|
|
}
|
|
|
|
|
|
def run_cmake_build(script_path):
|
|
"""Configure and build using Ninja generator with parallel jobs matching CPU count."""
|
|
subprocess.check_call(["cmake", "-GNinja", script_path]) # nosec
|
|
subprocess.check_call(
|
|
["cmake", "--build", ".", "--parallel", str(os.cpu_count())]
|
|
) # nosec
|
|
|
|
|
|
def get_case_number(map, case):
|
|
# Check if the input is numeric (case number)
|
|
if case.isdigit():
|
|
return str(case)
|
|
|
|
# Otherwise, treat it as a case name and find the corresponding number
|
|
for caseNum, info in map.items():
|
|
if case.lower() == info[0].lower():
|
|
return str(caseNum)
|
|
raise ValueError(f"Invalid case name or number: {case}")
|
|
|
|
|
|
StatusMap = {
|
|
0: "RPP_SUCCESS",
|
|
-1: "RPP_ERROR",
|
|
-2: "RPP_ERROR_INVALID_ARGUMENTS",
|
|
-3: "RPP_ERROR_LOW_OFFSET",
|
|
-4: "RPP_ERROR_ZERO_DIVISION",
|
|
-5: "RPP_ERROR_HIGH_SRC_DIMENSION",
|
|
-6: "RPP_ERROR_NOT_IMPLEMENTED",
|
|
-7: "RPP_ERROR_INVALID_SRC_CHANNELS",
|
|
-8: "RPP_ERROR_INVALID_DST_CHANNELS",
|
|
-9: "RPP_ERROR_INVALID_SRC_LAYOUT",
|
|
-10: "RPP_ERROR_INVALID_DST_LAYOUT",
|
|
-11: "RPP_ERROR_INVALID_SRC_DATATYPE",
|
|
-12: "RPP_ERROR_INVALID_DST_DATATYPE",
|
|
-13: "RPP_ERROR_INVALID_SRC_OR_DST_DATATYPE",
|
|
-14: "RPP_ERROR_INSUFFICIENT_DST_BUFFER_LENGTH",
|
|
-15: "RPP_ERROR_INVALID_PARAMETER_DATATYPE",
|
|
-16: "RPP_ERROR_NOT_ENOUGH_MEMORY",
|
|
-17: "RPP_ERROR_OUT_OF_BOUND_SRC_ROI",
|
|
-18: "RPP_ERROR_LAYOUT_MISMATCH",
|
|
-19: "RPP_ERROR_INVALID_CHANNELS",
|
|
-20: "RPP_ERROR_INVALID_OUTPUT_TILE_LENGTH",
|
|
-21: "RPP_ERROR_OUT_OF_BOUND_SHARED_MEMORY_SIZE",
|
|
-22: "RPP_ERROR_OUT_OF_BOUND_SCRATCH_MEMORY_SIZE",
|
|
-23: "RPP_ERROR_INVALID_SRC_DIMS",
|
|
-24: "RPP_ERROR_INVALID_DST_DIMS",
|
|
}
|
|
|
|
|
|
# Checks if the folder path is empty, or is it a root folder, or if it exists, and remove its contents
|
|
def validate_and_remove_files(path):
|
|
if not path: # check if a string is empty
|
|
print("Folder path is empty.")
|
|
exit()
|
|
|
|
elif path == "/*": # check if the root directory is passed to the function
|
|
print("Root folder cannot be deleted.")
|
|
exit()
|
|
|
|
elif os.path.exists(path): # check if the folder exists
|
|
# Get a list of files and directories within the specified path
|
|
items = os.listdir(path)
|
|
|
|
if items:
|
|
# The directory is not empty, delete its contents
|
|
for item in items:
|
|
item_path = os.path.join(path, item)
|
|
if os.path.isfile(item_path):
|
|
os.remove(item_path)
|
|
elif os.path.isdir(item_path):
|
|
shutil.rmtree(item_path) # Delete the directory if it exists
|
|
|
|
else:
|
|
print("Path is invalid or does not exist.")
|
|
exit()
|
|
|
|
|
|
# Check if the folder is the root folder or exists, and remove the specified subfolders
|
|
def validate_and_remove_folders(path, folder):
|
|
if path == "/*": # check if the root directory is passed to the function
|
|
print("Root folder cannot be deleted.")
|
|
exit()
|
|
if path and os.path.isdir(
|
|
path
|
|
): # checks if directory string is not empty and it exists
|
|
output_folders = [
|
|
folder_name
|
|
for folder_name in os.listdir(path)
|
|
if folder_name.startswith(folder)
|
|
]
|
|
|
|
# Loop through each directory and delete it only if it exists
|
|
for folder_name in output_folders:
|
|
folder_path = os.path.join(path, folder_name)
|
|
if os.path.isdir(folder_path):
|
|
shutil.rmtree(folder_path) # Delete the directory if it exists
|
|
print("Deleted directory:", folder_path)
|
|
else:
|
|
print("Directory not found:", folder_path)
|
|
|
|
|
|
# Check if a case file exists and filter its contents based on certain conditions
|
|
def case_file_check(CASE_FILE_PATH, TYPE, TENSOR_TYPE_LIST, new_file, d_counter):
|
|
try:
|
|
case_file = open(CASE_FILE_PATH, "r")
|
|
for line in case_file:
|
|
print(line)
|
|
if not (line.startswith('"Name"')):
|
|
if TYPE in TENSOR_TYPE_LIST:
|
|
new_file.write(line)
|
|
d_counter[TYPE] = d_counter[TYPE] + 1
|
|
case_file.close()
|
|
return True
|
|
except IOError:
|
|
print("Unable to open case results")
|
|
return False
|
|
|
|
|
|
# Generate a directory name based on certain parameters
|
|
def directory_name_generator(
|
|
qaMode, affinity, layoutType, case, path, groupMap, func_group_finder, augMap
|
|
):
|
|
if qaMode == 0:
|
|
functionality_group = func_group_finder(groupMap, int(case), augMap)
|
|
dst_folder_temp = (
|
|
path + "/rpp_" + affinity + "_" + layoutType + "_" + functionality_group
|
|
)
|
|
else:
|
|
dst_folder_temp = path
|
|
|
|
return dst_folder_temp
|
|
|
|
|
|
# Process the layout based on the given parameters and generate the directory name and log file layout.
|
|
def process_layout(
|
|
layout, qaMode, case, dstPath, backend, groupMap, func_group_finder, augMap
|
|
):
|
|
if layout == Layout.PKD3:
|
|
dstPathTemp = directory_name_generator(
|
|
qaMode, backend, "pkd3", case, dstPath, groupMap, func_group_finder, augMap
|
|
)
|
|
log_file_layout = "pkd3"
|
|
elif layout == Layout.PLN3:
|
|
dstPathTemp = directory_name_generator(
|
|
qaMode, backend, "pln3", case, dstPath, groupMap, func_group_finder, augMap
|
|
)
|
|
log_file_layout = "pln3"
|
|
elif layout == Layout.PLN1:
|
|
dstPathTemp = directory_name_generator(
|
|
qaMode, backend, "pln1", case, dstPath, groupMap, func_group_finder, augMap
|
|
)
|
|
log_file_layout = "pln1"
|
|
|
|
return dstPathTemp, log_file_layout
|
|
|
|
|
|
# Validate if a path exists and is a directory
|
|
def validate_path(input_path):
|
|
if not os.path.exists(input_path):
|
|
raise ValueError("path " + input_path + " does not exist.")
|
|
if not os.path.isdir(input_path):
|
|
raise ValueError("path " + input_path + " is not a directory.")
|
|
|
|
|
|
# Create layout directories within a destination path based on a layout dictionary
|
|
def create_layout_directories(dst_path):
|
|
for layout in Layout: # iterate over enum members
|
|
current_layout = layout.name # get the string name like "PKD3"
|
|
try:
|
|
os.makedirs(dst_path + "/" + current_layout)
|
|
except FileExistsError:
|
|
pass
|
|
folder_list = [f for f in os.listdir(dst_path) if current_layout.lower() in f]
|
|
for folder in folder_list:
|
|
os.rename(
|
|
dst_path + "/" + folder, dst_path + "/" + current_layout + "/" + folder
|
|
)
|
|
|
|
|
|
# Read data from the logs generated from rocprof, process the data
|
|
# and generate performance reports based on counters and a list of types
|
|
def generate_performance_reports(d_counter, TYPE_LIST, RESULTS_DIR):
|
|
import pandas as pd
|
|
|
|
pd.options.display.max_rows = None
|
|
# Generate performance report
|
|
for TYPE in TYPE_LIST:
|
|
print("\n\n\nKernels tested - ", d_counter[TYPE], "\n\n")
|
|
df = pd.read_csv(RESULTS_DIR + "/consolidated_results_" + TYPE + ".stats.csv")
|
|
df["AverageMs"] = df["AverageNs"] / 1000000
|
|
dfPrint = df.drop(["Percentage"], axis=1)
|
|
dfPrint["HIP Kernel Name"] = dfPrint.iloc[:, 0].str.lstrip("Hip_")
|
|
dfPrint_noIndices = dfPrint.astype(str)
|
|
dfPrint_noIndices.replace(["0", "0.0"], "", inplace=True)
|
|
dfPrint_noIndices = dfPrint_noIndices.to_string(index=False)
|
|
print(dfPrint_noIndices)
|
|
|
|
|
|
# Read the data from QA logs, process the data and print the results as a summary
|
|
def print_qa_tests_summary(qaFilePath, supportedCaseList, nonQACaseList, fileName):
|
|
numLines = 0
|
|
numPassed = 0
|
|
resultsInfo = ""
|
|
with open(qaFilePath, "r+") as f:
|
|
for line in f:
|
|
sys.stdout.write(line)
|
|
sys.stdout.flush()
|
|
if not line.strip():
|
|
continue
|
|
# Count only verdict lines so blank lines / stray text do not skew totals
|
|
if "PASSED" not in line and "FAILED" not in line:
|
|
continue
|
|
numLines += 1
|
|
if "PASSED" in line:
|
|
numPassed += 1
|
|
resultsInfo = "\n\nFinal Results of Tests:"
|
|
resultsInfo += (
|
|
"\n - Total test cases including all subvariants REQUESTED = "
|
|
+ str(numLines)
|
|
)
|
|
resultsInfo += (
|
|
"\n - Total test cases including all subvariants PASSED = "
|
|
+ str(numPassed)
|
|
)
|
|
resultsInfo += (
|
|
"\n\nGeneral information on " + fileName + " test suite availability:"
|
|
)
|
|
resultsInfo += (
|
|
"\n - Total augmentations supported in Tensor test suite = "
|
|
+ str(len(supportedCaseList))
|
|
)
|
|
resultsInfo += (
|
|
"\n - Total augmentations with golden output QA test support = "
|
|
+ str(len(supportedCaseList) - len(nonQACaseList))
|
|
)
|
|
resultsInfo += (
|
|
"\n - Total augmentations without golden output QA test support (due to randomization involved) = "
|
|
+ str(len(nonQACaseList))
|
|
)
|
|
f.write(resultsInfo)
|
|
print(
|
|
"\n---------------------------------- Summary of QA Test - "
|
|
+ fileName
|
|
+ " ----------------------------------"
|
|
+ resultsInfo
|
|
+ "\n\n-------------------------------------------------------------------"
|
|
)
|
|
if numPassed != numLines:
|
|
print(
|
|
"ERROR: QA failures: "
|
|
+ str(numLines - numPassed)
|
|
+ " of "
|
|
+ str(numLines)
|
|
+ " test verdict(s) did not pass (see "
|
|
+ qaFilePath
|
|
+ ").",
|
|
file=sys.stderr,
|
|
)
|
|
sys.exit(1)
|
|
|
|
|
|
# Read the data from performance logs, process the data and print the results as a summary
|
|
def print_performance_tests_summary(logFile, functionalityGroupList, numRuns):
|
|
try:
|
|
f = open(logFile, "r")
|
|
print("\nOpened log file -> " + logFile)
|
|
except IOError:
|
|
print("Skipping file -> " + logFile)
|
|
return
|
|
|
|
stats = []
|
|
maxVals = []
|
|
minVals = []
|
|
avgVals = []
|
|
functions = []
|
|
frames = []
|
|
prevLine = ""
|
|
funcCount = 0
|
|
|
|
# Loop over each line
|
|
for line in f:
|
|
for functionalityGroup in functionalityGroupList:
|
|
if functionalityGroup in line:
|
|
functions.extend([" ", functionalityGroup, " "])
|
|
frames.extend([" ", " ", " "])
|
|
maxVals.extend([" ", " ", " "])
|
|
minVals.extend([" ", " ", " "])
|
|
avgVals.extend([" ", " ", " "])
|
|
|
|
if "max,min,avg wall times in ms/batch" in line:
|
|
splitWordStart = "Running "
|
|
splitWordEnd = " " + str(numRuns)
|
|
prevLine = prevLine.partition(splitWordStart)[2].partition(splitWordEnd)[0]
|
|
if prevLine not in functions:
|
|
functions.append(prevLine)
|
|
frames.append(numRuns)
|
|
splitWordStart = "max,min,avg wall times in ms/batch = "
|
|
splitWordEnd = "\n"
|
|
stats = (
|
|
line.partition(splitWordStart)[2]
|
|
.partition(splitWordEnd)[0]
|
|
.split(",")
|
|
)
|
|
maxVals.append(stats[0])
|
|
minVals.append(stats[1])
|
|
avgVals.append(stats[2])
|
|
funcCount += 1
|
|
|
|
if line != "\n":
|
|
prevLine = line
|
|
|
|
# Print log lengths
|
|
print("Functionalities - " + str(funcCount))
|
|
|
|
# Print summary of log
|
|
headerFormat = "{:<70} {:<15} {:<15} {:<15} {:<15}"
|
|
rowFormat = "{:<70} {:<15} {:<15} {:<15} {:<15}"
|
|
print(
|
|
"\n"
|
|
+ headerFormat.format(
|
|
"Functionality",
|
|
"Frames Count",
|
|
"max(ms/batch)",
|
|
"min(ms/batch)",
|
|
"avg(ms/batch)",
|
|
)
|
|
+ "\n"
|
|
)
|
|
if len(functions) != 0:
|
|
for i, func in enumerate(functions):
|
|
print(
|
|
rowFormat.format(
|
|
func,
|
|
str(frames[i]),
|
|
str(maxVals[i]),
|
|
str(minVals[i]),
|
|
str(avgVals[i]),
|
|
)
|
|
)
|
|
else:
|
|
print("No variants under this category")
|
|
|
|
# Closing log file
|
|
f.close()
|
|
|
|
|
|
# Read the standard output from subprocess and writes to log file
|
|
def read_from_subprocess_and_write_to_log(process, logFile):
|
|
while True:
|
|
output = process.stdout.readline()
|
|
if not output and process.poll() is not None:
|
|
break
|
|
output = output.decode(
|
|
"utf-8", errors="replace"
|
|
).strip() # Decode bytes to string and strip extra whitespace
|
|
if output:
|
|
print(output)
|
|
logFile.write(output + "\n")
|
|
|
|
|
|
# Returns the layout name based on layout value
|
|
def get_layout_name(layout):
|
|
if layout == Layout.PKD3:
|
|
return "PKD3"
|
|
elif layout == Layout.PLN3:
|
|
return "PLN3"
|
|
elif layout == Layout.PLN1:
|
|
return "PLN1"
|
|
|
|
|
|
# Prints entire case list if user asks for help
|
|
def print_case_list(imageAugmentationMap, backendType, parser):
|
|
if "--help" in sys.argv or "-h" in sys.argv:
|
|
parser.print_help()
|
|
print("\n" + "=" * 30)
|
|
print("Functionality Reference List")
|
|
print("=" * 30 + "\n")
|
|
headerFormat = "{:<12} {:<15}"
|
|
print(headerFormat.format("CaseNumber", "Functionality"))
|
|
print("-" * 27)
|
|
rowFormat = "{:<12} {:<15}"
|
|
for key, value_list in imageAugmentationMap.items():
|
|
if backendType in value_list:
|
|
print(rowFormat.format(key, value_list[0]))
|
|
|
|
sys.exit(0)
|
|
|
|
|
|
def func_group_finder(groupMap, case_number, augMap):
|
|
# get augmentation name for the given case number
|
|
if case_number not in augMap:
|
|
return "miscellaneous"
|
|
aug_name = augMap[case_number][0] # first element is the name
|
|
|
|
# check which group contains this name
|
|
for key, value in groupMap.items():
|
|
if aug_name in value:
|
|
return key
|
|
return "miscellaneous"
|
|
|
|
|
|
def dataframe_to_markdown(df):
|
|
# Calculate the maximum width of each column
|
|
column_widths = {}
|
|
for col in df.columns:
|
|
max_length = len(col)
|
|
for value in df[col]:
|
|
max_length = max(max_length, len(str(value)))
|
|
column_widths[col] = max_length
|
|
|
|
# Create the header row
|
|
md = (
|
|
"| "
|
|
+ " | ".join([col.ljust(column_widths[col]) for col in df.columns])
|
|
+ " |\n"
|
|
)
|
|
md += "| " + " | ".join(["-" * column_widths[col] for col in df.columns]) + " |\n"
|
|
|
|
# Create the data rows
|
|
for i, row in df.iterrows():
|
|
md += (
|
|
"| "
|
|
+ " | ".join(
|
|
[
|
|
str(value).ljust(column_widths[df.columns[j]])
|
|
for j, value in enumerate(row.values)
|
|
]
|
|
)
|
|
+ " |\n"
|
|
)
|
|
|
|
return md
|
|
|
|
|
|
def get_image_layout_type(layout, outputFormatToggle, backend):
|
|
result = "Tensor_" + backend
|
|
if layout == Layout.PKD3:
|
|
result += "_PKD3"
|
|
if outputFormatToggle:
|
|
result += "_toPLN3"
|
|
else:
|
|
result += "_toPKD3"
|
|
elif layout == Layout.PLN3:
|
|
result += "_PLN3"
|
|
if outputFormatToggle:
|
|
result += "_toPKD3"
|
|
else:
|
|
result += "_toPLN3"
|
|
else:
|
|
result += "_PLN1"
|
|
result += "_toPLN1"
|
|
return result
|
|
|
|
|
|
def get_misc_func_name(testCase, nDim, additionalArg):
|
|
axisMaskCase = 0
|
|
permOrderCase = 0
|
|
if testCase == 1:
|
|
axisMaskCase = 1
|
|
elif testCase == 0:
|
|
permOrderCase = 1
|
|
additionalParam = 1
|
|
if axisMaskCase or permOrderCase:
|
|
additionalParam = additionalArg
|
|
axisMask = additionalParam
|
|
permOrder = additionalParam
|
|
result = ""
|
|
if axisMaskCase:
|
|
result = result + str(nDim) + "d" + "_axisMask" + str(axisMask)
|
|
if permOrderCase:
|
|
result = result + str(nDim) + "d" + "_permOrder" + str(permOrder)
|
|
return result
|
|
|
|
|
|
def get_voxel_layout_type(layout, backend):
|
|
result = "Tensor_" + backend
|
|
if layout == Layout.PKD3:
|
|
result += "_PKD3_toPKD3"
|
|
elif layout == Layout.PLN3:
|
|
result += "_PLN3_toPLN3"
|
|
else:
|
|
result += "_PLN1_toPLN1"
|
|
return result
|
|
|
|
|
|
def get_bit_depth(BitDepthTestMode):
|
|
result = str(bitDepthDict[BitDepthTestMode])
|
|
return result
|
|
|
|
|
|
def get_signal_name_from_return_code(returnCode):
|
|
result = ""
|
|
if returnCode < 0:
|
|
signalNum = -returnCode
|
|
result = result + " ( "
|
|
for signame, signum in signal.__dict__.items():
|
|
if isinstance(signum, int) and signum == signalNum:
|
|
signalName = signame
|
|
break
|
|
result = result + signalName + " ) "
|
|
elif returnCode > 127:
|
|
signalNum = returnCode - 256
|
|
if signalNum in StatusMap.keys():
|
|
result = result + " ( " + StatusMap[signalNum] + " ) "
|
|
return result
|
|
|
|
|
|
def log_detected(result, errorLog, caseName, functionBitDepth, functionSpecificName):
|
|
stdoutData, stderrData = result.communicate()
|
|
print(stdoutData.decode())
|
|
exitCode = result.returncode
|
|
if exitCode != 0:
|
|
if exitCode == 250:
|
|
errorLog[0]["notExecutedFunctionality"] += 1
|
|
else:
|
|
if exitCode > 127:
|
|
errorData = (
|
|
"Returned non-zero exit status : "
|
|
+ str(exitCode - 256)
|
|
+ " "
|
|
+ stderrData.decode()
|
|
)
|
|
else:
|
|
errorData = (
|
|
"Returned non-zero exit status : "
|
|
+ str(exitCode)
|
|
+ " "
|
|
+ stderrData.decode()
|
|
)
|
|
msg = (
|
|
caseName
|
|
+ functionBitDepth
|
|
+ functionSpecificName
|
|
+ " - "
|
|
+ errorData
|
|
+ get_signal_name_from_return_code(exitCode)
|
|
)
|
|
errorLog.append(msg)
|