Files
TheRock/rocm-libraries/projects/rpp/utilities/test_suite/common.py
T
derek.holloway 7502bf64a4
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
Flatten subprojects into a single base monorepo
2026-09-02 16:34:47 -07:00

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)