Improve block filtering to accept metric ids (#821)
* Fix tests
* Update CHANGELOG and documentation
[ROCm/rocprofiler-compute commit: a70ae40ddc]
Tento commit je obsažen v:
@@ -81,6 +81,8 @@ Full documentation for ROCm Compute Profiler is available at [https://rocm.docs.
|
||||
* Update Roofline binaries
|
||||
* Rebuild using latest ROCm stack
|
||||
* OS distribution support minimum for roofline feature is now Ubuntu22.04, RHEL9, and SLES15SP6
|
||||
* Improve analysis block based filtering to accept metric id level filtering
|
||||
* This can be used to collect individual metrics from various sections of analysis config
|
||||
|
||||
### Optimized
|
||||
|
||||
|
||||
@@ -294,6 +294,36 @@ for ``Compute Unit - Instruction Mix`` (block 10) and ``Wavefront Launch Statist
|
||||
...
|
||||
|
||||
|
||||
It is also possible to collect individual metrics from the analysis report by providing metric ids.
|
||||
The following example only collects the counters required to calculate ``Total VALU FLOPs`` (metric id 11.1.0) and ``LDS Utilization`` (metric id 12.1.0).
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
$ rocprof-compute profile --name vcopy -b 11.1.1 12.1.1 -- ./vcopy -n 1048576 -b 256
|
||||
|
||||
__ _
|
||||
_ __ ___ ___ _ __ _ __ ___ / _| ___ ___ _ __ ___ _ __ _ _| |_ ___
|
||||
| '__/ _ \ / __| '_ \| '__/ _ \| |_ _____ / __/ _ \| '_ ` _ \| '_ \| | | | __/ _ \
|
||||
| | | (_) | (__| |_) | | | (_) | _|_____| (_| (_) | | | | | | |_) | |_| | || __/
|
||||
|_| \___/ \___| .__/|_| \___/|_| \___\___/|_| |_| |_| .__/ \__,_|\__\___|
|
||||
|_| |_|
|
||||
|
||||
rocprofiler-compute version: 2.0.0
|
||||
Profiler choice: rocprofv1
|
||||
Path: /home/auser/repos/rocprofiler-compute/sample/workloads/vcopy/MI200
|
||||
Target: MI200
|
||||
Command: ./vcopy -n 1048576 -b 256
|
||||
Kernel Selection: None
|
||||
Dispatch Selection: None
|
||||
Hardware Blocks: []
|
||||
Report Sections: ['11.1.0', '12.1.0']
|
||||
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
Collecting Performance Counters
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
...
|
||||
|
||||
|
||||
To see a list of available hardware report blocks, use the ``--list-metrics`` option.
|
||||
|
||||
.. code-block:: shell-session
|
||||
|
||||
@@ -179,9 +179,8 @@ Examples:
|
||||
)
|
||||
|
||||
def validate_block(value):
|
||||
# Metric id regex, for example, 10, 4, 4.3, 4.32
|
||||
# Dont allow more than two digits after decimal point
|
||||
metric_id_pattern = re.compile(r"^\d+$|^\d+\.\d$|^\d+\.\d\d$")
|
||||
# Metric id is of the form I or I.I or I.I.I where I is two digit number.
|
||||
metric_id_pattern = re.compile(r"^\d{1,2}(?:\.\d{1,2}){0,2}$")
|
||||
if metric_id_pattern.match(value):
|
||||
return value
|
||||
raise argparse.ArgumentTypeError(f"Invalid metric id: {value}")
|
||||
@@ -195,7 +194,7 @@ Examples:
|
||||
nargs="+",
|
||||
required=False,
|
||||
default=[],
|
||||
help="""\t\t\tSpecify metric id(s) from --list-metrics for filtering (e.g. 10, 4, 4.3).\n\t\t\tCan provide multiple space separated arguments.""",
|
||||
help="""\t\t\tSpecify metric id(s) from --list-metrics for filtering (e.g. 12, 12.1, 12.1.1).\n\t\t\tCan provide multiple space separated arguments.""",
|
||||
)
|
||||
profile_group.add_argument(
|
||||
"--list-metrics",
|
||||
|
||||
@@ -50,7 +50,7 @@ from utils.parser import build_in_vars, supported_denom
|
||||
from utils.utils import (
|
||||
add_counter_extra_config_input_yaml,
|
||||
capture_subprocess_output,
|
||||
convert_metric_id_to_panel_idx,
|
||||
convert_metric_id_to_panel_info,
|
||||
detect_rocprof,
|
||||
get_submodules,
|
||||
is_tcc_channel_counter,
|
||||
@@ -261,66 +261,73 @@ class OmniSoC_Base:
|
||||
Create a set of counters required for the selected report sections.
|
||||
Parse analysis report configuration files based on the selected report sections to be filtered.
|
||||
"""
|
||||
counters = set()
|
||||
config_filenames = {
|
||||
filename: []
|
||||
for filename in os.listdir(
|
||||
Path(self.get_args().config_dir).joinpath(self.__arch)
|
||||
)
|
||||
if filename.endswith(".yaml")
|
||||
# Read the analysis config files and filter
|
||||
config_root_dir = f"{self.get_args().config_dir}/{self.__arch}"
|
||||
# File id dict
|
||||
config_filename_dict = {
|
||||
Path(filename).name.split("_")[0]: filename
|
||||
for filename in glob.glob(f"{config_root_dir}/*.yaml")
|
||||
}
|
||||
file_ids = []
|
||||
for section in self.get_args().filter_blocks:
|
||||
section_num = convert_metric_id_to_panel_idx(section)
|
||||
file_id = str(section_num // 100)
|
||||
# Convert "4" to "04"
|
||||
if len(file_id) == 1:
|
||||
file_id = f"0{file_id}"
|
||||
file_ids.append(file_id)
|
||||
# Apply sub section filtering
|
||||
for config_filename in config_filenames:
|
||||
# If first two characters of the config filename match the file_id
|
||||
if config_filename[:2].startswith(file_id) and section_num % 100:
|
||||
config_filenames[config_filename].append(section_num)
|
||||
texts = list()
|
||||
|
||||
# Apply section filters only if metric ids have been provided for filtering
|
||||
if self.get_args().filter_blocks:
|
||||
# Identify yaml files corresponding to file_ids
|
||||
config_filenames = {
|
||||
filename: subsections
|
||||
for filename, subsections in config_filenames.items()
|
||||
if filename[:2].startswith(tuple(file_ids))
|
||||
}
|
||||
if not self.get_args().filter_blocks:
|
||||
# Read all config files if no filter_blocks are specified
|
||||
for filename in config_filename_dict.values():
|
||||
with open(filename, "r") as stream:
|
||||
texts.append(stream.read())
|
||||
|
||||
for config_filename, subsections in config_filenames.items():
|
||||
# Read the yaml file
|
||||
with open(
|
||||
Path(self.get_args().config_dir).joinpath(self.__arch, config_filename),
|
||||
"r",
|
||||
) as stream:
|
||||
section_config = yaml.safe_load(stream)
|
||||
# Extract subsection if section is of the form 4.52
|
||||
if subsections:
|
||||
section_config_text = "\n".join(
|
||||
[
|
||||
# Convert yaml to string
|
||||
yaml.dump(subsection, sort_keys=False)
|
||||
for subsection in section_config["Panel Config"]["data source"]
|
||||
if subsection["metric_table"]["id"] in subsections
|
||||
]
|
||||
for block_id in self.get_args().filter_blocks:
|
||||
file_id, panel_id, metric_id = convert_metric_id_to_panel_info(block_id)
|
||||
|
||||
# File id filtering
|
||||
if file_id not in config_filename_dict:
|
||||
console_warning(
|
||||
f"Skipping {block_id}: file id {file_id} not found in {config_root_dir}"
|
||||
)
|
||||
else:
|
||||
# Convert yaml to string
|
||||
section_config_text = yaml.dump(section_config, sort_keys=False)
|
||||
counters = counters.union(self.parse_counters(section_config_text))
|
||||
continue
|
||||
with open(config_filename_dict[file_id], "r") as stream:
|
||||
file_config = yaml.safe_load(stream)
|
||||
if panel_id is None:
|
||||
# If no panel id level filtering, then read the whole file
|
||||
texts.append(yaml.dump(file_config, sort_keys=False))
|
||||
continue
|
||||
|
||||
# Panel id filtering
|
||||
panel_dict = {
|
||||
section["metric_table"]["id"]: section["metric_table"]
|
||||
for section in file_config["Panel Config"]["data source"]
|
||||
if "metric_table" in section
|
||||
}
|
||||
if panel_id not in panel_dict:
|
||||
console_warning(
|
||||
f"Skipping {block_id}: metric table {panel_id} not found in {config_filename_dict[file_id]}"
|
||||
)
|
||||
continue
|
||||
if metric_id is None:
|
||||
# If no metric id level filtering, then read the whole panel
|
||||
texts.append(yaml.dump(panel_dict[panel_id], sort_keys=False))
|
||||
|
||||
# Metric id filtering
|
||||
metric_dict = {
|
||||
id: panel_dict[panel_id]["metric"][metric]
|
||||
for id, metric in enumerate(panel_dict[panel_id]["metric"].keys())
|
||||
}
|
||||
if metric_id not in metric_dict:
|
||||
console_warning(
|
||||
f"Skipping {block_id}: metric id {metric_id} not found in panel id {panel_id}"
|
||||
)
|
||||
continue
|
||||
texts.append(yaml.dump(metric_dict[metric_id], sort_keys=False))
|
||||
|
||||
counters = self.parse_counters("\n".join(texts))
|
||||
|
||||
# Handle TCC channel counters: if hw_counter_matches has elements ending with '['
|
||||
# Expand and interleve the TCC channel counters
|
||||
# e.g. TCC_HIT[0] TCC_ATOMIC[0] ... TCC_HIT[1] TCC_ATOMIC[1] ...
|
||||
num_xcd_for_pmc_file = 1
|
||||
if using_v3():
|
||||
num_xcd_for_pmc_file = int(self._mspec.num_xcd)
|
||||
|
||||
else:
|
||||
num_xcd_for_pmc_file = 1
|
||||
for counter_name in counters.copy():
|
||||
if counter_name.startswith("TCC") and counter_name.endswith("["):
|
||||
counters.remove(counter_name)
|
||||
@@ -562,7 +569,7 @@ class OmniSoC_Base:
|
||||
|
||||
# Sanity check whether counters are supported by underlying rocprof tool
|
||||
rocprof_counters = self.get_rocprof_supported_counters()
|
||||
# rocprof does not support TCC channel counters, so remove channel suffix for comparison
|
||||
# rocprof does not support TCC channel counters in the avail output, so remove channel suffix for comparison
|
||||
not_supported_counters = {
|
||||
counter.split("[")[0] if is_tcc_channel_counter(counter) else counter
|
||||
for counter in counters
|
||||
@@ -606,8 +613,6 @@ class OmniSoC_Base:
|
||||
file_count = 0
|
||||
# Store all channels for a TCC channel counter in the same file
|
||||
tcc_channel_counter_file_map = dict()
|
||||
# Store all pipes for SPI pipe counters in the same file
|
||||
spi_pipe_counter_file_map = dict()
|
||||
for ctr in counters:
|
||||
# Store all channels for a TCC channel counter in the same file
|
||||
if is_tcc_channel_counter(ctr):
|
||||
|
||||
@@ -313,7 +313,8 @@ def process_panels_to_dataframes(
|
||||
name for name, type in filter_panel_ids.items() if type == "metric_id"
|
||||
]
|
||||
filter_panel_ids = [
|
||||
convert_metric_id_to_panel_idx(section) for section in filter_panel_ids
|
||||
int(convert_metric_id_to_panel_info(metric_id)[0])
|
||||
for metric_id in filter_panel_ids
|
||||
]
|
||||
|
||||
# Initialize the result structure
|
||||
@@ -562,15 +563,48 @@ def string_multiple_lines(source, width, max_rows):
|
||||
return "\n".join(lines)
|
||||
|
||||
|
||||
def convert_metric_id_to_panel_idx(metric_id):
|
||||
# "4.02" -> 402
|
||||
# "4.23" -> 423
|
||||
# "4" -> 400
|
||||
def convert_metric_id_to_panel_info(metric_id):
|
||||
"""
|
||||
Convert metric id into panel information.
|
||||
Output is a tuples of the form (file_id, panel_id, metric_id).
|
||||
|
||||
For example:
|
||||
|
||||
Input: "2"
|
||||
Output: ("0200", None, None)
|
||||
|
||||
Input: "11"
|
||||
Output: ("1100", None, None)
|
||||
|
||||
Input: "11.1"
|
||||
Output: ("1100", 1101, None)
|
||||
|
||||
Input: "11.1.1"
|
||||
Output: ("1100", 1101, 1)
|
||||
|
||||
Raises exception for invalid metric id.
|
||||
"""
|
||||
tokens = metric_id.split(".")
|
||||
if len(tokens) == 1:
|
||||
return int(tokens[0]) * 100
|
||||
elif len(tokens) == 2:
|
||||
return int(tokens[0]) * 100 + int(tokens[1])
|
||||
if 0 < len(tokens) < 4:
|
||||
# File id
|
||||
file_id = str(int(tokens[0]))
|
||||
# 4 -> 04
|
||||
if len(file_id) < 2:
|
||||
file_id = f"0{file_id}"
|
||||
# Multiply integer by 100
|
||||
file_id = f"{file_id}00"
|
||||
# Panel id
|
||||
if len(tokens) > 1:
|
||||
panel_id = int(tokens[0]) * 100
|
||||
panel_id += int(tokens[1])
|
||||
else:
|
||||
panel_id = None
|
||||
# Metric id
|
||||
if len(tokens) > 2:
|
||||
metric_id = int(tokens[2])
|
||||
else:
|
||||
metric_id = None
|
||||
return (file_id, panel_id, metric_id)
|
||||
else:
|
||||
raise Exception(f"Invalid metric id: {metric_id}")
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ from tabulate import tabulate
|
||||
from config import HIDDEN_COLUMNS, HIDDEN_SECTIONS
|
||||
from utils import mem_chart, parser
|
||||
from utils.logger import console_error, console_log, console_warning
|
||||
from utils.utils import convert_metric_id_to_panel_idx
|
||||
from utils.utils import convert_metric_id_to_panel_info
|
||||
|
||||
|
||||
def string_multiple_lines(source, width, max_rows):
|
||||
@@ -71,9 +71,9 @@ def show_all(args, runs, archConfigs, output, profiling_config, roof_plot=None):
|
||||
name for name, type in filter_panel_ids.items() if type == "metric_id"
|
||||
]
|
||||
filter_panel_ids = [
|
||||
convert_metric_id_to_panel_idx(section) for section in filter_panel_ids
|
||||
int(convert_metric_id_to_panel_info(metric_id)[0])
|
||||
for metric_id in filter_panel_ids
|
||||
]
|
||||
comparable_columns = parser.build_comparable_columns(args.time_unit)
|
||||
|
||||
for panel_id, panel in archConfigs.panel_configs.items():
|
||||
# Skip panels that don't support baseline comparison
|
||||
|
||||
@@ -1536,16 +1536,50 @@ def merge_counters_spatial_multiplex(df_multi_index):
|
||||
return final_df
|
||||
|
||||
|
||||
def convert_metric_id_to_panel_idx(metric_id):
|
||||
# "4.02" -> 402
|
||||
# "4.23" -> 423
|
||||
# "4" -> 400
|
||||
def convert_metric_id_to_panel_info(metric_id):
|
||||
"""
|
||||
Convert metric id into panel information.
|
||||
Output is a tuples of the form (file_id, panel_id, metric_id).
|
||||
|
||||
For example:
|
||||
|
||||
Input: "2"
|
||||
Output: ("0200", None, None)
|
||||
|
||||
Input: "11"
|
||||
Output: ("1100", None, None)
|
||||
|
||||
Input: "11.1"
|
||||
Output: ("1100", 1101, None)
|
||||
|
||||
Input: "11.1.1"
|
||||
Output: ("1100", 1101, 1)
|
||||
|
||||
Raises exception for invalid metric id.
|
||||
"""
|
||||
tokens = metric_id.split(".")
|
||||
if len(tokens) == 1:
|
||||
return int(tokens[0]) * 100
|
||||
if len(tokens) == 2:
|
||||
return int(tokens[0]) * 100 + int(tokens[1])
|
||||
raise Exception(f"Invalid metric id: {metric_id}")
|
||||
if 0 < len(tokens) < 4:
|
||||
# File id
|
||||
file_id = str(int(tokens[0]))
|
||||
# 4 -> 04
|
||||
if len(file_id) == 1:
|
||||
file_id = f"0{file_id}"
|
||||
# Multiply integer by 100
|
||||
file_id = f"{file_id}00"
|
||||
# Panel id
|
||||
if len(tokens) > 1:
|
||||
panel_id = int(tokens[0]) * 100
|
||||
panel_id += int(tokens[1])
|
||||
else:
|
||||
panel_id = None
|
||||
# Metric id
|
||||
if len(tokens) > 2:
|
||||
metric_id = int(tokens[2])
|
||||
else:
|
||||
metric_id = None
|
||||
return (file_id, panel_id, metric_id)
|
||||
else:
|
||||
raise Exception(f"Invalid metric id: {metric_id}")
|
||||
|
||||
|
||||
def format_time(seconds):
|
||||
|
||||
@@ -8484,39 +8484,39 @@ def test_merge_counters_spatial_multiplex_timestamp_median_calculation():
|
||||
|
||||
|
||||
# =============================================================================
|
||||
# Tests for convert_metric_id_to_panel_idx function
|
||||
# Tests for convert_metric_id_to_panel_info function
|
||||
# ============================================================================
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_zero_values():
|
||||
"""Test convert_metric_id_to_panel_idx with zero values in different positions.
|
||||
def test_convert_metric_id_to_panel_info_zero_values():
|
||||
"""Test convert_metric_id_to_panel_info with zero values in different positions.
|
||||
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None: Asserts that zero values are handled correctly in metric IDs.
|
||||
"""
|
||||
assert utils.convert_metric_id_to_panel_idx("0") == 0
|
||||
assert utils.convert_metric_id_to_panel_idx("0.0") == 0
|
||||
assert utils.convert_metric_id_to_panel_idx("5.0") == 500
|
||||
assert utils.convert_metric_id_to_panel_idx("0.5") == 5
|
||||
assert utils.convert_metric_id_to_panel_info("0") == ("0000", None, None)
|
||||
assert utils.convert_metric_id_to_panel_info("0.0") == ("0000", 0, None)
|
||||
assert utils.convert_metric_id_to_panel_info("5.0") == ("0500", 500, None)
|
||||
assert utils.convert_metric_id_to_panel_info("0.5") == ("0000", 5, None)
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_leading_zeros():
|
||||
"""Test convert_metric_id_to_panel_idx with leading zeros in metric IDs.
|
||||
def test_convert_metric_id_to_panel_info_leading_zeros():
|
||||
"""Test convert_metric_id_to_panel_info with leading zeros in metric IDs.
|
||||
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None: Asserts that leading zeros are handled correctly.
|
||||
"""
|
||||
assert utils.convert_metric_id_to_panel_idx("04") == 400
|
||||
assert utils.convert_metric_id_to_panel_idx("4.02") == 402
|
||||
assert utils.convert_metric_id_to_panel_idx("01.05") == 105
|
||||
assert utils.convert_metric_id_to_panel_info("04") == ("0400", None, None)
|
||||
assert utils.convert_metric_id_to_panel_info("4.02") == ("0400", 402, None)
|
||||
assert utils.convert_metric_id_to_panel_info("01.05") == ("0100", 105, None)
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_invalid_empty_string():
|
||||
"""Test convert_metric_id_to_panel_idx with empty string raises exception.
|
||||
def test_convert_metric_id_to_panel_info_invalid_empty_string():
|
||||
"""Test convert_metric_id_to_panel_info with empty string raises exception.
|
||||
|
||||
Args:
|
||||
None
|
||||
@@ -8524,11 +8524,11 @@ def test_convert_metric_id_to_panel_idx_invalid_empty_string():
|
||||
None: Asserts that empty string raises ValueError.
|
||||
"""
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("")
|
||||
utils.convert_metric_id_to_panel_info("")
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_invalid_too_many_parts():
|
||||
"""Test convert_metric_id_to_panel_idx with more than two parts raises exception.
|
||||
def test_convert_metric_id_to_panel_info_invalid_too_many_parts():
|
||||
"""Test convert_metric_id_to_panel_info with more than two parts raises exception.
|
||||
|
||||
Args:
|
||||
None
|
||||
@@ -8536,17 +8536,17 @@ def test_convert_metric_id_to_panel_idx_invalid_too_many_parts():
|
||||
None: Asserts that metric IDs with more than two parts raise Exception.
|
||||
"""
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("4.02.1")
|
||||
utils.convert_metric_id_to_panel_info("4.02.1.5")
|
||||
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("1.2.3.4")
|
||||
utils.convert_metric_id_to_panel_info("1.2.3.4")
|
||||
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("4.02.1.5")
|
||||
utils.convert_metric_id_to_panel_info("4.02.1.5")
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_invalid_non_numeric():
|
||||
"""Test convert_metric_id_to_panel_idx with non-numeric values raises exception.
|
||||
def test_convert_metric_id_to_panel_info_invalid_non_numeric():
|
||||
"""Test convert_metric_id_to_panel_info with non-numeric values raises exception.
|
||||
|
||||
Args:
|
||||
None
|
||||
@@ -8554,68 +8554,63 @@ def test_convert_metric_id_to_panel_idx_invalid_non_numeric():
|
||||
None: Asserts that non-numeric metric IDs raise ValueError.
|
||||
"""
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("abc")
|
||||
utils.convert_metric_id_to_panel_info("abc")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("4.abc")
|
||||
utils.convert_metric_id_to_panel_info("4.abc")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("abc.02")
|
||||
utils.convert_metric_id_to_panel_info("abc.02")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("4.02abc")
|
||||
utils.convert_metric_id_to_panel_info("4.02abc")
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_invalid_floating_point():
|
||||
"""Test convert_metric_id_to_panel_idx with floating point numbers in unexpected format.
|
||||
def test_convert_metric_id_to_panel_info_three_floating_point():
|
||||
"""Test convert_metric_id_to_panel_info with floating point numbers in unexpected format.
|
||||
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None: Asserts behavior with floating point representations.
|
||||
"""
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("4.0.2")
|
||||
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("4.2.0")
|
||||
assert utils.convert_metric_id_to_panel_info("4.0.2") == ("0400", 400, 2)
|
||||
assert utils.convert_metric_id_to_panel_info("4.2.0") == ("0400", 402, 0)
|
||||
assert utils.convert_metric_id_to_panel_info("4.0.3") == ("0400", 400, 3)
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_edge_case_whitespace():
|
||||
"""Test convert_metric_id_to_panel_idx with whitespace in metric IDs.
|
||||
def test_convert_metric_id_to_panel_info_edge_case_whitespace():
|
||||
"""Test convert_metric_id_to_panel_info with whitespace in metric IDs.
|
||||
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None: Asserts that whitespace is handled (int() strips whitespace).
|
||||
"""
|
||||
assert utils.convert_metric_id_to_panel_idx(" 4") == 400
|
||||
assert utils.convert_metric_id_to_panel_idx("4 ") == 400
|
||||
assert utils.convert_metric_id_to_panel_idx(" 4.02 ") == 402
|
||||
|
||||
assert utils.convert_metric_id_to_panel_idx("4. 02") == 402
|
||||
assert utils.convert_metric_id_to_panel_idx(" 4 . 02 ") == 402
|
||||
assert utils.convert_metric_id_to_panel_info(" 4") == ("0400", None, None)
|
||||
assert utils.convert_metric_id_to_panel_info("4 ") == ("0400", None, None)
|
||||
assert utils.convert_metric_id_to_panel_info("4 . 02") == ("0400", 402, None)
|
||||
|
||||
|
||||
def test_convert_metric_id_to_panel_idx_edge_case_dot_only():
|
||||
"""Test convert_metric_id_to_panel_idx with only dot character raises exception.
|
||||
def test_convert_metric_id_to_panel_info_edge_case_dot_only():
|
||||
"""Test convert_metric_id_to_panel_info with only dot character raises exception.
|
||||
|
||||
Args:
|
||||
None
|
||||
Returns:
|
||||
None: Asserts that metric ID with only dot raises Exception.
|
||||
"""
|
||||
with pytest.raises(Exception, match="Invalid metric id"):
|
||||
utils.convert_metric_id_to_panel_idx("..")
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_info("..")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx(".")
|
||||
utils.convert_metric_id_to_panel_info(".")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx("4.")
|
||||
utils.convert_metric_id_to_panel_info("4.")
|
||||
|
||||
with pytest.raises(ValueError):
|
||||
utils.convert_metric_id_to_panel_idx(".02")
|
||||
utils.convert_metric_id_to_panel_info(".02")
|
||||
|
||||
|
||||
# =============================================================================
|
||||
|
||||
Odkázat v novém úkolu
Zablokovat Uživatele