Browse Source

deugger: add ut for graph and watch point

tags/v1.1.0
zhangyunshu 5 years ago
parent
commit
7a1d5fb0fd
12 changed files with 324 additions and 49 deletions
  1. +15
    -0
      tests/ut/debugger/__init__.py
  2. +95
    -0
      tests/ut/debugger/configurations.py
  3. +1
    -0
      tests/ut/debugger/expected_results/graph/graph_handler_get_1_no_filter_condintion.json
  4. +1
    -0
      tests/ut/debugger/expected_results/graph/graph_handler_get_2_list_nodes.json
  5. +0
    -0
      tests/ut/debugger/expected_results/graph/graph_handler_get_3_single_node.json
  6. +0
    -0
      tests/ut/debugger/expected_results/graph/search_node_1.json
  7. +1
    -0
      tests/ut/debugger/expected_results/graph/search_nodes_0.json
  8. +0
    -0
      tests/ut/debugger/expected_results/graph/tenor_hist_0.json
  9. +0
    -0
      tests/ut/debugger/expected_results/graph/tensor_hist_1.json
  10. +15
    -0
      tests/ut/debugger/stream_handler/__init__.py
  11. +13
    -49
      tests/ut/debugger/stream_handler/test_graph_handler.py
  12. +183
    -0
      tests/ut/debugger/stream_handler/test_watchpoint_handler.py

+ 15
- 0
tests/ut/debugger/__init__.py View File

@@ -0,0 +1,15 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Test for debugger module."""

+ 95
- 0
tests/ut/debugger/configurations.py View File

@@ -0,0 +1,95 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Common configurations for debugger unit testing."""
import json
import os

from google.protobuf import json_format

from mindinsight.debugger.proto import ms_graph_pb2
from mindinsight.debugger.stream_handler.graph_handler import GraphHandler

graph_proto_file = os.path.join(
os.path.dirname(__file__), '../../utils/resource/graph_pb/lenet.pb'
)


def get_graph_proto():
"""Get graph proto."""
with open(graph_proto_file, 'rb') as f:
content = f.read()

graph = ms_graph_pb2.GraphProto()
graph.ParseFromString(content)

return graph


def init_graph_handler():
"""Init graph proto."""
graph = get_graph_proto()
graph_handler = GraphHandler()
graph_handler.put(graph)

return graph_handler


def mock_tensor_proto():
"""Mock tensor proto."""
tensor_dict = {
"node_name":
"Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/gradReLU/ReluGradV2-op92",
"slot": "0"
}
tensor_proto = json_format.Parse(json.dumps(tensor_dict), ms_graph_pb2.TensorProto())

return tensor_proto


def mock_tensor_history():
"""Mock tensor history."""
tensor_history = {
"tensor_history": [
{"name": "Default/TransData-op99:0",
"full_name": "Default/TransData-op99:0",
"node_type": "TransData",
"type": "output",
"step": 0,
"dtype": "DT_FLOAT32",
"shape": [2, 3],
"has_prev_step": False,
"value": "click to view"},
{"name": "Default/args0:0",
"full_name": "Default/args0:0",
"node_type": "Parameter",
"type": "input",
"step": 0,
"dtype": "DT_FLOAT32",
"shape": [2, 3],
"has_prev_step": False,
"value": "click to view"}
],
"metadata": {
"state": "waiting",
"step": 0,
"device_name": "0",
"pos": "0",
"ip": "127.0.0.1:57492",
"node_name": "",
"backend": "Ascend"
}
}

return tensor_history

+ 1
- 0
tests/ut/debugger/expected_results/graph/graph_handler_get_1_no_filter_condintion.json
File diff suppressed because it is too large
View File


+ 1
- 0
tests/ut/debugger/expected_results/graph/graph_handler_get_2_list_nodes.json
File diff suppressed because it is too large
View File


tests/st/func/debugger/expect_results/graph_handler_get_3_single_node.json → tests/ut/debugger/expected_results/graph/graph_handler_get_3_single_node.json View File


tests/st/func/debugger/expect_results/search_node_1.json → tests/ut/debugger/expected_results/graph/search_node_1.json View File


+ 1
- 0
tests/ut/debugger/expected_results/graph/search_nodes_0.json View File

@@ -0,0 +1 @@
{"nodes": [{"name": "Default", "type": null, "nodes": [{"name": "Default/network-WithLossCell", "type": null, "nodes": [{"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits", "type": null, "nodes": [{"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/OneHot-op0", "type": "OneHot", "nodes": []}, {"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/SoftmaxCrossEntropyWithLogits-op18", "type": "SoftmaxCrossEntropyWithLogits", "nodes": []}, {"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/ReduceMean-op60", "type": "ReduceMean", "nodes": []}, {"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/args1", "type": "Parameter", "nodes": []}, {"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/cst1", "type": "Const", "nodes": []}, {"name": "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/cst2", "type": "Const", "nodes": []}]}]}]}, {"name": "Gradients", "type": null, "nodes": [{"name": "Gradients/Default", "type": null, "nodes": [{"name": "Gradients/Default/network-WithLossCell", "type": null, "nodes": [{"name": "Gradients/Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits", "type": null, "nodes": [{"name": "Gradients/Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/gradSoftmaxCrossEntropyWithLogits", "type": null, "nodes": [{"name": "Gradients/Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/gradSoftmaxCrossEntropyWithLogits/Mul-op20", "type": "Mul", "nodes": []}, {"name": "Gradients/Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/gradSoftmaxCrossEntropyWithLogits/cst8", "type": "Const", "nodes": []}]}]}]}]}]}]}

tests/st/func/debugger/expect_results/tenor_hist_0.json → tests/ut/debugger/expected_results/graph/tenor_hist_0.json View File


tests/st/func/debugger/expect_results/tensor_hist_1.json → tests/ut/debugger/expected_results/graph/tensor_hist_1.json View File


+ 15
- 0
tests/ut/debugger/stream_handler/__init__.py View File

@@ -0,0 +1,15 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Test for debugger stream handler."""

tests/st/func/debugger/test_graph_handler.py → tests/ut/debugger/stream_handler/test_graph_handler.py View File

@@ -16,31 +16,30 @@
Function: Function:
Test query debugger graph handler. Test query debugger graph handler.
Usage: Usage:
pytest tests/st/func/debugger/test_graph_handler.py
pytest tests/ut/debugger
""" """
import os import os


import pytest import pytest


from ....utils.tools import compare_result_with_file
from .conftest import init_graph_handler
from tests.ut.debugger.configurations import init_graph_handler
from tests.utils.tools import compare_result_with_file




class TestGraphHandler: class TestGraphHandler:
"""Test GraphHandler.""" """Test GraphHandler."""
graph_results_dir = os.path.join(os.path.dirname(__file__), 'expect_results')
graph_handler = init_graph_handler()
@classmethod
def setup_class(cls):
"""Init WatchpointHandler for watchpoint unittest."""
cls.graph_results_dir = os.path.join(os.path.dirname(__file__),
'../expected_results/graph')
cls.graph_handler = init_graph_handler()


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("filter_condition, result_file", [ @pytest.mark.parametrize("filter_condition, result_file", [
(None, "graph_handler_get_1_no_filter_condintion.json"), (None, "graph_handler_get_1_no_filter_condintion.json"),
({'name': 'Default'}, "graph_handler_get_2_list_nodes.json"), ({'name': 'Default'}, "graph_handler_get_2_list_nodes.json"),
({'name': 'Default/network-WithLossCell/_backbone-LeNet5/conv1-Conv2d/Cast-op190', 'single_node': True},
({'name': 'Default/network-WithLossCell/_backbone-LeNet5/conv1-Conv2d/Cast-op190',
'single_node': True},
"graph_handler_get_3_single_node.json") "graph_handler_get_3_single_node.json")
]) ])
def test_get(self, filter_condition, result_file): def test_get(self, filter_condition, result_file):
@@ -49,12 +48,6 @@ class TestGraphHandler:
file_path = os.path.join(self.graph_results_dir, result_file) file_path = os.path.join(self.graph_results_dir, result_file)
compare_result_with_file(result, file_path) compare_result_with_file(result, file_path)


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("node_name, result_file", [ @pytest.mark.parametrize("node_name, result_file", [
("Default/network-WithLossCell/_backbone-LeNet5/conv1-Conv2d/Cast-op190", ("Default/network-WithLossCell/_backbone-LeNet5/conv1-Conv2d/Cast-op190",
"tenor_hist_0.json"), "tenor_hist_0.json"),
@@ -67,12 +60,6 @@ class TestGraphHandler:
file_path = os.path.join(self.graph_results_dir, result_file) file_path = os.path.join(self.graph_results_dir, result_file)
compare_result_with_file(result, file_path) compare_result_with_file(result, file_path)


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("pattern, result_file", [ @pytest.mark.parametrize("pattern, result_file", [
("withlogits", "search_nodes_0.json"), ("withlogits", "search_nodes_0.json"),
("cst", "search_node_1.json") ("cst", "search_node_1.json")
@@ -83,12 +70,6 @@ class TestGraphHandler:
file_path = os.path.join(self.graph_results_dir, result_file) file_path = os.path.join(self.graph_results_dir, result_file)
compare_result_with_file(result, file_path) compare_result_with_file(result, file_path)


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("node_name, expect_type", [ @pytest.mark.parametrize("node_name, expect_type", [
("Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/cst1", 'Const'), ("Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/cst1", 'Const'),
("Default/TransData-op99", "TransData") ("Default/TransData-op99", "TransData")
@@ -98,12 +79,6 @@ class TestGraphHandler:
node_type = self.graph_handler.get_node_type(node_name) node_type = self.graph_handler.get_node_type(node_name)
assert node_type == expect_type assert node_type == expect_type


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("node_name, expect_full_name", [ @pytest.mark.parametrize("node_name, expect_full_name", [
(None, ""), (None, ""),
("Default/make_tuple[9]_3/make_tuple-op284", "Default/make_tuple-op284"), ("Default/make_tuple[9]_3/make_tuple-op284", "Default/make_tuple-op284"),
@@ -114,12 +89,6 @@ class TestGraphHandler:
full_name = self.graph_handler.get_full_name(node_name) full_name = self.graph_handler.get_full_name(node_name)
assert full_name == expect_full_name assert full_name == expect_full_name


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("full_name, expect_node_name", [ @pytest.mark.parametrize("full_name, expect_node_name", [
(None, ""), (None, ""),
("Default/make_tuple-op284", "Default/make_tuple[9]_3/make_tuple-op284"), ("Default/make_tuple-op284", "Default/make_tuple[9]_3/make_tuple-op284"),
@@ -130,14 +99,9 @@ class TestGraphHandler:
node_name = self.graph_handler.get_node_name_by_full_name(full_name) node_name = self.graph_handler.get_node_name_by_full_name(full_name)
assert node_name == expect_node_name assert node_name == expect_node_name


@pytest.mark.level0
@pytest.mark.env_single
@pytest.mark.platform_x86_cpu
@pytest.mark.platform_arm_ascend_training
@pytest.mark.platform_x86_gpu_training
@pytest.mark.platform_x86_ascend_training
@pytest.mark.parametrize("node_name, ascend, expect_next", [ @pytest.mark.parametrize("node_name, ascend, expect_next", [
(None, True, "Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/OneHot-op0"),
(None, True,
"Default/network-WithLossCell/_loss_fn-SoftmaxCrossEntropyWithLogits/OneHot-op0"),
(None, False, None), (None, False, None),
("Default/tuple_getitem[10]_0/tuple_getitem-op206", True, ("Default/tuple_getitem[10]_0/tuple_getitem-op206", True,
"Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/ReLUV2-op89"), "Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/ReLUV2-op89"),

+ 183
- 0
tests/ut/debugger/stream_handler/test_watchpoint_handler.py View File

@@ -0,0 +1,183 @@
# Copyright 2020 Huawei Technologies Co., Ltd
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# ============================================================================
"""Test WatchpointHandler."""
import json
import os
from unittest import mock, TestCase

import pytest

from mindinsight.debugger.common.exceptions.exceptions import DebuggerParamValueError, \
DebuggerParamTypeError
from mindinsight.debugger.common.log import logger as log
from mindinsight.debugger.stream_cache.watchpoint import Watchpoint
from mindinsight.debugger.stream_handler.watchpoint_handler import WatchpointHandler, \
WatchpointHitHandler, validate_watch_condition, validate_watch_condition_params

from tests.ut.debugger.configurations import init_graph_handler, mock_tensor_proto, \
mock_tensor_history


class TestWatchpointHandler:
"""Test WatchpointHandler."""
@classmethod
def setup_class(cls):
"""Init WatchpointHandler for watchpoint unittest."""
cls.handler = WatchpointHandler()
cls.graph_results_dir = os.path.join(os.path.dirname(__file__),
'../expected_results/graph')
cls.graph_stream = init_graph_handler()

@pytest.mark.parametrize(
"watch_condition, watch_nodes, watch_point_id, expect_new_id", [
({'condition': 'INF'}, None, None, 1),
({'condition': 'INF'}, ["Default"], None, 2),
({'condition': 'MAX_GT', 'param': 1},
["Gradients/Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/gradReLU/ReluGradV2-op92"], None, 3)
])
@mock.patch.object(Watchpoint, 'add_nodes')
def test_create_watchpoint(self, mock_add_nodes, watch_condition, watch_nodes,
watch_point_id, expect_new_id):
"""Test create_watchpoint."""
mock_add_nodes.return_value = None
watch_point_id = self.handler.create_watchpoint(watch_condition, watch_nodes, watch_point_id)
assert watch_point_id == expect_new_id

@pytest.mark.parametrize("filter_condition", [True, False])
@mock.patch.object(Watchpoint, 'get_set_cmd')
@mock.patch.object(Watchpoint, 'get_watch_condition_info')
def test_get(self, mock_get_wp, mock_get_cmd, filter_condition):
"""Test get."""
mock_get_wp.return_value = None
mock_get_cmd.return_value = None
with TestCase().assertLogs(logger=log, level='DEBUG') as log_content:
self.handler.get(filter_condition)
TestCase().assertIn(f"DEBUG:debugger.debugger:get the watch points with filter_condition:{filter_condition}",
log_content.output)

def test_get_watchpoint_by_id_except(self):
"""Test get_watchpoint_by_id."""
watchpoint_id = 4
with pytest.raises(DebuggerParamValueError) as err:
self.handler.get_watchpoint_by_id(watchpoint_id)
assert err.value.error_code == '5054B081'
assert err.value.message == f"ValueError. Invalid watchpoint id {watchpoint_id}"

@pytest.mark.parametrize("graph_file, watch_point_id", [
('graph_handler_get_3_single_node.json', 4)
])
@mock.patch.object(WatchpointHandler, '_set_watch_status_recursively')
def test_set_watch_nodes(self, mock_set_recur, graph_file, watch_point_id):
"""Test set_watch_nodes."""
path = os.path.join(self.graph_results_dir, graph_file)
with open(path, 'r') as f:
graph = json.load(f)
instance = mock_set_recur.return_value
self.handler.set_watch_nodes(graph, self.graph_stream, watch_point_id)
assert instance.iscalled()

@pytest.mark.parametrize(
"watch_point_id, watch_nodes, watched, expect_updated_id", [
(2, ["Default"], 0, 2),
(3, ["Gradients/Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/gradReLU/ReluGradV2-op92"], 1, 3)
])
@mock.patch.object(Watchpoint, 'remove_nodes')
@mock.patch.object(Watchpoint, 'add_nodes')
def test_update_watchpoint(self, mock_add_nodes, mock_remove_nodes, watch_point_id, watch_nodes,
watched, expect_updated_id):
"""Test update_watchpoint."""
mock_add_nodes.return_value = None
mock_remove_nodes.return_value = None
with TestCase().assertLogs(logger=log, level='DEBUG') as log_content:
self.handler.update_watchpoint(watch_point_id, watch_nodes, watched)
TestCase().assertIn(f"DEBUG:debugger.debugger:Update watchpoint {expect_updated_id} in cache.",
log_content.output)

@pytest.mark.parametrize(
"watch_point_id, expect_deleted_ids", [
(3, 3), (2, 2)
])
def test_delete_watchpoint(self, watch_point_id, expect_deleted_ids):
"""Test delete_watchpoint."""
with TestCase().assertLogs(logger=log, level='DEBUG') as log_content:
self.handler.delete_watchpoint(watch_point_id)
TestCase().assertIn(f"DEBUG:debugger.debugger:Delete watchpoint {expect_deleted_ids} in cache.",
log_content.output)


class TestWatchpointHitHandler:
"""Test WatchpointHitHandler."""
@classmethod
def setup_class(cls):
"""Setup."""
cls.handler = WatchpointHitHandler()
cls.tensor_proto = mock_tensor_proto()
cls.tensor_hist = mock_tensor_history()

@mock.patch('mindinsight.debugger.stream_cache.watchpoint.WatchpointHit')
def test_put(self, mock_hit):
"""Test put."""
value = {
'tensor_proto': self.tensor_proto,
'watchpoint': {'id': 1, 'watch_condition': {'condition': 'INF'}},
'node_name': 'Gradients/Default/network-WithLossCell/_backbone-LeNet5/relu-ReLU/gradReLU/ReluGradV2-op92'
}
mock_hit.return_value = mock.MagicMock(
tensor_proto=value.get('tensor_proto'),
watchpoint=value.get('watchpoint'),
node_name=value.get('node_name')
)
self.handler.put(value)

@pytest.mark.parametrize("filter_condition", [
None, "Default/network-WithLossCell/_backbone-LeNet5/conv1-Conv2d/Cast-op190"
])
@mock.patch.object(WatchpointHitHandler, 'get_watchpoint_hits')
def test_get(self, mock_get, filter_condition):
"""Test get."""
mock_get.return_value = {'watch_point_hits': []}
self.handler.get(filter_condition)

@mock.patch.object(WatchpointHitHandler, '_is_tensor_hit')
def test_update_tensor_history(self, mock_hit):
"""Test update_tensor_history."""
mock_hit.side_effect = [True, False]
self.handler.update_tensor_history(self.tensor_hist)


def test_validate_watch_condition_type_error():
"""Test validate_watch_condition."""
watch_condition = []
with pytest.raises(DebuggerParamTypeError) as err:
validate_watch_condition(watch_condition)
assert err.value.error_code == '5054B080'

watch_condition = {'watch_condition': {'condition': 'MAXIMUM'}}
with pytest.raises(DebuggerParamValueError) as err:
validate_watch_condition(watch_condition)
assert err.value.error_code == '5054B081'


def test_validate_watch_condition_params_except():
"""Test validate_watch_condition_params."""
watch_condition = {'watch_condition': {'condition': 'NAN', 'param': 1}}
with pytest.raises(DebuggerParamValueError) as err:
validate_watch_condition_params(watch_condition)
assert err.value.error_code == '5054B081'

watch_condition = {'watch_condition': {'condition': 'MAX_GT', 'param': '0'}}
with pytest.raises(DebuggerParamValueError) as err:
validate_watch_condition_params(watch_condition)
assert err.value.error_code == '5054B081'

Loading…
Cancel
Save