| @@ -91,4 +91,5 @@ class ExplainJobEncap(ExplainDataEncap): | |||||
| saliency_info["metrics"] = list(job.metrics) | saliency_info["metrics"] = list(job.metrics) | ||||
| info["saliency"] = saliency_info | info["saliency"] = saliency_info | ||||
| info["uncertainty"] = {"enabled": job.uncertainty_enabled} | info["uncertainty"] = {"enabled": job.uncertainty_enabled} | ||||
| info["status"] = job.status | |||||
| return info | return info | ||||
| @@ -1,4 +1,4 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # Copyright 2020-2021 Huawei Technologies Co., Ltd | |||||
| # | # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | # you may not use this file except in compliance with the License. | ||||
| @@ -50,6 +50,8 @@ _SAMPLE_FIELD_NAMES = [ | |||||
| class _LoaderStatus(Enum): | class _LoaderStatus(Enum): | ||||
| STOP = 'STOP' | STOP = 'STOP' | ||||
| LOADING = 'LOADING' | LOADING = 'LOADING' | ||||
| PENDING = 'PENDING' | |||||
| LOADED = 'LOADED' | |||||
| def _round(score): | def _round(score): | ||||
| @@ -75,13 +77,13 @@ class ExplainLoader: | |||||
| 'create_time': os.stat(summary_dir).st_ctime, | 'create_time': os.stat(summary_dir).st_ctime, | ||||
| 'update_time': os.stat(summary_dir).st_mtime, | 'update_time': os.stat(summary_dir).st_mtime, | ||||
| 'query_time': os.stat(summary_dir).st_ctime, | 'query_time': os.stat(summary_dir).st_ctime, | ||||
| 'uncertainty_enabled': False | |||||
| 'uncertainty_enabled': False, | |||||
| } | } | ||||
| self._samples = defaultdict(dict) | self._samples = defaultdict(dict) | ||||
| self._metadata = {'explainers': [], 'metrics': [], 'labels': [], 'min_confidence': 0.5} | self._metadata = {'explainers': [], 'metrics': [], 'labels': [], 'min_confidence': 0.5} | ||||
| self._benchmark = {'explainer_score': defaultdict(dict), 'label_score': defaultdict(dict)} | self._benchmark = {'explainer_score': defaultdict(dict), 'label_score': defaultdict(dict)} | ||||
| self._status = _LoaderStatus.STOP.value | |||||
| self._status = _LoaderStatus.PENDING.value | |||||
| self._status_mutex = threading.Lock() | self._status_mutex = threading.Lock() | ||||
| @property | @property | ||||
| @@ -270,7 +272,9 @@ class ExplainLoader: | |||||
| def load(self): | def load(self): | ||||
| """Start loading data from the latest summary file to the loader.""" | """Start loading data from the latest summary file to the loader.""" | ||||
| self.status = _LoaderStatus.LOADING.value | |||||
| if self.status != _LoaderStatus.LOADED.value: | |||||
| self.status = _LoaderStatus.LOADING.value | |||||
| filenames = [] | filenames = [] | ||||
| for filename in FileHandler.list_dir(self._loader_info['summary_dir']): | for filename in FileHandler.list_dir(self._loader_info['summary_dir']): | ||||
| if FileHandler.is_file(FileHandler.join(self._loader_info['summary_dir'], filename)): | if FileHandler.is_file(FileHandler.join(self._loader_info['summary_dir'], filename)): | ||||
| @@ -286,15 +290,20 @@ class ExplainLoader: | |||||
| try: | try: | ||||
| file_changed, is_end, event_dict = self._parser.list_events(filenames) | file_changed, is_end, event_dict = self._parser.list_events(filenames) | ||||
| except UnknownError: | except UnknownError: | ||||
| is_end = True | |||||
| break | break | ||||
| if file_changed: | if file_changed: | ||||
| logger.info('Summary file in %s update, reload the data in the summary.', | logger.info('Summary file in %s update, reload the data in the summary.', | ||||
| self._loader_info['summary_dir']) | self._loader_info['summary_dir']) | ||||
| self._clear_job() | self._clear_job() | ||||
| if self.status != _LoaderStatus.STOP.value: | |||||
| self.status = _LoaderStatus.LOADING.value | |||||
| if event_dict: | if event_dict: | ||||
| self._import_data_from_event(event_dict) | self._import_data_from_event(event_dict) | ||||
| self._reform_sample_info() | self._reform_sample_info() | ||||
| if is_end: | |||||
| self.status = _LoaderStatus.LOADED.value | |||||
| @property | @property | ||||
| def status(self): | def status(self): | ||||
| @@ -1,4 +1,4 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # Copyright 2020-2021 Huawei Technologies Co., Ltd | |||||
| # | # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | # you may not use this file except in compliance with the License. | ||||
| @@ -27,7 +27,7 @@ from mindinsight.datavisual.common.enums import BaseEnum | |||||
| from mindinsight.datavisual.data_access.file_handler import FileHandler | from mindinsight.datavisual.data_access.file_handler import FileHandler | ||||
| from mindinsight.datavisual.data_transform.summary_watcher import SummaryWatcher | from mindinsight.datavisual.data_transform.summary_watcher import SummaryWatcher | ||||
| from mindinsight.explainer.common.log import logger | from mindinsight.explainer.common.log import logger | ||||
| from mindinsight.explainer.manager.explain_loader import ExplainLoader | |||||
| from mindinsight.explainer.manager.explain_loader import ExplainLoader, _LoaderStatus | |||||
| from mindinsight.utils.exceptions import ParamValueError, UnknownError | from mindinsight.utils.exceptions import ParamValueError, UnknownError | ||||
| _MAX_LOADERS_NUM = 3 | _MAX_LOADERS_NUM = 3 | ||||
| @@ -91,6 +91,9 @@ class ExplainManager: | |||||
| if loader_id in self._loader_pool: | if loader_id in self._loader_pool: | ||||
| self._loader_pool[loader_id].query_time = datetime.now().timestamp() | self._loader_pool[loader_id].query_time = datetime.now().timestamp() | ||||
| self._loader_pool.move_to_end(loader_id, last=True) | self._loader_pool.move_to_end(loader_id, last=True) | ||||
| loader = self._loader_pool[loader_id] | |||||
| if loader.status == _LoaderStatus.STOP.value: | |||||
| self._reload_data_again() | |||||
| return self._loader_pool[loader_id] | return self._loader_pool[loader_id] | ||||
| try: | try: | ||||
| @@ -1,4 +1,4 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # Copyright 2020-2021 Huawei Technologies Co., Ltd | |||||
| # | # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | # you may not use this file except in compliance with the License. | ||||
| @@ -16,6 +16,7 @@ | |||||
| from datetime import datetime | from datetime import datetime | ||||
| from mindinsight.explainer.encapsulator.explain_job_encap import ExplainJobEncap | from mindinsight.explainer.encapsulator.explain_job_encap import ExplainJobEncap | ||||
| from mindinsight.explainer.manager.explain_loader import _LoaderStatus | |||||
| class MockExplainJob: | class MockExplainJob: | ||||
| @@ -60,6 +61,7 @@ class MockExplainJob: | |||||
| ] | ] | ||||
| } | } | ||||
| ] | ] | ||||
| self.status = _LoaderStatus.LOADED.value | |||||
| def retrieve_image(self, image_id): | def retrieve_image(self, image_id): | ||||
| """Get original image binary.""" | """Get original image binary.""" | ||||
| @@ -1,4 +1,4 @@ | |||||
| # Copyright 2020 Huawei Technologies Co., Ltd | |||||
| # Copyright 2020-2021 Huawei Technologies Co., Ltd | |||||
| # | # | ||||
| # Licensed under the Apache License, Version 2.0 (the "License"); | # Licensed under the Apache License, Version 2.0 (the "License"); | ||||
| # you may not use this file except in compliance with the License. | # you may not use this file except in compliance with the License. | ||||
| @@ -24,6 +24,12 @@ from mindinsight.explainer.manager.explain_loader import _LoaderStatus | |||||
| from mindinsight.explainer.manager.explain_parser import ExplainParser | from mindinsight.explainer.manager.explain_parser import ExplainParser | ||||
| class _MockStat: | |||||
| def __init__(self, _): | |||||
| self.st_ctime = 1 | |||||
| self.st_mtime = 1 | |||||
| self.st_size = 1 | |||||
| class TestExplainLoader: | class TestExplainLoader: | ||||
| """Test explain loader class.""" | """Test explain loader class.""" | ||||
| @@ -37,11 +43,6 @@ class TestExplainLoader: | |||||
| mock_list_dir.return_value = ['events.summary.123.host_explain'] | mock_list_dir.return_value = ['events.summary.123.host_explain'] | ||||
| mock_list_events.return_value = (True, False, None) | mock_list_events.return_value = (True, False, None) | ||||
| class _MockStat: | |||||
| def __init__(self, _): | |||||
| self.st_ctime = 1 | |||||
| self.st_mtime = 1 | |||||
| self.st_size = 1 | |||||
| mock_stat.side_effect = _MockStat | mock_stat.side_effect = _MockStat | ||||
| @@ -50,8 +51,8 @@ class TestExplainLoader: | |||||
| summary_dir='./summary_dir') | summary_dir='./summary_dir') | ||||
| def _stop_loader(explain_loader): | def _stop_loader(explain_loader): | ||||
| time.sleep(0.01) | |||||
| assert explain_loader.status == _LoaderStatus.LOADING.value | |||||
| while explain_loader.status != _LoaderStatus.LOADING.value: | |||||
| time.sleep(0.01) | |||||
| explain_loader.stop() | explain_loader.stop() | ||||
| thread = threading.Thread(target=_stop_loader, args=[loader], daemon=True) | thread = threading.Thread(target=_stop_loader, args=[loader], daemon=True) | ||||
| @@ -59,3 +60,22 @@ class TestExplainLoader: | |||||
| loader.load() | loader.load() | ||||
| assert loader.status == _LoaderStatus.STOP.value | assert loader.status == _LoaderStatus.STOP.value | ||||
| @patch.object(ExplainParser, 'list_events') | |||||
| @patch.object(FileHandler, 'list_dir') | |||||
| @patch.object(FileHandler, 'is_file') | |||||
| @patch.object(os, 'stat') | |||||
| def test_loaded_with_is_end(self, mock_stat, mock_is_file, mock_list_dir, mock_list_events): | |||||
| """Test loading function.""" | |||||
| mock_is_file.return_value = True | |||||
| mock_list_dir.return_value = ['events.summary.123.host_explain'] | |||||
| mock_list_events.return_value = (True, True, None) | |||||
| mock_stat.side_effect = _MockStat | |||||
| loader = ExplainLoader( | |||||
| loader_id='./summary_dir', | |||||
| summary_dir='./summary_dir') | |||||
| loader.load() | |||||
| assert loader.status == _LoaderStatus.LOADED.value | |||||