[CONFORMANCE] Improve python test utils (#15329)
* Remove download of vodels + move some methods to utils * Separate constants * filelist * separate conformance utilities * Update script according new utils * Fix subgraphdumper crash * Some small improvements for api conformance * add warn_message * One short fix * fix master
This commit is contained in:
parent
290947da84
commit
e88210c95d
@ -196,10 +196,9 @@ OPCache::serialize_function(const std::pair<std::shared_ptr<ov::Node>, LayerTest
|
|||||||
}
|
}
|
||||||
std::replace(op_name.begin(), op_name.end(), '/', '_');
|
std::replace(op_name.begin(), op_name.end(), '/', '_');
|
||||||
std::replace(op_name.begin(), op_name.end(), '\\', '_');
|
std::replace(op_name.begin(), op_name.end(), '\\', '_');
|
||||||
auto filePrefix = CommonTestUtils::generateTestFilePrefix();
|
auto xml_path = current_op_folder + CommonTestUtils::FileSeparator + op_name + ".xml";
|
||||||
auto xml_path = current_op_folder + CommonTestUtils::FileSeparator + filePrefix + op_name + ".xml";
|
auto bin_path = current_op_folder + CommonTestUtils::FileSeparator + op_name + ".bin";
|
||||||
auto bin_path = current_op_folder + CommonTestUtils::FileSeparator + filePrefix + op_name + ".bin";
|
auto meta_info = current_op_folder + CommonTestUtils::FileSeparator + op_name + ".meta";
|
||||||
auto meta_info = current_op_folder + CommonTestUtils::FileSeparator + filePrefix + op_name + ".meta";
|
|
||||||
auto cnn_net = InferenceEngine::CNNNetwork(function);
|
auto cnn_net = InferenceEngine::CNNNetwork(function);
|
||||||
cnn_net.serialize(xml_path, bin_path);
|
cnn_net.serialize(xml_path, bin_path);
|
||||||
serialize_meta_info(op.second, meta_info);
|
serialize_meta_info(op.second, meta_info);
|
||||||
|
@ -8,7 +8,8 @@ import zipfile
|
|||||||
import argparse
|
import argparse
|
||||||
import openpyxl
|
import openpyxl
|
||||||
|
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger
|
||||||
|
from utils import constants
|
||||||
|
|
||||||
|
|
||||||
LOGS_ZIP_NAME = 'logs.zip'
|
LOGS_ZIP_NAME = 'logs.zip'
|
||||||
@ -17,7 +18,7 @@ NEW_LOG_DIR = 'ie_logs'
|
|||||||
|
|
||||||
SW_PLUGINS = {'HETERO': '1', 'AUTO': '2', 'BATCH': '3', 'MULTI': '4'}
|
SW_PLUGINS = {'HETERO': '1', 'AUTO': '2', 'BATCH': '3', 'MULTI': '4'}
|
||||||
|
|
||||||
logger = utils.get_logger('AnalyzerConformanceLog')
|
logger = get_logger('AnalyzerConformanceLog')
|
||||||
|
|
||||||
|
|
||||||
class AnalyzerConformanceLog:
|
class AnalyzerConformanceLog:
|
||||||
@ -90,7 +91,7 @@ class AnalyzerConformanceLog:
|
|||||||
test_info_by_device = None
|
test_info_by_device = None
|
||||||
|
|
||||||
for line in lines:
|
for line in lines:
|
||||||
if utils.RUN in line:
|
if constants.RUN in line:
|
||||||
in_run_stage = True
|
in_run_stage = True
|
||||||
error_msg = ''
|
error_msg = ''
|
||||||
# if run stage exists, it is because gtest decided to show log as test fails
|
# if run stage exists, it is because gtest decided to show log as test fails
|
||||||
@ -98,7 +99,7 @@ class AnalyzerConformanceLog:
|
|||||||
continue
|
continue
|
||||||
|
|
||||||
# it is result, we got to the end of run stage
|
# it is result, we got to the end of run stage
|
||||||
if utils.TEST_STATUS['failed'] in line:
|
if constants.TEST_STATUS['failed'][0] in line:
|
||||||
in_run_stage = False
|
in_run_stage = False
|
||||||
if error_msg:
|
if error_msg:
|
||||||
test_info_by_device['err_info'] = error_msg
|
test_info_by_device['err_info'] = error_msg
|
||||||
|
@ -2,14 +2,14 @@ import os
|
|||||||
import re
|
import re
|
||||||
import argparse
|
import argparse
|
||||||
|
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger
|
||||||
|
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
|
|
||||||
logger = utils.get_logger('HighlightTable')
|
logger = get_logger('HighlightTable')
|
||||||
|
|
||||||
OPSET_REPORT_NAME_RE = r'.*report_opset_\w*.xml'
|
OPSET_REPORT_NAME_RE = r'.*report_opset_\w*.xml'
|
||||||
API_REPORT_NAME_RE = r'.*report_api_\w*.xml'
|
API_REPORT_NAME_RE = r'.*report_api_\w*.xml'
|
||||||
|
@ -8,7 +8,8 @@ import glob
|
|||||||
import defusedxml.ElementTree as ET
|
import defusedxml.ElementTree as ET
|
||||||
from defusedxml import defuse_stdlib
|
from defusedxml import defuse_stdlib
|
||||||
|
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger
|
||||||
|
from utils import stat_update_utils
|
||||||
|
|
||||||
# defuse_stdlib provide patched version of xml.etree.ElementTree which allows to use objects from xml.etree.ElementTree
|
# defuse_stdlib provide patched version of xml.etree.ElementTree which allows to use objects from xml.etree.ElementTree
|
||||||
# in a safe manner without including unsafe xml.etree.ElementTree
|
# in a safe manner without including unsafe xml.etree.ElementTree
|
||||||
@ -16,7 +17,7 @@ ET_defused = defuse_stdlib()[ET]
|
|||||||
Element = ET_defused.Element
|
Element = ET_defused.Element
|
||||||
SubElement = ET_defused.SubElement
|
SubElement = ET_defused.SubElement
|
||||||
|
|
||||||
logger = utils.get_logger('XmlMerger')
|
logger = get_logger('xml_merge_tool')
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
@ -54,7 +55,7 @@ def update_result_node(xml_node: SubElement, aggregated_res: SubElement):
|
|||||||
def aggregate_test_results(aggregated_results: SubElement, xml_reports: list, report_type: str):
|
def aggregate_test_results(aggregated_results: SubElement, xml_reports: list, report_type: str):
|
||||||
aggregated_timestamp = None
|
aggregated_timestamp = None
|
||||||
for xml in xml_reports:
|
for xml in xml_reports:
|
||||||
logger.info(f" Processing: {xml}")
|
# logger.info(f" Processing: {xml}")
|
||||||
try:
|
try:
|
||||||
xml_root = ET.parse(xml).getroot()
|
xml_root = ET.parse(xml).getroot()
|
||||||
except ET.ParseError:
|
except ET.ParseError:
|
||||||
@ -131,10 +132,10 @@ def merge_xml(input_folder_paths: list, output_folder_paths: str, output_filenam
|
|||||||
SubElement(entity_list, entity.tag)
|
SubElement(entity_list, entity.tag)
|
||||||
timestamp = aggregate_test_results(results, xml_reports, report_type)
|
timestamp = aggregate_test_results(results, xml_reports, report_type)
|
||||||
if report_type == "OP":
|
if report_type == "OP":
|
||||||
utils.update_passrates(results)
|
stat_update_utils.update_passrates(results)
|
||||||
else:
|
else:
|
||||||
for sub_result in results:
|
for sub_result in results:
|
||||||
utils.update_passrates(sub_result)
|
stat_update_utils.update_passrates(sub_result)
|
||||||
summary.set("timestamp", timestamp)
|
summary.set("timestamp", timestamp)
|
||||||
logger.info(f" Processing is finished")
|
logger.info(f" Processing is finished")
|
||||||
|
|
||||||
|
@ -6,16 +6,39 @@ import defusedxml.ElementTree as ET
|
|||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger, set_env_variable
|
||||||
|
from utils.constants import PY_OPENVINO, LD_LIB_PATH_NAME, PYTHON_NAME
|
||||||
|
from utils.file_utils import get_ov_path, find_latest_dir
|
||||||
|
|
||||||
from openvino.runtime import Core
|
import os
|
||||||
|
|
||||||
|
logger = get_logger('rename_conformance_ir')
|
||||||
|
|
||||||
|
try:
|
||||||
|
from openvino.runtime import Core
|
||||||
|
except:
|
||||||
|
script_dir, _ = os.path.split(os.path.abspath(__file__))
|
||||||
|
ov_bin_path = get_ov_path(script_dir, None, True)
|
||||||
|
if PY_OPENVINO in os.listdir(ov_bin_path):
|
||||||
|
env = os.environ
|
||||||
|
py_ov = os.path.join(ov_bin_path, PY_OPENVINO)
|
||||||
|
py_ov = os.path.join(py_ov, find_latest_dir(py_ov))
|
||||||
|
|
||||||
|
env = set_env_variable(env, "PYTHONPATH", py_ov)
|
||||||
|
env = set_env_variable(env, LD_LIB_PATH_NAME, ov_bin_path)
|
||||||
|
logger.warning("Set the following env varibles to rename conformance ir based on hash: ")
|
||||||
|
logger.warning(f'PYTHONPATH={env["PYTHONPATH"]}')
|
||||||
|
logger.warning(f'{LD_LIB_PATH_NAME}={env[LD_LIB_PATH_NAME]}')
|
||||||
|
exit(0)
|
||||||
|
else:
|
||||||
|
print(f'Impossible to run the tool! PyOpenVINO was not built!')
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
|
||||||
XML_EXTENSION = ".xml"
|
XML_EXTENSION = ".xml"
|
||||||
BIN_EXTENSION = ".bin"
|
BIN_EXTENSION = ".bin"
|
||||||
META_EXTENSION = ".meta"
|
META_EXTENSION = ".meta"
|
||||||
|
|
||||||
logger = utils.get_logger('Rename Conformance IRs using hash')
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
@ -77,7 +100,7 @@ def create_hash(in_dir_path: Path):
|
|||||||
meta_path.rename(Path(meta_path.parent, new_name + META_EXTENSION))
|
meta_path.rename(Path(meta_path.parent, new_name + META_EXTENSION))
|
||||||
bin_path.rename(Path(bin_path.parent, new_name + BIN_EXTENSION))
|
bin_path.rename(Path(bin_path.parent, new_name + BIN_EXTENSION))
|
||||||
|
|
||||||
logger.info(f"{old_name} -> {new_name}")
|
# logger.info(f"{old_name} -> {new_name}")
|
||||||
|
|
||||||
if __name__=="__main__":
|
if __name__=="__main__":
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
jinja2==3.1.2
|
jinja2==3.1.2
|
||||||
gitpython
|
|
||||||
defusedxml>=0.7.1
|
defusedxml>=0.7.1
|
||||||
openpyxl==3.0.10
|
openpyxl==3.0.10
|
@ -1,79 +1,39 @@
|
|||||||
from asyncio import subprocess
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
from queue import Empty
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
from git import Repo
|
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from utils import utils
|
|
||||||
from subprocess import Popen
|
from subprocess import Popen
|
||||||
from shutil import copytree, rmtree
|
from shutil import copytree, rmtree
|
||||||
from summarize import create_summary
|
from summarize import create_summary
|
||||||
from merge_xmls import merge_xml
|
from merge_xmls import merge_xml
|
||||||
from run_parallel import TestParallelRunner
|
from run_parallel import TestParallelRunner
|
||||||
from pathlib import Path, PurePath
|
from pathlib import Path
|
||||||
from sys import version, platform
|
|
||||||
|
|
||||||
import defusedxml.ElementTree as ET
|
import defusedxml.ElementTree as ET
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import urllib.request as ur
|
||||||
|
from utils import constants
|
||||||
|
from utils.conformance_utils import get_logger
|
||||||
|
from utils import file_utils
|
||||||
|
|
||||||
logger = utils.get_logger('ConformanceRunner')
|
logger = get_logger('conformance_runner')
|
||||||
|
is_hash = True
|
||||||
OPENVINO_NAME = 'openvino'
|
try:
|
||||||
|
from rename_conformance_ir import create_hash
|
||||||
OMZ_REPO_URL = "https://github.com/openvinotoolkit/open_model_zoo.git"
|
except:
|
||||||
OMZ_REPO_BRANCH = "master"
|
logger.warning("Please set the above env variable to get the same conformance ir names run by run!")
|
||||||
|
is_hash = False
|
||||||
GTEST_PARALLEL_URL = "https://github.com/intel-innersource/frameworks.ai.openvino.ci.infrastructure.git"
|
|
||||||
GTEST_PARALLEL_BRANCH = "master"
|
|
||||||
|
|
||||||
API_CONFORMANCE_BIN_NAME = "apiConformanceTests"
|
API_CONFORMANCE_BIN_NAME = "apiConformanceTests"
|
||||||
OP_CONFORMANCE_BIN_NAME = "conformanceTests"
|
OP_CONFORMANCE_BIN_NAME = "conformanceTests"
|
||||||
SUBGRAPH_DUMPER_BIN_NAME = "subgraphsDumper"
|
SUBGRAPH_DUMPER_BIN_NAME = "subgraphsDumper"
|
||||||
|
|
||||||
DEBUG_DIR = "Debug"
|
NO_MODEL_CONSTANT = "http://ov-share-03.sclab.intel.com/Shares/conformance_ir/dlb/master/2022.3.0-8953-8c3425ff698.tar"
|
||||||
RELEASE_DIR = "Release"
|
|
||||||
|
|
||||||
IS_WIN = "windows" in platform or "win32" in platform
|
|
||||||
|
|
||||||
OS_SCRIPT_EXT = ".bat" if IS_WIN else ""
|
|
||||||
OS_BIN_FILE_EXT = ".exe" if IS_WIN else ""
|
|
||||||
|
|
||||||
NO_MODEL_CONSTANT = "NO_MODEL"
|
|
||||||
|
|
||||||
ENV_SEPARATOR = ";" if IS_WIN else ":"
|
|
||||||
|
|
||||||
PYTHON_NAME = "python" if IS_WIN else "python3"
|
|
||||||
PIP_NAME = "pip" if IS_WIN else "pip3"
|
|
||||||
|
|
||||||
SCRIPT_DIR_PATH, SCRIPT_NAME = os.path.split(os.path.abspath(__file__))
|
SCRIPT_DIR_PATH, SCRIPT_NAME = os.path.split(os.path.abspath(__file__))
|
||||||
|
|
||||||
def find_latest_dir(in_dir: Path, pattern_list = list()):
|
|
||||||
get_latest_dir = lambda path: sorted(Path(path).iterdir(), key=os.path.getmtime)
|
|
||||||
entities = get_latest_dir(in_dir)
|
|
||||||
entities.reverse()
|
|
||||||
|
|
||||||
for entity in entities:
|
|
||||||
if entity.is_dir():
|
|
||||||
if not pattern_list:
|
|
||||||
return entity
|
|
||||||
else:
|
|
||||||
for pattern in pattern_list:
|
|
||||||
if pattern in str(os.fspath(PurePath(entity))):
|
|
||||||
return entity
|
|
||||||
logger.error(f"{in_dir} does not contain applicable directories to patterns: {pattern_list}")
|
|
||||||
exit(-1)
|
|
||||||
|
|
||||||
def get_ov_path(ov_dir=None, is_bin=False):
|
|
||||||
if ov_dir is None or not os.path.isdir(ov_dir):
|
|
||||||
if 'INTEL_OPENVINO_DIR' in os.environ:
|
|
||||||
ov_dir = os.environ['INTEL_OPENVINO_DIR']
|
|
||||||
else:
|
|
||||||
ov_dir = os.path.abspath(SCRIPT_DIR_PATH)[:os.path.abspath(SCRIPT_DIR_PATH).find(OPENVINO_NAME) + len(OPENVINO_NAME)]
|
|
||||||
if is_bin:
|
|
||||||
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir, ['bin']))
|
|
||||||
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir))
|
|
||||||
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir, [DEBUG_DIR, RELEASE_DIR]))
|
|
||||||
return ov_dir
|
|
||||||
|
|
||||||
def get_default_working_dir():
|
def get_default_working_dir():
|
||||||
path = Path(__file__).parent.resolve()
|
path = Path(__file__).parent.resolve()
|
||||||
return os.path.join(path, "temp")
|
return os.path.join(path, "temp")
|
||||||
@ -81,9 +41,9 @@ def get_default_working_dir():
|
|||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
|
|
||||||
models_path_help = "Path to the directory/ies containing models to dump subgraph (the default way is to download OMZ). If --s=0, specify the Conformance IRs directory"
|
models_path_help = "Path to the directory/ies containing models to dump subgraph (the default way is to download conformance IR). It may be directory, archieve file, .lst file or http link to download something . If --s=0, specify the Conformance IRs directory"
|
||||||
device_help = " Specify the target device. The default value is CPU"
|
device_help = " Specify the target device. The default value is CPU"
|
||||||
ov_help = "OV binary files path. The default way is try to find installed OV by INTEL_OPENVINO_DIR in environmet variables or to find the absolute path of OV repo (by using script path)"
|
ov_help = "OV repo path. The default way is try to find the absolute path of OV repo (by using script path)"
|
||||||
working_dir_help = "Specify a working directory to save all artifacts, such as reports, models, conformance_irs, etc."
|
working_dir_help = "Specify a working directory to save all artifacts, such as reports, models, conformance_irs, etc."
|
||||||
type_help = "Specify conformance type: `OP` or `API`. The default value is `OP`"
|
type_help = "Specify conformance type: `OP` or `API`. The default value is `OP`"
|
||||||
workers_help = "Specify number of workers to run in parallel. The default value is CPU count - 1"
|
workers_help = "Specify number of workers to run in parallel. The default value is CPU count - 1"
|
||||||
@ -93,123 +53,56 @@ def parse_arguments():
|
|||||||
|
|
||||||
parser.add_argument("-m", "--models_path", help=models_path_help, type=str, required=False, default=NO_MODEL_CONSTANT)
|
parser.add_argument("-m", "--models_path", help=models_path_help, type=str, required=False, default=NO_MODEL_CONSTANT)
|
||||||
parser.add_argument("-d", "--device", help= device_help, type=str, required=False, default="CPU")
|
parser.add_argument("-d", "--device", help= device_help, type=str, required=False, default="CPU")
|
||||||
parser.add_argument("-ov", "--ov_path", help=ov_help, type=str, required=False, default=get_ov_path())
|
parser.add_argument("-ov", "--ov_path", help=ov_help, type=str, required=False, default=file_utils.get_ov_path(SCRIPT_DIR_PATH))
|
||||||
parser.add_argument("-w", "--working_dir", help=working_dir_help, type=str, required=False, default=get_default_working_dir())
|
parser.add_argument("-w", "--working_dir", help=working_dir_help, type=str, required=False, default=get_default_working_dir())
|
||||||
parser.add_argument("-t", "--type", help=type_help, type=str, required=False, default="OP")
|
parser.add_argument("-t", "--type", help=type_help, type=str, required=False, default="OP")
|
||||||
parser.add_argument("-j", "--workers", help=workers_help, type=int, required=False, default=os.cpu_count()-1)
|
parser.add_argument("-j", "--workers", help=workers_help, type=int, required=False, default=os.cpu_count()-1)
|
||||||
parser.add_argument("--gtest_filter", help=gtest_filter_helper, type=str, required=False, default="*")
|
parser.add_argument("--gtest_filter", help=gtest_filter_helper, type=str, required=False, default="*")
|
||||||
parser.add_argument("-c", "--ov_config_path", help=ov_config_path_helper, type=str, required=False, default="")
|
parser.add_argument("-c", "--ov_config_path", help=ov_config_path_helper, type=str, required=False, default="")
|
||||||
parser.add_argument("-s", "--dump_conformance", help=dump_conformance_help, type=int, required=False, default=1)
|
parser.add_argument("-s", "--dump_conformance", help=dump_conformance_help, type=int, required=False, default=0)
|
||||||
|
|
||||||
return parser.parse_args()
|
return parser.parse_args()
|
||||||
|
|
||||||
def set_env_variable(env: os.environ, var_name: str, var_value: str):
|
|
||||||
if var_name in env:
|
|
||||||
env[var_name] = var_value + ENV_SEPARATOR + env[var_name]
|
|
||||||
else:
|
|
||||||
env[var_name] = var_value
|
|
||||||
return env
|
|
||||||
|
|
||||||
class Conformance:
|
class Conformance:
|
||||||
def __init__(self, device:str, model_path:os.path, ov_path:os.path, type:str, workers:int,
|
def __init__(self, device:str, model_path:os.path, ov_path:os.path, type:str, workers:int,
|
||||||
gtest_filter:str, working_dir:os.path, ov_config_path:os.path):
|
gtest_filter:str, working_dir:os.path, ov_config_path:os.path):
|
||||||
self._device = device
|
self._device = device
|
||||||
self._model_path = model_path
|
self._model_path = model_path
|
||||||
self._ov_path = ov_path
|
self._ov_path = ov_path
|
||||||
self._ov_bin_path = get_ov_path(self._ov_path, True)
|
self._ov_bin_path = file_utils.get_ov_path(SCRIPT_DIR_PATH, self._ov_path, True)
|
||||||
self._working_dir = working_dir
|
self._working_dir = working_dir
|
||||||
if not os.path.exists(self._working_dir):
|
if os.path.exists(self._working_dir):
|
||||||
os.mkdir(self._working_dir)
|
logger.info(f"Working dir {self._working_dir} is cleaned up")
|
||||||
|
rmtree(self._working_dir)
|
||||||
|
os.mkdir(self._working_dir)
|
||||||
if not (type == "OP" or type == "API"):
|
if not (type == "OP" or type == "API"):
|
||||||
logger.error(f"Incorrect conformance type: {type}. Please use 'OP' or 'API'")
|
logger.error(f"Incorrect conformance type: {type}. Please use 'OP' or 'API'")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
self._type = type
|
self._type = type
|
||||||
self._workers = workers
|
self._workers = workers
|
||||||
self._gtest_filter = gtest_filter
|
self._gtest_filter = gtest_filter
|
||||||
|
|
||||||
if not os.path.exists(ov_config_path) and ov_config_path != "":
|
if not os.path.exists(ov_config_path) and ov_config_path != "":
|
||||||
logger.error(f"Specified config file does not exist: {ov_config_path}.")
|
logger.error(f"Specified config file does not exist: {ov_config_path}.")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
self._ov_config_path = ov_config_path
|
self._ov_config_path = ov_config_path
|
||||||
|
|
||||||
def __download_repo(self, https_url: str, version: str):
|
def __download_conformance_ir(self):
|
||||||
repo_name = https_url[https_url.rfind('/') + 1:len(https_url) - 4]
|
_, file_name = os.path.split(urlparse(self._model_path).path)
|
||||||
repo_path = os.path.join(self._working_dir, repo_name)
|
model_archieve_path = os.path.join(self._working_dir, file_name)
|
||||||
if os.path.isdir(repo_path):
|
|
||||||
logger.info(f'Repo: {repo_name} exists in {self._working_dir}. Skip the repo download.')
|
|
||||||
repo = Repo(repo_path)
|
|
||||||
else:
|
|
||||||
logger.info(f'Started to clone repo: {https_url} to {repo_path}')
|
|
||||||
repo = Repo.clone_from(https_url, repo_path)
|
|
||||||
repo.submodule_update(recursive=True)
|
|
||||||
logger.info(f'Repo {https_url} was cloned sucessful')
|
|
||||||
remote_version = "origin/" + version
|
|
||||||
if remote_version in repo.git.branch('-r').replace(' ', '').split('\n'):
|
|
||||||
repo.git.checkout(version)
|
|
||||||
repo.git.pull()
|
|
||||||
repo.submodule_update(recursive=True)
|
|
||||||
logger.info(f'Repo {https_url} is on {version}')
|
|
||||||
return repo_path
|
|
||||||
|
|
||||||
def _convert_models(self):
|
|
||||||
omz_tools_path = os.path.join(self._omz_path, "tools", "model_tools")
|
|
||||||
original_model_path = os.path.join(self._working_dir, "original_models")
|
|
||||||
converted_model_path = os.path.join(self._working_dir, "converted_models")
|
|
||||||
if os.path.isdir(original_model_path):
|
|
||||||
logger.info(f"Original model path: {original_model_path} is removed")
|
|
||||||
rmtree(original_model_path)
|
|
||||||
if os.path.isdir(converted_model_path):
|
|
||||||
logger.info(f"Converted model path: {converted_model_path} is removed")
|
|
||||||
rmtree(converted_model_path)
|
|
||||||
mo_path = os.path.join(self._ov_path, "tools", "mo")
|
|
||||||
ov_python_path = os.path.join(self._ov_bin_path, "python_api", f"python{version[0:3]}")
|
|
||||||
|
|
||||||
convert_model_env = os.environ.copy()
|
|
||||||
ld_lib_path_name = ""
|
|
||||||
# Windows or MacOS
|
|
||||||
if IS_WIN or platform == "darwin":
|
|
||||||
ld_lib_path_name = "PATH"
|
|
||||||
# Linux
|
|
||||||
elif "lin" in platform:
|
|
||||||
ld_lib_path_name = "LD_LIBRARY_PATH"
|
|
||||||
convert_model_env = set_env_variable(convert_model_env, ld_lib_path_name, self._ov_bin_path)
|
|
||||||
convert_model_env = set_env_variable(convert_model_env, "PYTHONPATH", f"{ov_python_path}{ENV_SEPARATOR}{mo_path}")
|
|
||||||
convert_model_env = set_env_variable(convert_model_env, "OMZ_ROOT", self._omz_path)
|
|
||||||
|
|
||||||
logger.info(f"Model conversion from {original_model_path} to {converted_model_path} is started")
|
|
||||||
activate_path = os.path.join(".env3", "bin", "activate")
|
|
||||||
|
|
||||||
command = f'cd "{self._working_dir}"; ' \
|
|
||||||
f'{"" if os.path.isdir(".env3") else f"{PYTHON_NAME} -m venv .env3; "} '\
|
|
||||||
f'{"" if IS_WIN else "source"} {activate_path}{OS_SCRIPT_EXT}; '\
|
|
||||||
f'{PIP_NAME} install -e "{mo_path}/.[caffe,kaldi,mxnet,onnx,pytorch,tensorflow2]"; ' \
|
|
||||||
f'{PIP_NAME} install "{omz_tools_path}/.[paddle,pytorch,tensorflow]"; ' \
|
|
||||||
f'omz_downloader --all --output_dir="{original_model_path}"; '\
|
|
||||||
f'omz_converter --all --download_dir="{original_model_path}" --output_dir="{converted_model_path}"; '\
|
|
||||||
f'deactivate'
|
|
||||||
try:
|
try:
|
||||||
process = Popen(command, shell=True, env=convert_model_env)
|
logger.info(f"Conformance IRs will be downloaded from {self._model_path} to {model_archieve_path}")
|
||||||
out, err = process.communicate()
|
ur.urlretrieve(self._model_path, filename=model_archieve_path)
|
||||||
if err is None:
|
|
||||||
for line in str(out).split('\n'):
|
|
||||||
logger.info(line)
|
|
||||||
else:
|
|
||||||
logger.error(err)
|
|
||||||
exit(-1)
|
|
||||||
logger.info(f"Model conversion is successful. Converted models are saved to {converted_model_path}")
|
|
||||||
except:
|
except:
|
||||||
logger.error(f"Something is wrong with the model conversion! Abort the process")
|
logger.error(f"Please verify URL: {self._model_path}. Looks like that is incorrect")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
return converted_model_path
|
logger.info(f"Conformance IRs were downloaded from {self._model_path} to {model_archieve_path}")
|
||||||
|
if not file_utils.is_archieve(model_archieve_path):
|
||||||
|
logger.error(f"The file {model_archieve_path} is not archieve! It should be the archieve!")
|
||||||
|
exit()
|
||||||
|
self._model_path = file_utils.unzip_archieve(model_archieve_path, self._working_dir)
|
||||||
|
|
||||||
def download_and_convert_models(self):
|
def __dump_subgraph(self):
|
||||||
logger.info("Starting model downloading and conversion")
|
subgraph_dumper_path = os.path.join(self._ov_bin_path, f'{SUBGRAPH_DUMPER_BIN_NAME}{constants.OS_BIN_FILE_EXT}')
|
||||||
self._omz_path = self.__download_repo(OMZ_REPO_URL, OMZ_REPO_BRANCH)
|
|
||||||
self._model_path = self._convert_models()
|
|
||||||
logger.info("Model downloading and conversion is finished successful")
|
|
||||||
|
|
||||||
def dump_subgraph(self):
|
|
||||||
subgraph_dumper_path = os.path.join(self._ov_bin_path, f'{SUBGRAPH_DUMPER_BIN_NAME}{OS_BIN_FILE_EXT}')
|
|
||||||
if not os.path.isfile(subgraph_dumper_path):
|
if not os.path.isfile(subgraph_dumper_path):
|
||||||
logger.error(f"{subgraph_dumper_path} is not exist!")
|
logger.error(f"{subgraph_dumper_path} is not exist!")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
@ -231,13 +124,18 @@ class Conformance:
|
|||||||
logger.error("Process failed on step: 'Subgraph dumping'")
|
logger.error("Process failed on step: 'Subgraph dumping'")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
self._model_path = conformance_ir_path
|
self._model_path = conformance_ir_path
|
||||||
|
if is_hash:
|
||||||
def run_conformance(self):
|
create_hash(Path(self._model_path))
|
||||||
conformance_path = None
|
logger.info(f"All conformance IRs in {self._ov_bin_path} were renamed based on hash")
|
||||||
if self._type == "OP":
|
|
||||||
conformance_path = os.path.join(self._ov_bin_path, f'{OP_CONFORMANCE_BIN_NAME}{OS_BIN_FILE_EXT}')
|
|
||||||
else:
|
else:
|
||||||
conformance_path = os.path.join(self._ov_bin_path, f'{API_CONFORMANCE_BIN_NAME}{OS_BIN_FILE_EXT}')
|
logger.warning("The OV Python was not built or Environment was not updated to requirments. Skip the step to rename Conformance IR based on a hash")
|
||||||
|
|
||||||
|
def __run_conformance(self):
|
||||||
|
conformance_path = None
|
||||||
|
if self._type == constants.OP_CONFORMANCE:
|
||||||
|
conformance_path = os.path.join(self._ov_bin_path, f'{OP_CONFORMANCE_BIN_NAME}{constants.OS_BIN_FILE_EXT}')
|
||||||
|
else:
|
||||||
|
conformance_path = os.path.join(self._ov_bin_path, f'{API_CONFORMANCE_BIN_NAME}{constants.OS_BIN_FILE_EXT}')
|
||||||
|
|
||||||
if not os.path.isfile(conformance_path):
|
if not os.path.isfile(conformance_path):
|
||||||
logger.error(f"{conformance_path} is not exist!")
|
logger.error(f"{conformance_path} is not exist!")
|
||||||
@ -254,29 +152,30 @@ class Conformance:
|
|||||||
if not os.path.isdir(logs_dir):
|
if not os.path.isdir(logs_dir):
|
||||||
os.mkdir(logs_dir)
|
os.mkdir(logs_dir)
|
||||||
|
|
||||||
try:
|
command_line_args = [f"--device={self._device}", f'--input_folders="{self._model_path}"',
|
||||||
command_line_args = [f"--device={self._device}", f'--input_folders="{self._model_path}"',
|
f"--report_unique_name", f'--output_folder="{parallel_report_dir}"',
|
||||||
f"--report_unique_name", f'--output_folder="{parallel_report_dir}"',
|
f'--gtest_filter={self._gtest_filter}', f'--config_path="{self._ov_config_path}"']
|
||||||
f'--gtest_filter={self._gtest_filter}', f'--config_path "{self._ov_config_path}"']
|
conformance = TestParallelRunner(f"{conformance_path}", command_line_args, self._workers, logs_dir, "")
|
||||||
conformance = TestParallelRunner(f"{conformance_path}", command_line_args, self._workers, logs_dir, "")
|
conformance.run()
|
||||||
conformance.run()
|
conformance.postprocess_logs()
|
||||||
conformance.postprocess_logs()
|
|
||||||
except:
|
|
||||||
logger.error(f"Please check the output from `parallel_runner`. Something is wrong")
|
|
||||||
exit(-1)
|
|
||||||
final_report_name = f'report_{self._type}'
|
final_report_name = f'report_{self._type}'
|
||||||
|
# API Conformance contains both report type
|
||||||
merge_xml([parallel_report_dir], report_dir, final_report_name, self._type)
|
merge_xml([parallel_report_dir], report_dir, final_report_name, self._type)
|
||||||
|
if self._type == constants.API_CONFORMANCE:
|
||||||
|
final_op_report_name = f'report_{constants.OP_CONFORMANCE}'
|
||||||
|
merge_xml([parallel_report_dir], report_dir, final_op_report_name, constants.OP_CONFORMANCE)
|
||||||
logger.info(f"Conformance is successful. XML reportwas saved to {report_dir}")
|
logger.info(f"Conformance is successful. XML reportwas saved to {report_dir}")
|
||||||
return (os.path.join(report_dir, final_report_name + ".xml"), report_dir)
|
return (os.path.join(report_dir, final_report_name + ".xml"), report_dir)
|
||||||
|
|
||||||
def summarize(self, xml_report_path:os.path, report_dir: os.path):
|
def __summarize(self, xml_report_path:os.path, report_dir: os.path):
|
||||||
summary_root = ET.parse(xml_report_path).getroot()
|
summary_root = ET.parse(xml_report_path).getroot()
|
||||||
create_summary(summary_root, report_dir, [], "", "", False, True)
|
create_summary(summary_root, report_dir, [], "", "", False, True)
|
||||||
copytree(os.path.join(SCRIPT_DIR_PATH, "template"), os.path.join(report_dir, "template"))
|
copytree(os.path.join(SCRIPT_DIR_PATH, "template"), os.path.join(report_dir, "template"))
|
||||||
logger.info(f"Report was saved to {os.path.join(report_dir, 'report.html')}")
|
logger.info(f"Report was saved to {os.path.join(report_dir, 'report.html')}")
|
||||||
|
|
||||||
def start_pipeline(self, dump_models: bool):
|
def run(self, dump_models: bool):
|
||||||
command = f'{PIP_NAME} install -r {os.path.join(SCRIPT_DIR_PATH, "requirements.txt")}'
|
command = f'{constants.PIP_NAME} install -r {os.path.join(SCRIPT_DIR_PATH, "requirements.txt")}'
|
||||||
process = Popen(command, shell=True)
|
process = Popen(command, shell=True)
|
||||||
out, err = process.communicate()
|
out, err = process.communicate()
|
||||||
if err is None:
|
if err is None:
|
||||||
@ -296,16 +195,19 @@ class Conformance:
|
|||||||
logger.info(f"[ARGUMENTS] --ov_config_path = {self._ov_config_path}")
|
logger.info(f"[ARGUMENTS] --ov_config_path = {self._ov_config_path}")
|
||||||
logger.info(f"[ARGUMENTS] --dump_conformance = {dump_models}")
|
logger.info(f"[ARGUMENTS] --dump_conformance = {dump_models}")
|
||||||
|
|
||||||
|
if self._model_path == NO_MODEL_CONSTANT or file_utils.is_url(self._model_path):
|
||||||
|
self.__download_conformance_ir()
|
||||||
if dump_models:
|
if dump_models:
|
||||||
if self._model_path == NO_MODEL_CONSTANT:
|
self.__dump_subgraph()
|
||||||
self.download_and_convert_models()
|
if not os.path.exists(self._model_path):
|
||||||
self.dump_subgraph()
|
logger.error(f"The model direstory {self._model_path} does not exist!")
|
||||||
|
exit(-1)
|
||||||
if not os.path.exists(self._model_path):
|
if not os.path.exists(self._model_path):
|
||||||
logger.error(f"Directory {self._model_path} does not exist")
|
logger.error(f"Directory {self._model_path} does not exist")
|
||||||
exit(-1)
|
exit(-1)
|
||||||
xml_report, report_dir = self.run_conformance()
|
xml_report, report_dir = self.__run_conformance()
|
||||||
if self._type == "OP":
|
if self._type == "OP":
|
||||||
self.summarize(xml_report, report_dir)
|
self.__summarize(xml_report, report_dir)
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
args = parse_arguments()
|
args = parse_arguments()
|
||||||
@ -313,4 +215,4 @@ if __name__ == "__main__":
|
|||||||
args.ov_path, args.type,
|
args.ov_path, args.type,
|
||||||
args.workers, args.gtest_filter,
|
args.workers, args.gtest_filter,
|
||||||
args.working_dir, args.ov_config_path)
|
args.working_dir, args.ov_config_path)
|
||||||
conformance.start_pipeline(args.dump_conformance)
|
conformance.run(args.dump_conformance)
|
||||||
|
@ -1,13 +1,14 @@
|
|||||||
# Copyright (C) 2018-2023 Intel Corporation
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger, progressbar
|
||||||
|
from utils import constants
|
||||||
|
from utils import file_utils
|
||||||
from argparse import ArgumentParser
|
from argparse import ArgumentParser
|
||||||
from subprocess import Popen, STDOUT, TimeoutExpired
|
from subprocess import Popen, STDOUT, TimeoutExpired
|
||||||
from hashlib import sha256
|
from hashlib import sha256
|
||||||
from pathlib import Path
|
from pathlib import Path
|
||||||
from shutil import rmtree, copyfile
|
from shutil import rmtree
|
||||||
from zipfile import ZipFile, is_zipfile
|
|
||||||
|
|
||||||
import os
|
import os
|
||||||
import sys
|
import sys
|
||||||
@ -15,7 +16,6 @@ import threading
|
|||||||
import platform
|
import platform
|
||||||
import csv
|
import csv
|
||||||
import datetime
|
import datetime
|
||||||
import tarfile
|
|
||||||
|
|
||||||
if sys.version_info.major >= 3:
|
if sys.version_info.major >= 3:
|
||||||
import _thread as thread
|
import _thread as thread
|
||||||
@ -26,18 +26,8 @@ FILENAME_LENGTH = 255
|
|||||||
LOG_NAME_REPLACE_STR = "##NAME##"
|
LOG_NAME_REPLACE_STR = "##NAME##"
|
||||||
DEFAULT_PROCESS_TIMEOUT = 3600
|
DEFAULT_PROCESS_TIMEOUT = 3600
|
||||||
MAX_LENGHT = 4096 if platform.system() != "Windows" else 8191
|
MAX_LENGHT = 4096 if platform.system() != "Windows" else 8191
|
||||||
TEST_STATUS = {
|
|
||||||
'passed': ["[ OK ]"],
|
|
||||||
'failed': ["[ FAILED ]"],
|
|
||||||
'hanged': ["Test finished by timeout"],
|
|
||||||
'crashed': ["Unexpected application crash with code", "Segmentation fault", "Crash happens", "core dumped"],
|
|
||||||
'skipped': ["[ SKIPPED ]"],
|
|
||||||
'interapted': ["interapted", "Killed"]}
|
|
||||||
RUN = "[ RUN ]"
|
|
||||||
GTEST_FILTER = "Google Test filter = "
|
|
||||||
DISABLED_PREFIX = "DISABLED_"
|
|
||||||
|
|
||||||
logger = utils.get_logger('test_parallel_runner')
|
logger = get_logger('test_parallel_runner')
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
parser = ArgumentParser()
|
parser = ArgumentParser()
|
||||||
@ -160,32 +150,12 @@ class TestParallelRunner:
|
|||||||
self._cache_path = os.path.join(cache_path)
|
self._cache_path = os.path.join(cache_path)
|
||||||
head, _ = os.path.split(self._cache_path)
|
head, _ = os.path.split(self._cache_path)
|
||||||
if not os.path.exists(head):
|
if not os.path.exists(head):
|
||||||
|
pass
|
||||||
os.mkdir(head)
|
os.mkdir(head)
|
||||||
self._is_save_cache = True
|
self._is_save_cache = True
|
||||||
self._disabled_tests = list()
|
self._disabled_tests = list()
|
||||||
self._total_test_cnt = 0
|
self._total_test_cnt = 0
|
||||||
|
|
||||||
def __unzip_archieve(self, zip_path: os.path):
|
|
||||||
_, tail = os.path.split(zip_path)
|
|
||||||
dst_path = os.path.join(self._working_dir, tail)
|
|
||||||
copyfile(zip_path, dst_path)
|
|
||||||
logger.info(f"Archieve {zip_path} was copied to {dst_path}")
|
|
||||||
dst_dir, _ = os.path.splitext(dst_path)
|
|
||||||
if tarfile.is_tarfile(zip_path):
|
|
||||||
file = tarfile.open(dst_path)
|
|
||||||
file.extractall(dst_dir)
|
|
||||||
file.close()
|
|
||||||
elif is_zipfile(zip_path):
|
|
||||||
with ZipFile(dst_path, 'r') as zObject:
|
|
||||||
zObject.extractall(path=dst_dir)
|
|
||||||
else:
|
|
||||||
logger.error(f"Impossible to extract {zip_path}")
|
|
||||||
sys.exit(-1)
|
|
||||||
logger.info(f"Archieve {dst_path} was extacted to {dst_dir}")
|
|
||||||
os.remove(dst_path)
|
|
||||||
logger.info(f"Archieve {dst_path} was removed")
|
|
||||||
return dst_dir
|
|
||||||
|
|
||||||
|
|
||||||
def __init_basic_command_line_for_exec_file(self, test_command_line: list):
|
def __init_basic_command_line_for_exec_file(self, test_command_line: list):
|
||||||
command = f'{self._exec_file_path}'
|
command = f'{self._exec_file_path}'
|
||||||
@ -199,9 +169,9 @@ class TestParallelRunner:
|
|||||||
buf = ""
|
buf = ""
|
||||||
for _ in argument.split(','):
|
for _ in argument.split(','):
|
||||||
input_path = argument.replace('"', '')
|
input_path = argument.replace('"', '')
|
||||||
if os.path.isfile(input_path) and (tarfile.is_tarfile(input_path) or is_zipfile(input_path)):
|
if os.path.isfile(input_path) and file_utils.is_archieve(input_path):
|
||||||
input_path = self.__unzip_archieve(input_path)
|
input_path = file_utils.unzip_archieve(input_path, self._working_dir)
|
||||||
buf = utils.prepare_filelist(input_path, "*.xml", logger)
|
buf = file_utils.prepare_filelist(input_path, "*.xml")
|
||||||
buf += ","
|
buf += ","
|
||||||
argument = buf
|
argument = buf
|
||||||
else:
|
else:
|
||||||
@ -230,7 +200,7 @@ class TestParallelRunner:
|
|||||||
pos = test_name.find('#')
|
pos = test_name.find('#')
|
||||||
if pos > 0:
|
if pos > 0:
|
||||||
real_test_name = test_suite + test_name[2:pos-2]
|
real_test_name = test_suite + test_name[2:pos-2]
|
||||||
if DISABLED_PREFIX in real_test_name:
|
if constants.DISABLED_PREFIX in real_test_name:
|
||||||
self._disabled_tests.append(real_test_name)
|
self._disabled_tests.append(real_test_name)
|
||||||
else:
|
else:
|
||||||
test_list.append(f'"{self.__replace_restricted_symbols(real_test_name)}":')
|
test_list.append(f'"{self.__replace_restricted_symbols(real_test_name)}":')
|
||||||
@ -251,7 +221,7 @@ class TestParallelRunner:
|
|||||||
pos = line.find(":")
|
pos = line.find(":")
|
||||||
time = line[:pos]
|
time = line[:pos]
|
||||||
test_name = line[pos+1:]
|
test_name = line[pos+1:]
|
||||||
if not DISABLED_PREFIX in test_name:
|
if not constants.DISABLED_PREFIX in test_name:
|
||||||
test_list_cache.append(TestStructure(test_name.replace("\n", ""), time))
|
test_list_cache.append(TestStructure(test_name.replace("\n", ""), time))
|
||||||
logger.info(f"Len test_list_cache: {len(test_list_cache)}")
|
logger.info(f"Len test_list_cache: {len(test_list_cache)}")
|
||||||
return test_list_cache
|
return test_list_cache
|
||||||
@ -284,7 +254,7 @@ class TestParallelRunner:
|
|||||||
|
|
||||||
# Run crashed tests in a separed thread
|
# Run crashed tests in a separed thread
|
||||||
if idx < len(proved_test_list):
|
if idx < len(proved_test_list):
|
||||||
while proved_test_list[idx]._time == -1:
|
while proved_test_list[idx]._time == -1 :
|
||||||
proved_test_list.pop(idx)
|
proved_test_list.pop(idx)
|
||||||
if idx >= len(proved_test_list):
|
if idx >= len(proved_test_list):
|
||||||
break
|
break
|
||||||
@ -352,21 +322,6 @@ class TestParallelRunner:
|
|||||||
logger.info(f"Total test counter is {self._total_test_cnt}")
|
logger.info(f"Total test counter is {self._total_test_cnt}")
|
||||||
return final_test_list
|
return final_test_list
|
||||||
|
|
||||||
@staticmethod
|
|
||||||
def progressbar(it_num, message="", progress_bar_size=60, out=sys.stdout):
|
|
||||||
max_len = len(it_num)
|
|
||||||
if max_len == 0:
|
|
||||||
return
|
|
||||||
def show(sym_pos):
|
|
||||||
x = int(progress_bar_size * sym_pos / max_len)
|
|
||||||
print("{}[{}{}] {}/{}".format(message, "#"*x, "."*(progress_bar_size-x), sym_pos, max_len),
|
|
||||||
end='\r', file=out, flush=True)
|
|
||||||
show(0)
|
|
||||||
for i, item in enumerate(it_num):
|
|
||||||
yield item
|
|
||||||
show(i+1)
|
|
||||||
print("", flush=True, file=out)
|
|
||||||
|
|
||||||
def run(self):
|
def run(self):
|
||||||
if TaskManager.process_timeout == -1:
|
if TaskManager.process_timeout == -1:
|
||||||
TaskManager.process_timeout = DEFAULT_PROCESS_TIMEOUT
|
TaskManager.process_timeout = DEFAULT_PROCESS_TIMEOUT
|
||||||
@ -375,11 +330,9 @@ class TestParallelRunner:
|
|||||||
|
|
||||||
commands = [f'{self._command} --gtest_filter={filter}' for filter in self.__get_filters()]
|
commands = [f'{self._command} --gtest_filter={filter}' for filter in self.__get_filters()]
|
||||||
task_manager = TaskManager(commands, self._working_dir)
|
task_manager = TaskManager(commands, self._working_dir)
|
||||||
# from tqdm import tqdm
|
for _ in progressbar(range(self._worker_num), "Worker initialization: ", 40):
|
||||||
# for _ in tqdm(range(self._worker_num)):
|
|
||||||
for _ in self.progressbar(range(self._worker_num), "Worker initialization: ", 40):
|
|
||||||
task_manager.init_worker()
|
task_manager.init_worker()
|
||||||
for _ in self.progressbar(range(len(commands) - self._worker_num), "Worker execution: ", 40):
|
for _ in progressbar(range(len(commands) - self._worker_num), "Worker execution: ", 40):
|
||||||
if not task_manager.update_worker():
|
if not task_manager.update_worker():
|
||||||
break
|
break
|
||||||
task_manager.compelete_all_processes()
|
task_manager.compelete_all_processes()
|
||||||
@ -413,7 +366,7 @@ class TestParallelRunner:
|
|||||||
logger.info(f"Logs directory {logs_dir} is cleaned up")
|
logger.info(f"Logs directory {logs_dir} is cleaned up")
|
||||||
rmtree(logs_dir)
|
rmtree(logs_dir)
|
||||||
os.mkdir(logs_dir)
|
os.mkdir(logs_dir)
|
||||||
for test_st, _ in TEST_STATUS.items():
|
for test_st, _ in constants.TEST_STATUS.items():
|
||||||
if not os.path.exists(os.path.join(logs_dir, test_st)):
|
if not os.path.exists(os.path.join(logs_dir, test_st)):
|
||||||
os.mkdir(os.path.join(logs_dir, test_st))
|
os.mkdir(os.path.join(logs_dir, test_st))
|
||||||
hash_map = dict()
|
hash_map = dict()
|
||||||
@ -426,13 +379,13 @@ class TestParallelRunner:
|
|||||||
dir = None
|
dir = None
|
||||||
test_cnt_expected = test_cnt_real_saved_now = test_cnt_real_saved_before = 0
|
test_cnt_expected = test_cnt_real_saved_now = test_cnt_real_saved_before = 0
|
||||||
for line in log_file.readlines():
|
for line in log_file.readlines():
|
||||||
if GTEST_FILTER in line:
|
if constants.GTEST_FILTER in line:
|
||||||
line = line[line.find(GTEST_FILTER):]
|
line = line[line.find(constants.GTEST_FILTER):]
|
||||||
test_cnt_expected = line.count(':')
|
test_cnt_expected = line.count(':')
|
||||||
if RUN in line:
|
if constants.RUN in line:
|
||||||
test_name = line[line.find(RUN) + len(RUN) + 1:-1:]
|
test_name = line[line.find(constants.RUN) + len(constants.RUN) + 1:-1:]
|
||||||
if dir is None:
|
if dir is None:
|
||||||
for test_st, mes_list in TEST_STATUS.items():
|
for test_st, mes_list in constants.TEST_STATUS.items():
|
||||||
for mes in mes_list:
|
for mes in mes_list:
|
||||||
if mes in line:
|
if mes in line:
|
||||||
dir = test_st
|
dir = test_st
|
||||||
|
@ -9,7 +9,8 @@ from defusedxml import defuse_stdlib
|
|||||||
|
|
||||||
from jinja2 import Environment, FileSystemLoader
|
from jinja2 import Environment, FileSystemLoader
|
||||||
|
|
||||||
from utils import utils
|
from utils.conformance_utils import get_logger
|
||||||
|
from utils import stat_update_utils
|
||||||
|
|
||||||
# defuse_stdlib provide patched version of xml.etree.ElementTree which allows to use objects from xml.etree.ElementTree
|
# defuse_stdlib provide patched version of xml.etree.ElementTree which allows to use objects from xml.etree.ElementTree
|
||||||
# in a safe manner without including unsafe xml.etree.ElementTree
|
# in a safe manner without including unsafe xml.etree.ElementTree
|
||||||
@ -22,7 +23,7 @@ NA = "N/A"
|
|||||||
|
|
||||||
STATUS_CSV_ORDER = ["implemented", "passed", "failed", "skipped", "crashed", "hanged", "passrate"]
|
STATUS_CSV_ORDER = ["implemented", "passed", "failed", "skipped", "crashed", "hanged", "passrate"]
|
||||||
|
|
||||||
logger = utils.get_logger('Summarize')
|
logger = get_logger('conformance_summary')
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
def parse_arguments():
|
||||||
@ -104,7 +105,7 @@ def merge_xmls(xml_paths: list):
|
|||||||
device_results.find(current_op_res.tag).set(attr_name, str(xml_value))
|
device_results.find(current_op_res.tag).set(attr_name, str(xml_value))
|
||||||
else:
|
else:
|
||||||
device_results.append(op_result)
|
device_results.append(op_result)
|
||||||
utils.update_passrates(summary_results)
|
stat_update_utils.update_passrates(summary_results)
|
||||||
summary.set("timestamp", timestamp)
|
summary.set("timestamp", timestamp)
|
||||||
logger.info("Merging XML files is competed")
|
logger.info("Merging XML files is competed")
|
||||||
return summary
|
return summary
|
||||||
@ -228,8 +229,8 @@ def serialize_to_csv(report_filename: str, output_dir: os.path, op_list: list, d
|
|||||||
def create_summary(summary_root: Element, output_folder: os.path, expected_devices:list, report_tag: str, report_version: str,
|
def create_summary(summary_root: Element, output_folder: os.path, expected_devices:list, report_tag: str, report_version: str,
|
||||||
is_conformance_mode: bool, is_serialize_to_csv: bool, output_filename='report'):
|
is_conformance_mode: bool, is_serialize_to_csv: bool, output_filename='report'):
|
||||||
if is_conformance_mode:
|
if is_conformance_mode:
|
||||||
utils.update_conformance_test_counters(summary_root, logger)
|
stat_update_utils.update_conformance_test_counters(summary_root)
|
||||||
utils.update_passrates(summary_root.find("results"))
|
stat_update_utils.update_passrates(summary_root.find("results"))
|
||||||
device_list, results, general_pass_rate, pass_rate_avg, general_test_count, trusted_ops, covered_ops = \
|
device_list, results, general_pass_rate, pass_rate_avg, general_test_count, trusted_ops, covered_ops = \
|
||||||
collect_statistic(summary_root, is_conformance_mode)
|
collect_statistic(summary_root, is_conformance_mode)
|
||||||
|
|
||||||
|
@ -0,0 +1,40 @@
|
|||||||
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import logging
|
||||||
|
|
||||||
|
from sys import stdout
|
||||||
|
from os import environ
|
||||||
|
|
||||||
|
from . import constants
|
||||||
|
|
||||||
|
def get_logger(app_name: str):
|
||||||
|
logging.basicConfig()
|
||||||
|
logger = logging.getLogger(app_name)
|
||||||
|
logger.setLevel(logging.INFO)
|
||||||
|
return logger
|
||||||
|
|
||||||
|
UTILS_LOGGER = get_logger('conformance_utilities')
|
||||||
|
|
||||||
|
|
||||||
|
def progressbar(it_num, message="", progress_bar_size=60, out=stdout):
|
||||||
|
max_len = len(it_num)
|
||||||
|
if max_len == 0:
|
||||||
|
return
|
||||||
|
def show(sym_pos):
|
||||||
|
x = int(progress_bar_size * sym_pos / max_len)
|
||||||
|
print("{}[{}{}] {}/{}".format(message, "#"*x, "."*(progress_bar_size-x), sym_pos, max_len),
|
||||||
|
end='\r', file=out, flush=True)
|
||||||
|
show(0)
|
||||||
|
for i, item in enumerate(it_num):
|
||||||
|
yield item
|
||||||
|
show(i+1)
|
||||||
|
print("", flush=True, file=out)
|
||||||
|
|
||||||
|
|
||||||
|
def set_env_variable(env: environ, var_name: str, var_value: str):
|
||||||
|
if var_name in env and not var_value in env[var_name]:
|
||||||
|
env[var_name] = var_value + constants.ENV_SEPARATOR + env[var_name]
|
||||||
|
else:
|
||||||
|
env[var_name] = var_value
|
||||||
|
return env
|
@ -0,0 +1,33 @@
|
|||||||
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
from sys import platform
|
||||||
|
|
||||||
|
TEST_STATUS = {
|
||||||
|
'passed': ["[ OK ]"],
|
||||||
|
'failed': ["[ FAILED ]"],
|
||||||
|
'hanged': ["Test finished by timeout"],
|
||||||
|
'crashed': ["Unexpected application crash with code", "Segmentation fault", "Crash happens", "core dumped"],
|
||||||
|
'skipped': ["[ SKIPPED ]"],
|
||||||
|
'interapted': ["interapted", "Killed"]}
|
||||||
|
RUN = "[ RUN ]"
|
||||||
|
GTEST_FILTER = "Google Test filter = "
|
||||||
|
DISABLED_PREFIX = "DISABLED_"
|
||||||
|
|
||||||
|
IS_WIN = "windows" in platform or "win32" in platform
|
||||||
|
|
||||||
|
OS_SCRIPT_EXT = ".bat" if IS_WIN else ""
|
||||||
|
OS_BIN_FILE_EXT = ".exe" if IS_WIN else ""
|
||||||
|
ENV_SEPARATOR = ";" if IS_WIN else ":"
|
||||||
|
PYTHON_NAME = "python" if IS_WIN else "python3"
|
||||||
|
PIP_NAME = "pip" if IS_WIN else "pip3"
|
||||||
|
LD_LIB_PATH_NAME = "PATH" if IS_WIN or platform == "darwin" else "LD_LIBRARY_PATH"
|
||||||
|
|
||||||
|
OPENVINO_NAME = 'openvino'
|
||||||
|
PY_OPENVINO = "python_api"
|
||||||
|
|
||||||
|
DEBUG_DIR = "Debug"
|
||||||
|
RELEASE_DIR = "Release"
|
||||||
|
|
||||||
|
OP_CONFORMANCE = "OP"
|
||||||
|
API_CONFORMANCE = "API"
|
@ -0,0 +1,91 @@
|
|||||||
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
|
import os
|
||||||
|
import tarfile
|
||||||
|
|
||||||
|
from pathlib import Path, PurePath
|
||||||
|
from shutil import copyfile
|
||||||
|
from zipfile import ZipFile, is_zipfile
|
||||||
|
from urllib.parse import urlparse
|
||||||
|
|
||||||
|
from . import constants
|
||||||
|
from . import conformance_utils
|
||||||
|
|
||||||
|
# generates file list file inside directory. Returns path to saved filelist
|
||||||
|
def prepare_filelist(input_dir: os.path, pattern: str):
|
||||||
|
filelist_path = input_dir
|
||||||
|
if os.path.isdir(filelist_path):
|
||||||
|
filelist_path = os.path.join(input_dir, "conformance_ir_files.lst")
|
||||||
|
elif os.path.isfile(filelist_path):
|
||||||
|
head, _ = os.path.split(filelist_path)
|
||||||
|
input_dir = head
|
||||||
|
if os.path.isfile(filelist_path):
|
||||||
|
conformance_utils.UTILS_LOGGER.info(f"{filelist_path} is exists! The script will update it!")
|
||||||
|
xmls = Path(input_dir).rglob(pattern)
|
||||||
|
try:
|
||||||
|
with open(filelist_path, 'w') as file:
|
||||||
|
for xml in xmls:
|
||||||
|
file.write(str(xml) + '\n')
|
||||||
|
file.close()
|
||||||
|
except:
|
||||||
|
conformance_utils.UTILS_LOGGER.warning(f"Impossible to update {filelist_path}! Something going is wrong!")
|
||||||
|
return filelist_path
|
||||||
|
|
||||||
|
def is_archieve(input_path: os.path):
|
||||||
|
return tarfile.is_tarfile(input_path) or is_zipfile(input_path)
|
||||||
|
|
||||||
|
def is_url(url: str):
|
||||||
|
try:
|
||||||
|
result = urlparse(url)
|
||||||
|
return all([result.scheme, result.netloc])
|
||||||
|
except:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def unzip_archieve(zip_path: os.path, dst_path: os.path):
|
||||||
|
_, tail = os.path.split(zip_path)
|
||||||
|
dst_path = os.path.join(dst_path, tail)
|
||||||
|
if zip_path != dst_path:
|
||||||
|
copyfile(zip_path, dst_path)
|
||||||
|
conformance_utils.UTILS_LOGGER.info(f"Archieve {zip_path} was copied to {dst_path}")
|
||||||
|
dst_dir, _ = os.path.splitext(dst_path)
|
||||||
|
if tarfile.is_tarfile(zip_path):
|
||||||
|
file = tarfile.open(dst_path)
|
||||||
|
file.extractall(dst_dir)
|
||||||
|
file.close()
|
||||||
|
elif is_zipfile(zip_path):
|
||||||
|
with ZipFile(dst_path, 'r') as zObject:
|
||||||
|
zObject.extractall(path=dst_dir)
|
||||||
|
else:
|
||||||
|
conformance_utils.UTILS_LOGGER.error(f"Impossible to extract {zip_path}")
|
||||||
|
exit(-1)
|
||||||
|
conformance_utils.UTILS_LOGGER.info(f"Archieve {dst_path} was extacted to {dst_dir}")
|
||||||
|
os.remove(dst_path)
|
||||||
|
conformance_utils.UTILS_LOGGER.info(f"Archieve {dst_path} was removed")
|
||||||
|
return dst_dir
|
||||||
|
|
||||||
|
# find latest changed directory
|
||||||
|
def find_latest_dir(in_dir: Path, pattern_list = list()):
|
||||||
|
get_latest_dir = lambda path: sorted(Path(path).iterdir(), key=os.path.getmtime)
|
||||||
|
entities = get_latest_dir(in_dir)
|
||||||
|
entities.reverse()
|
||||||
|
|
||||||
|
for entity in entities:
|
||||||
|
if entity.is_dir():
|
||||||
|
if not pattern_list:
|
||||||
|
return entity
|
||||||
|
else:
|
||||||
|
for pattern in pattern_list:
|
||||||
|
if pattern in str(os.fspath(PurePath(entity))):
|
||||||
|
return entity
|
||||||
|
conformance_utils.UTILS_LOGGER.error(f"{in_dir} does not contain applicable directories to patterns: {pattern_list}")
|
||||||
|
exit(-1)
|
||||||
|
|
||||||
|
def get_ov_path(script_dir_path: os.path, ov_dir=None, is_bin=False):
|
||||||
|
if ov_dir is None or not os.path.isdir(ov_dir):
|
||||||
|
ov_dir = os.path.abspath(script_dir_path)[:os.path.abspath(script_dir_path).find(constants.OPENVINO_NAME) + len(constants.OPENVINO_NAME)]
|
||||||
|
if is_bin:
|
||||||
|
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir, ['bin']))
|
||||||
|
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir))
|
||||||
|
ov_dir = os.path.join(ov_dir, find_latest_dir(ov_dir, [constants.DEBUG_DIR, constants.RELEASE_DIR]))
|
||||||
|
return ov_dir
|
@ -1,20 +1,9 @@
|
|||||||
# Copyright (C) 2018-2023 Intel Corporation
|
# Copyright (C) 2018-2023 Intel Corporation
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
# SPDX-License-Identifier: Apache-2.0
|
||||||
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import xml.etree.ElementTree as ET
|
import xml.etree.ElementTree as ET
|
||||||
from pathlib import Path
|
|
||||||
|
|
||||||
TEST_STATUS = {'passed': "[ OK ]", 'failed': "[ FAILED ]", 'hanged': "Test finished by timeout", 'crashed': "Crash happens", 'skipped': "[ SKIPPED ]", "interapted": "interapted"}
|
|
||||||
RUN = "[ RUN ]"
|
|
||||||
|
|
||||||
def get_logger(app_name: str):
|
|
||||||
logging.basicConfig()
|
|
||||||
logger = logging.getLogger(app_name)
|
|
||||||
logger.setLevel(logging.INFO)
|
|
||||||
return logger
|
|
||||||
|
|
||||||
|
from . import conformance_utils
|
||||||
|
|
||||||
def update_passrates(results: ET.SubElement):
|
def update_passrates(results: ET.SubElement):
|
||||||
for device in results:
|
for device in results:
|
||||||
@ -36,7 +25,7 @@ def update_passrates(results: ET.SubElement):
|
|||||||
op.set("passrate", str(round(passrate, 1)))
|
op.set("passrate", str(round(passrate, 1)))
|
||||||
|
|
||||||
|
|
||||||
def update_conformance_test_counters(results: ET.SubElement, logger: logging.Logger):
|
def update_conformance_test_counters(results: ET.SubElement):
|
||||||
max_test_cnt = dict()
|
max_test_cnt = dict()
|
||||||
incorrect_ops = set()
|
incorrect_ops = set()
|
||||||
for device in results.find("results"):
|
for device in results.find("results"):
|
||||||
@ -63,24 +52,6 @@ def update_conformance_test_counters(results: ET.SubElement, logger: logging.Log
|
|||||||
if test_cnt != max_test_cnt[op.tag]:
|
if test_cnt != max_test_cnt[op.tag]:
|
||||||
diff = max_test_cnt[op.tag] - test_cnt
|
diff = max_test_cnt[op.tag] - test_cnt
|
||||||
op.set("skipped", str(int(op.attrib["skipped"]) + diff))
|
op.set("skipped", str(int(op.attrib["skipped"]) + diff))
|
||||||
logger.warning(f'{device.tag}: added {diff} skipped tests for {op.tag}')
|
conformance_utils.UTILS_LOGGER.warning(f'{device.tag}: added {diff} skipped tests for {op.tag}')
|
||||||
update_passrates(results)
|
update_passrates(results)
|
||||||
|
|
||||||
def prepare_filelist(input_dir: os.path, pattern: str, logger):
|
|
||||||
filelist_path = input_dir
|
|
||||||
if os.path.isdir(filelist_path):
|
|
||||||
filelist_path = os.path.join(input_dir, "conformance_ir_files.lst")
|
|
||||||
elif os.path.isfile(filelist_path):
|
|
||||||
head, _ = os.path.split(filelist_path)
|
|
||||||
input_dir = head
|
|
||||||
if os.path.isfile(filelist_path):
|
|
||||||
logger.info(f"{filelist_path} is exists! The script will update it!")
|
|
||||||
xmls = Path(input_dir).rglob(pattern)
|
|
||||||
try:
|
|
||||||
with open(filelist_path, 'w') as file:
|
|
||||||
for xml in xmls:
|
|
||||||
file.write(str(xml) + '\n')
|
|
||||||
file.close()
|
|
||||||
except:
|
|
||||||
logger.warning(f"Impossible to update {filelist_path}! Something going is wrong!")
|
|
||||||
return filelist_path
|
|
@ -1,96 +0,0 @@
|
|||||||
# Copyright (C) 2018-2023 Intel Corporation
|
|
||||||
# SPDX-License-Identifier: Apache-2.0
|
|
||||||
|
|
||||||
import os
|
|
||||||
import glob
|
|
||||||
import argparse
|
|
||||||
|
|
||||||
|
|
||||||
def parse_arguments():
|
|
||||||
parser = argparse.ArgumentParser()
|
|
||||||
|
|
||||||
skip_config_help = "Paths to folder with skip_config_files"
|
|
||||||
input_folders_help = "Paths to folders with logs"
|
|
||||||
extend_file_help = "Extend exiting file"
|
|
||||||
|
|
||||||
parser.add_argument("-s", "--skip_config_folders", help=skip_config_help, nargs='*', required=True)
|
|
||||||
parser.add_argument("-i", "--input_logs", help=input_folders_help, nargs='*', required=True)
|
|
||||||
parser.add_argument("-e", "--extend_file", help=extend_file_help, default=False, required=False)
|
|
||||||
|
|
||||||
return parser.parse_args()
|
|
||||||
|
|
||||||
|
|
||||||
def is_conformance(content: str):
|
|
||||||
if 'conformance' in content:
|
|
||||||
return True
|
|
||||||
return False
|
|
||||||
|
|
||||||
|
|
||||||
def is_hung_test(content: str):
|
|
||||||
if content == '' or \
|
|
||||||
"SKIPPED" in content or \
|
|
||||||
"FAILED" in content or \
|
|
||||||
"Unexpected application crash!" in content or \
|
|
||||||
"PASSED" in content:
|
|
||||||
return False
|
|
||||||
return True
|
|
||||||
|
|
||||||
|
|
||||||
def get_device_name(content: str):
|
|
||||||
target_device_str = 'TargetDevice='
|
|
||||||
pos_start = content.find(target_device_str)
|
|
||||||
pos_end = content.find('\n')
|
|
||||||
return f'{content[pos_start + len(target_device_str):pos_end]}'.lower()
|
|
||||||
|
|
||||||
|
|
||||||
def get_regex(content: str):
|
|
||||||
ir_name_str = 'IR_name='
|
|
||||||
pos_start = content.find(ir_name_str)
|
|
||||||
pos_end = content.find('.xml_')
|
|
||||||
return f'.*{content[pos_start + len(ir_name_str):pos_end]}.*\n'
|
|
||||||
|
|
||||||
|
|
||||||
def get_conformance_hung_test(test_log_dirs: list):
|
|
||||||
regexp = dict()
|
|
||||||
for test_log_dir in test_log_dirs:
|
|
||||||
if not os.path.isdir(test_log_dir):
|
|
||||||
continue
|
|
||||||
for log_file in glob.glob(os.path.join(test_log_dir, '*/*')):
|
|
||||||
with open(log_file) as log:
|
|
||||||
content = log.read()
|
|
||||||
if not (is_hung_test(content) and is_conformance(content))::
|
|
||||||
print(log_file)
|
|
||||||
continue
|
|
||||||
device = get_device_name(content)
|
|
||||||
if 'arm' in content or 'arm' in log_file:
|
|
||||||
device = 'arm'
|
|
||||||
if not device in regexp.keys():
|
|
||||||
regexp.update({device: []})
|
|
||||||
if get_regex(content) in regexp[device]:
|
|
||||||
continue
|
|
||||||
regexp[device].append(get_regex(content))
|
|
||||||
for device, re_list in regexp.items():
|
|
||||||
re_list.sort()
|
|
||||||
return regexp
|
|
||||||
|
|
||||||
|
|
||||||
def save_to_file(skip_folder_paths: list, regexps: dict, extend_file: str):
|
|
||||||
for skip_folder_path in skip_folder_paths:
|
|
||||||
if not os.path.isdir(skip_folder_path):
|
|
||||||
continue
|
|
||||||
skip_files_paths = glob.glob(os.path.join(skip_folder_path, 'skip_config_*.lst'))
|
|
||||||
for skip_files_path in skip_files_paths:
|
|
||||||
for device, re_list in regexps.items():
|
|
||||||
if device in skip_files_path:
|
|
||||||
if extend_file:
|
|
||||||
with open(skip_files_path, 'r') as file:
|
|
||||||
content = file.readlines()
|
|
||||||
with open(skip_files_path, 'w') as file:
|
|
||||||
if extend_file:
|
|
||||||
file.writelines(content)
|
|
||||||
file.writelines(re_list)
|
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
|
||||||
args = parse_arguments()
|
|
||||||
save_to_file(args.skip_config_folders, get_conformance_hung_test(args.input_logs), args.extend_file)
|
|
Loading…
Reference in New Issue
Block a user