tensorbored 2.21.0rc1769983804__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- tensorbored/__init__.py +112 -0
- tensorbored/_vendor/__init__.py +0 -0
- tensorbored/_vendor/bleach/__init__.py +125 -0
- tensorbored/_vendor/bleach/_vendor/__init__.py +0 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/__init__.py +35 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_ihatexml.py +289 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_inputstream.py +918 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_tokenizer.py +1735 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/__init__.py +5 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/_base.py +40 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_trie/py.py +67 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/_utils.py +159 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/constants.py +2946 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/__init__.py +0 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/alphabeticalattributes.py +29 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/base.py +12 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/inject_meta_charset.py +73 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/lint.py +93 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/optionaltags.py +207 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/sanitizer.py +916 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/filters/whitespace.py +38 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/html5parser.py +2795 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/serializer.py +409 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/__init__.py +30 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/genshi.py +54 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treeadapters/sax.py +50 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/__init__.py +88 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/base.py +417 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/dom.py +239 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree.py +343 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treebuilders/etree_lxml.py +392 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/__init__.py +154 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/base.py +252 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/dom.py +43 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree.py +131 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/etree_lxml.py +215 -0
- tensorbored/_vendor/bleach/_vendor/html5lib/treewalkers/genshi.py +69 -0
- tensorbored/_vendor/bleach/_vendor/parse.py +1078 -0
- tensorbored/_vendor/bleach/callbacks.py +32 -0
- tensorbored/_vendor/bleach/html5lib_shim.py +757 -0
- tensorbored/_vendor/bleach/linkifier.py +633 -0
- tensorbored/_vendor/bleach/parse_shim.py +1 -0
- tensorbored/_vendor/bleach/sanitizer.py +638 -0
- tensorbored/_vendor/bleach/six_shim.py +19 -0
- tensorbored/_vendor/webencodings/__init__.py +342 -0
- tensorbored/_vendor/webencodings/labels.py +231 -0
- tensorbored/_vendor/webencodings/mklabels.py +59 -0
- tensorbored/_vendor/webencodings/x_user_defined.py +325 -0
- tensorbored/assets.py +36 -0
- tensorbored/auth.py +102 -0
- tensorbored/backend/__init__.py +0 -0
- tensorbored/backend/application.py +604 -0
- tensorbored/backend/auth_context_middleware.py +38 -0
- tensorbored/backend/client_feature_flags.py +113 -0
- tensorbored/backend/empty_path_redirect.py +46 -0
- tensorbored/backend/event_processing/__init__.py +0 -0
- tensorbored/backend/event_processing/data_ingester.py +276 -0
- tensorbored/backend/event_processing/data_provider.py +535 -0
- tensorbored/backend/event_processing/directory_loader.py +142 -0
- tensorbored/backend/event_processing/directory_watcher.py +272 -0
- tensorbored/backend/event_processing/event_accumulator.py +950 -0
- tensorbored/backend/event_processing/event_file_inspector.py +463 -0
- tensorbored/backend/event_processing/event_file_loader.py +292 -0
- tensorbored/backend/event_processing/event_multiplexer.py +521 -0
- tensorbored/backend/event_processing/event_util.py +68 -0
- tensorbored/backend/event_processing/io_wrapper.py +223 -0
- tensorbored/backend/event_processing/plugin_asset_util.py +104 -0
- tensorbored/backend/event_processing/plugin_event_accumulator.py +721 -0
- tensorbored/backend/event_processing/plugin_event_multiplexer.py +522 -0
- tensorbored/backend/event_processing/reservoir.py +266 -0
- tensorbored/backend/event_processing/tag_types.py +29 -0
- tensorbored/backend/experiment_id.py +71 -0
- tensorbored/backend/experimental_plugin.py +51 -0
- tensorbored/backend/http_util.py +263 -0
- tensorbored/backend/json_util.py +70 -0
- tensorbored/backend/path_prefix.py +67 -0
- tensorbored/backend/process_graph.py +74 -0
- tensorbored/backend/security_validator.py +202 -0
- tensorbored/compat/__init__.py +69 -0
- tensorbored/compat/proto/__init__.py +0 -0
- tensorbored/compat/proto/allocation_description_pb2.py +35 -0
- tensorbored/compat/proto/api_def_pb2.py +82 -0
- tensorbored/compat/proto/attr_value_pb2.py +80 -0
- tensorbored/compat/proto/cluster_pb2.py +58 -0
- tensorbored/compat/proto/config_pb2.py +271 -0
- tensorbored/compat/proto/coordination_config_pb2.py +45 -0
- tensorbored/compat/proto/cost_graph_pb2.py +87 -0
- tensorbored/compat/proto/cpp_shape_inference_pb2.py +70 -0
- tensorbored/compat/proto/debug_pb2.py +65 -0
- tensorbored/compat/proto/event_pb2.py +149 -0
- tensorbored/compat/proto/full_type_pb2.py +74 -0
- tensorbored/compat/proto/function_pb2.py +157 -0
- tensorbored/compat/proto/graph_debug_info_pb2.py +111 -0
- tensorbored/compat/proto/graph_pb2.py +41 -0
- tensorbored/compat/proto/histogram_pb2.py +39 -0
- tensorbored/compat/proto/meta_graph_pb2.py +254 -0
- tensorbored/compat/proto/node_def_pb2.py +61 -0
- tensorbored/compat/proto/op_def_pb2.py +81 -0
- tensorbored/compat/proto/resource_handle_pb2.py +48 -0
- tensorbored/compat/proto/rewriter_config_pb2.py +93 -0
- tensorbored/compat/proto/rpc_options_pb2.py +35 -0
- tensorbored/compat/proto/saved_object_graph_pb2.py +193 -0
- tensorbored/compat/proto/saver_pb2.py +38 -0
- tensorbored/compat/proto/step_stats_pb2.py +116 -0
- tensorbored/compat/proto/struct_pb2.py +144 -0
- tensorbored/compat/proto/summary_pb2.py +111 -0
- tensorbored/compat/proto/tensor_description_pb2.py +38 -0
- tensorbored/compat/proto/tensor_pb2.py +68 -0
- tensorbored/compat/proto/tensor_shape_pb2.py +46 -0
- tensorbored/compat/proto/tfprof_log_pb2.py +307 -0
- tensorbored/compat/proto/trackable_object_graph_pb2.py +90 -0
- tensorbored/compat/proto/types_pb2.py +105 -0
- tensorbored/compat/proto/variable_pb2.py +62 -0
- tensorbored/compat/proto/verifier_config_pb2.py +38 -0
- tensorbored/compat/proto/versions_pb2.py +35 -0
- tensorbored/compat/tensorflow_stub/__init__.py +38 -0
- tensorbored/compat/tensorflow_stub/app.py +124 -0
- tensorbored/compat/tensorflow_stub/compat/__init__.py +131 -0
- tensorbored/compat/tensorflow_stub/compat/v1/__init__.py +20 -0
- tensorbored/compat/tensorflow_stub/dtypes.py +692 -0
- tensorbored/compat/tensorflow_stub/error_codes.py +169 -0
- tensorbored/compat/tensorflow_stub/errors.py +507 -0
- tensorbored/compat/tensorflow_stub/flags.py +124 -0
- tensorbored/compat/tensorflow_stub/io/__init__.py +17 -0
- tensorbored/compat/tensorflow_stub/io/gfile.py +1011 -0
- tensorbored/compat/tensorflow_stub/pywrap_tensorflow.py +285 -0
- tensorbored/compat/tensorflow_stub/tensor_shape.py +1035 -0
- tensorbored/context.py +129 -0
- tensorbored/data/__init__.py +0 -0
- tensorbored/data/grpc_provider.py +365 -0
- tensorbored/data/ingester.py +46 -0
- tensorbored/data/proto/__init__.py +0 -0
- tensorbored/data/proto/data_provider_pb2.py +517 -0
- tensorbored/data/proto/data_provider_pb2_grpc.py +374 -0
- tensorbored/data/provider.py +1365 -0
- tensorbored/data/server_ingester.py +301 -0
- tensorbored/data_compat.py +159 -0
- tensorbored/dataclass_compat.py +224 -0
- tensorbored/default.py +124 -0
- tensorbored/errors.py +130 -0
- tensorbored/lazy.py +99 -0
- tensorbored/main.py +48 -0
- tensorbored/main_lib.py +62 -0
- tensorbored/manager.py +487 -0
- tensorbored/notebook.py +441 -0
- tensorbored/plugin_util.py +266 -0
- tensorbored/plugins/__init__.py +0 -0
- tensorbored/plugins/audio/__init__.py +0 -0
- tensorbored/plugins/audio/audio_plugin.py +229 -0
- tensorbored/plugins/audio/metadata.py +69 -0
- tensorbored/plugins/audio/plugin_data_pb2.py +37 -0
- tensorbored/plugins/audio/summary.py +230 -0
- tensorbored/plugins/audio/summary_v2.py +124 -0
- tensorbored/plugins/base_plugin.py +367 -0
- tensorbored/plugins/core/__init__.py +0 -0
- tensorbored/plugins/core/core_plugin.py +981 -0
- tensorbored/plugins/custom_scalar/__init__.py +0 -0
- tensorbored/plugins/custom_scalar/custom_scalars_plugin.py +320 -0
- tensorbored/plugins/custom_scalar/layout_pb2.py +85 -0
- tensorbored/plugins/custom_scalar/metadata.py +35 -0
- tensorbored/plugins/custom_scalar/summary.py +79 -0
- tensorbored/plugins/debugger_v2/__init__.py +0 -0
- tensorbored/plugins/debugger_v2/debug_data_multiplexer.py +631 -0
- tensorbored/plugins/debugger_v2/debug_data_provider.py +634 -0
- tensorbored/plugins/debugger_v2/debugger_v2_plugin.py +504 -0
- tensorbored/plugins/distribution/__init__.py +0 -0
- tensorbored/plugins/distribution/compressor.py +158 -0
- tensorbored/plugins/distribution/distributions_plugin.py +116 -0
- tensorbored/plugins/distribution/metadata.py +19 -0
- tensorbored/plugins/graph/__init__.py +0 -0
- tensorbored/plugins/graph/graph_util.py +129 -0
- tensorbored/plugins/graph/graphs_plugin.py +336 -0
- tensorbored/plugins/graph/keras_util.py +328 -0
- tensorbored/plugins/graph/metadata.py +42 -0
- tensorbored/plugins/histogram/__init__.py +0 -0
- tensorbored/plugins/histogram/histograms_plugin.py +144 -0
- tensorbored/plugins/histogram/metadata.py +63 -0
- tensorbored/plugins/histogram/plugin_data_pb2.py +34 -0
- tensorbored/plugins/histogram/summary.py +234 -0
- tensorbored/plugins/histogram/summary_v2.py +292 -0
- tensorbored/plugins/hparams/__init__.py +14 -0
- tensorbored/plugins/hparams/_keras.py +93 -0
- tensorbored/plugins/hparams/api.py +130 -0
- tensorbored/plugins/hparams/api_pb2.py +208 -0
- tensorbored/plugins/hparams/backend_context.py +606 -0
- tensorbored/plugins/hparams/download_data.py +158 -0
- tensorbored/plugins/hparams/error.py +26 -0
- tensorbored/plugins/hparams/get_experiment.py +71 -0
- tensorbored/plugins/hparams/hparams_plugin.py +206 -0
- tensorbored/plugins/hparams/hparams_util_pb2.py +69 -0
- tensorbored/plugins/hparams/json_format_compat.py +38 -0
- tensorbored/plugins/hparams/list_metric_evals.py +57 -0
- tensorbored/plugins/hparams/list_session_groups.py +1040 -0
- tensorbored/plugins/hparams/metadata.py +125 -0
- tensorbored/plugins/hparams/metrics.py +41 -0
- tensorbored/plugins/hparams/plugin_data_pb2.py +69 -0
- tensorbored/plugins/hparams/summary.py +205 -0
- tensorbored/plugins/hparams/summary_v2.py +597 -0
- tensorbored/plugins/image/__init__.py +0 -0
- tensorbored/plugins/image/images_plugin.py +232 -0
- tensorbored/plugins/image/metadata.py +65 -0
- tensorbored/plugins/image/plugin_data_pb2.py +34 -0
- tensorbored/plugins/image/summary.py +159 -0
- tensorbored/plugins/image/summary_v2.py +130 -0
- tensorbored/plugins/mesh/__init__.py +14 -0
- tensorbored/plugins/mesh/mesh_plugin.py +292 -0
- tensorbored/plugins/mesh/metadata.py +152 -0
- tensorbored/plugins/mesh/plugin_data_pb2.py +37 -0
- tensorbored/plugins/mesh/summary.py +251 -0
- tensorbored/plugins/mesh/summary_v2.py +214 -0
- tensorbored/plugins/metrics/__init__.py +0 -0
- tensorbored/plugins/metrics/metadata.py +17 -0
- tensorbored/plugins/metrics/metrics_plugin.py +623 -0
- tensorbored/plugins/pr_curve/__init__.py +0 -0
- tensorbored/plugins/pr_curve/metadata.py +75 -0
- tensorbored/plugins/pr_curve/plugin_data_pb2.py +34 -0
- tensorbored/plugins/pr_curve/pr_curves_plugin.py +241 -0
- tensorbored/plugins/pr_curve/summary.py +574 -0
- tensorbored/plugins/profile_redirect/__init__.py +0 -0
- tensorbored/plugins/profile_redirect/profile_redirect_plugin.py +49 -0
- tensorbored/plugins/projector/__init__.py +67 -0
- tensorbored/plugins/projector/metadata.py +26 -0
- tensorbored/plugins/projector/projector_config_pb2.py +54 -0
- tensorbored/plugins/projector/projector_plugin.py +795 -0
- tensorbored/plugins/projector/tf_projector_plugin/index.js +32 -0
- tensorbored/plugins/projector/tf_projector_plugin/projector_binary.html +524 -0
- tensorbored/plugins/projector/tf_projector_plugin/projector_binary.js +15536 -0
- tensorbored/plugins/scalar/__init__.py +0 -0
- tensorbored/plugins/scalar/metadata.py +60 -0
- tensorbored/plugins/scalar/plugin_data_pb2.py +34 -0
- tensorbored/plugins/scalar/scalars_plugin.py +181 -0
- tensorbored/plugins/scalar/summary.py +109 -0
- tensorbored/plugins/scalar/summary_v2.py +124 -0
- tensorbored/plugins/text/__init__.py +0 -0
- tensorbored/plugins/text/metadata.py +62 -0
- tensorbored/plugins/text/plugin_data_pb2.py +34 -0
- tensorbored/plugins/text/summary.py +114 -0
- tensorbored/plugins/text/summary_v2.py +124 -0
- tensorbored/plugins/text/text_plugin.py +288 -0
- tensorbored/plugins/wit_redirect/__init__.py +0 -0
- tensorbored/plugins/wit_redirect/wit_redirect_plugin.py +49 -0
- tensorbored/program.py +910 -0
- tensorbored/summary/__init__.py +35 -0
- tensorbored/summary/_output.py +124 -0
- tensorbored/summary/_tf/__init__.py +14 -0
- tensorbored/summary/_tf/summary/__init__.py +178 -0
- tensorbored/summary/_writer.py +105 -0
- tensorbored/summary/v1.py +51 -0
- tensorbored/summary/v2.py +25 -0
- tensorbored/summary/writer/__init__.py +13 -0
- tensorbored/summary/writer/event_file_writer.py +291 -0
- tensorbored/summary/writer/record_writer.py +50 -0
- tensorbored/util/__init__.py +0 -0
- tensorbored/util/encoder.py +116 -0
- tensorbored/util/grpc_util.py +311 -0
- tensorbored/util/img_mime_type_detector.py +40 -0
- tensorbored/util/io_util.py +20 -0
- tensorbored/util/lazy_tensor_creator.py +110 -0
- tensorbored/util/op_evaluator.py +104 -0
- tensorbored/util/platform_util.py +20 -0
- tensorbored/util/tb_logging.py +24 -0
- tensorbored/util/tensor_util.py +617 -0
- tensorbored/util/timing.py +122 -0
- tensorbored/version.py +21 -0
- tensorbored/webfiles.zip +0 -0
- tensorbored-2.21.0rc1769983804.dist-info/METADATA +49 -0
- tensorbored-2.21.0rc1769983804.dist-info/RECORD +271 -0
- tensorbored-2.21.0rc1769983804.dist-info/WHEEL +5 -0
- tensorbored-2.21.0rc1769983804.dist-info/entry_points.txt +6 -0
- tensorbored-2.21.0rc1769983804.dist-info/licenses/LICENSE +739 -0
- tensorbored-2.21.0rc1769983804.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,631 @@
|
|
|
1
|
+
# Copyright 2019 The TensorFlow Authors. All Rights Reserved.
|
|
2
|
+
#
|
|
3
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
4
|
+
# you may not use this file except in compliance with the License.
|
|
5
|
+
# You may obtain a copy of the License at
|
|
6
|
+
#
|
|
7
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
|
8
|
+
#
|
|
9
|
+
# Unless required by applicable law or agreed to in writing, software
|
|
10
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
11
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
12
|
+
# See the License for the specific language governing permissions and
|
|
13
|
+
# limitations under the License.
|
|
14
|
+
# ==============================================================================
|
|
15
|
+
"""A wrapper around DebugDataReader used for retrieving tfdbg v2 data."""
|
|
16
|
+
|
|
17
|
+
import threading
|
|
18
|
+
|
|
19
|
+
from tensorbored import errors
|
|
20
|
+
|
|
21
|
+
# Dummy run name for the debugger.
|
|
22
|
+
# Currently, the `DebuggerV2ExperimentMultiplexer` class is tied to a single
|
|
23
|
+
# logdir, which holds at most one DebugEvent file set in the tfdbg v2 (tfdbg2
|
|
24
|
+
# for short) format.
|
|
25
|
+
# TODO(cais): When tfdbg2 allows there to be multiple DebugEvent file sets in
|
|
26
|
+
# the same logdir, replace this magic string with actual run names.
|
|
27
|
+
DEFAULT_DEBUGGER_RUN_NAME = "__default_debugger_run__"
|
|
28
|
+
|
|
29
|
+
# Default number of alerts per monitor type.
|
|
30
|
+
# Limiting the number of alerts is based on the consideration that usually
|
|
31
|
+
# only the first few alerting events are the most critical and the subsequent
|
|
32
|
+
# ones are either repetitions of the earlier ones or caused by the earlier ones.
|
|
33
|
+
DEFAULT_PER_TYPE_ALERT_LIMIT = 1000
|
|
34
|
+
|
|
35
|
+
# Default interval between successive calls to `DebugDataReader.update()``.
|
|
36
|
+
DEFAULT_RELOAD_INTERVAL_SEC = 30
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def run_repeatedly_in_background(target, interval_sec):
|
|
40
|
+
"""Run a target task repeatedly in the background.
|
|
41
|
+
|
|
42
|
+
In the context of this module, `target` is the `update()` method of the
|
|
43
|
+
underlying reader for tfdbg2-format data.
|
|
44
|
+
This method is mocked by unit tests for deterministic behaviors during
|
|
45
|
+
testing.
|
|
46
|
+
|
|
47
|
+
Args:
|
|
48
|
+
target: The target task to run in the background, a callable with no args.
|
|
49
|
+
interval_sec: Time interval between repeats, in seconds.
|
|
50
|
+
|
|
51
|
+
Returns:
|
|
52
|
+
- A `threading.Event` object that can be used to interrupt an ongoing
|
|
53
|
+
waiting interval between successive runs of `target`. To interrupt the
|
|
54
|
+
interval, call the `set()` method of the object.
|
|
55
|
+
- The `threading.Thread` object on which `target` is run repeatedly.
|
|
56
|
+
"""
|
|
57
|
+
event = threading.Event()
|
|
58
|
+
|
|
59
|
+
def _run_repeatedly():
|
|
60
|
+
while True:
|
|
61
|
+
target()
|
|
62
|
+
event.wait(interval_sec)
|
|
63
|
+
event.clear()
|
|
64
|
+
|
|
65
|
+
# Use `daemon=True` to make sure the thread doesn't block program exit.
|
|
66
|
+
thread = threading.Thread(target=_run_repeatedly, daemon=True)
|
|
67
|
+
thread.start()
|
|
68
|
+
return event, thread
|
|
69
|
+
|
|
70
|
+
|
|
71
|
+
def _alert_to_json(alert):
|
|
72
|
+
# TODO(cais): Replace this with Alert.to_json() when supported by the
|
|
73
|
+
# backend.
|
|
74
|
+
from tensorflow.python.debug.lib import debug_events_monitors
|
|
75
|
+
|
|
76
|
+
if isinstance(alert, debug_events_monitors.InfNanAlert):
|
|
77
|
+
return {
|
|
78
|
+
"alert_type": "InfNanAlert",
|
|
79
|
+
"op_type": alert.op_type,
|
|
80
|
+
"output_slot": alert.output_slot,
|
|
81
|
+
# TODO(cais): Once supported by backend, add 'op_name' key
|
|
82
|
+
# for intra-graph execution events.
|
|
83
|
+
"size": alert.size,
|
|
84
|
+
"num_neg_inf": alert.num_neg_inf,
|
|
85
|
+
"num_pos_inf": alert.num_pos_inf,
|
|
86
|
+
"num_nan": alert.num_nan,
|
|
87
|
+
"execution_index": alert.execution_index,
|
|
88
|
+
"graph_execution_trace_index": alert.graph_execution_trace_index,
|
|
89
|
+
}
|
|
90
|
+
else:
|
|
91
|
+
raise TypeError("Unrecognized alert subtype: %s" % type(alert))
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
def parse_tensor_name(tensor_name):
|
|
95
|
+
"""Helper function that extracts op name and slot from tensor name."""
|
|
96
|
+
output_slot = 0
|
|
97
|
+
if ":" in tensor_name:
|
|
98
|
+
op_name, output_slot = tensor_name.split(":")
|
|
99
|
+
output_slot = int(output_slot)
|
|
100
|
+
else:
|
|
101
|
+
op_name = tensor_name
|
|
102
|
+
return op_name, output_slot
|
|
103
|
+
|
|
104
|
+
|
|
105
|
+
class DebuggerV2EventMultiplexer:
|
|
106
|
+
"""A class used for accessing tfdbg v2 DebugEvent data on local filesystem.
|
|
107
|
+
|
|
108
|
+
This class is a short-term hack, mirroring the EventMultiplexer for the main
|
|
109
|
+
TensorBoard plugins (e.g., scalar, histogram and graphs.) As such, it only
|
|
110
|
+
implements the methods relevant to the Debugger V2 pluggin.
|
|
111
|
+
|
|
112
|
+
TODO(cais): Integrate it with EventMultiplexer and use the integrated class
|
|
113
|
+
from MultiplexerDataProvider for a single path of accessing debugger and
|
|
114
|
+
non-debugger data.
|
|
115
|
+
"""
|
|
116
|
+
|
|
117
|
+
def __init__(self, logdir):
|
|
118
|
+
"""Constructor for the `DebugEventMultiplexer`.
|
|
119
|
+
|
|
120
|
+
Args:
|
|
121
|
+
logdir: Path to the directory to load the tfdbg v2 data from.
|
|
122
|
+
"""
|
|
123
|
+
self._logdir = logdir
|
|
124
|
+
self._reader = None
|
|
125
|
+
self._reader_lock = threading.Lock()
|
|
126
|
+
self._reload_needed_event = None
|
|
127
|
+
# Create the reader for the tfdbg2 data in the lodir as soon as
|
|
128
|
+
# the backend of the debugger-v2 plugin is created, so it doesn't need
|
|
129
|
+
# to wait for the first request from the FE to start loading data.
|
|
130
|
+
self._tryCreateReader()
|
|
131
|
+
|
|
132
|
+
def _tryCreateReader(self):
|
|
133
|
+
"""Try creating reader for tfdbg2 data in the logdir.
|
|
134
|
+
|
|
135
|
+
If the reader has already been created, a new one will not be created and
|
|
136
|
+
this function is a no-op.
|
|
137
|
+
|
|
138
|
+
If a reader has not been created, create it and start periodic calls to
|
|
139
|
+
`update()` on a separate thread.
|
|
140
|
+
"""
|
|
141
|
+
if self._reader:
|
|
142
|
+
return
|
|
143
|
+
with self._reader_lock:
|
|
144
|
+
if not self._reader:
|
|
145
|
+
try:
|
|
146
|
+
# TODO(cais): Avoid conditional imports and instead use
|
|
147
|
+
# plugin loader to gate the loading of this entire plugin.
|
|
148
|
+
from tensorflow.python.debug.lib import debug_events_reader
|
|
149
|
+
from tensorflow.python.debug.lib import (
|
|
150
|
+
debug_events_monitors,
|
|
151
|
+
)
|
|
152
|
+
except ImportError:
|
|
153
|
+
# This ensures graceful behavior when tensorflow install is
|
|
154
|
+
# unavailable or when the installed tensorflow version does not
|
|
155
|
+
# contain the required modules.
|
|
156
|
+
return
|
|
157
|
+
|
|
158
|
+
try:
|
|
159
|
+
self._reader = debug_events_reader.DebugDataReader(
|
|
160
|
+
self._logdir
|
|
161
|
+
)
|
|
162
|
+
except AttributeError:
|
|
163
|
+
# Gracefully fail for users without the required API changes to
|
|
164
|
+
# debug_events_reader.DebugDataReader introduced in
|
|
165
|
+
# TF 2.1.0.dev20200103. This should be safe to remove when
|
|
166
|
+
# TF 2.2 is released.
|
|
167
|
+
return
|
|
168
|
+
except ValueError:
|
|
169
|
+
# When no DebugEvent file set is found in the logdir, a
|
|
170
|
+
# `ValueError` is thrown.
|
|
171
|
+
return
|
|
172
|
+
|
|
173
|
+
self._monitors = [
|
|
174
|
+
debug_events_monitors.InfNanMonitor(
|
|
175
|
+
self._reader, limit=DEFAULT_PER_TYPE_ALERT_LIMIT
|
|
176
|
+
)
|
|
177
|
+
]
|
|
178
|
+
self._reload_needed_event, _ = run_repeatedly_in_background(
|
|
179
|
+
self._reader.update, DEFAULT_RELOAD_INTERVAL_SEC
|
|
180
|
+
)
|
|
181
|
+
|
|
182
|
+
def _reloadReader(self):
|
|
183
|
+
"""If a reader exists and has started period updating, unblock the update.
|
|
184
|
+
|
|
185
|
+
The updates are performed periodically with a sleep interval between
|
|
186
|
+
successive calls to the reader's update() method. Calling this method
|
|
187
|
+
interrupts the sleep immediately if one is ongoing.
|
|
188
|
+
"""
|
|
189
|
+
if self._reload_needed_event:
|
|
190
|
+
self._reload_needed_event.set()
|
|
191
|
+
|
|
192
|
+
def FirstEventTimestamp(self, run):
|
|
193
|
+
"""Return the timestamp of the first DebugEvent of the given run.
|
|
194
|
+
|
|
195
|
+
This may perform I/O if no events have been loaded yet for the run.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
run: A string name of the run for which the timestamp is retrieved.
|
|
199
|
+
This currently must be hardcoded as `DEFAULT_DEBUGGER_RUN_NAME`,
|
|
200
|
+
as each logdir contains at most one DebugEvent file set (i.e., a
|
|
201
|
+
run of a tfdbg2-instrumented TensorFlow program.)
|
|
202
|
+
|
|
203
|
+
Returns:
|
|
204
|
+
The wall_time of the first event of the run, which will be in seconds
|
|
205
|
+
since the epoch as a `float`.
|
|
206
|
+
"""
|
|
207
|
+
if self._reader is None:
|
|
208
|
+
raise ValueError("No tfdbg2 runs exists.")
|
|
209
|
+
if run != DEFAULT_DEBUGGER_RUN_NAME:
|
|
210
|
+
raise ValueError(
|
|
211
|
+
"Expected run name to be %s, but got %s"
|
|
212
|
+
% (DEFAULT_DEBUGGER_RUN_NAME, run)
|
|
213
|
+
)
|
|
214
|
+
return self._reader.starting_wall_time()
|
|
215
|
+
|
|
216
|
+
def PluginRunToTagToContent(self, plugin_name):
|
|
217
|
+
raise NotImplementedError(
|
|
218
|
+
"DebugDataMultiplexer.PluginRunToTagToContent() has not been "
|
|
219
|
+
"implemented yet."
|
|
220
|
+
)
|
|
221
|
+
|
|
222
|
+
def Runs(self):
|
|
223
|
+
"""Return all the tfdbg2 run names in the logdir watched by this instance.
|
|
224
|
+
|
|
225
|
+
The `Run()` method of this class is specialized for the tfdbg2-format
|
|
226
|
+
DebugEvent files.
|
|
227
|
+
|
|
228
|
+
As a side effect, this method unblocks the underlying reader's period
|
|
229
|
+
reloading if a reader exists. This lets the reader update at a higher
|
|
230
|
+
frequency than the default one with 30-second sleeping period between
|
|
231
|
+
reloading when data is being queried actively from this instance.
|
|
232
|
+
Note that this `Runs()` method is used by all other public data-access
|
|
233
|
+
methods of this class (e.g., `ExecutionData()`, `GraphExecutionData()`).
|
|
234
|
+
Hence calls to those methods will lead to accelerated data reloading of
|
|
235
|
+
the reader.
|
|
236
|
+
|
|
237
|
+
Returns:
|
|
238
|
+
If tfdbg2-format data exists in the `logdir` of this object, returns:
|
|
239
|
+
```
|
|
240
|
+
{runName: { "debugger-v2": [tag1, tag2, tag3] } }
|
|
241
|
+
```
|
|
242
|
+
where `runName` is the hard-coded string `DEFAULT_DEBUGGER_RUN_NAME`
|
|
243
|
+
string. This is related to the fact that tfdbg2 currently contains
|
|
244
|
+
at most one DebugEvent file set per directory.
|
|
245
|
+
If no tfdbg2-format data exists in the `logdir`, an empty `dict`.
|
|
246
|
+
"""
|
|
247
|
+
# Call `_tryCreateReader()` here to cover the possibility of tfdbg2
|
|
248
|
+
# data start being written to the logdir after the tensorboard backend
|
|
249
|
+
# starts.
|
|
250
|
+
self._tryCreateReader()
|
|
251
|
+
if self._reader:
|
|
252
|
+
# If a _reader exists, unblock its reloading (on a separate thread)
|
|
253
|
+
# immediately.
|
|
254
|
+
self._reloadReader()
|
|
255
|
+
return {
|
|
256
|
+
DEFAULT_DEBUGGER_RUN_NAME: {
|
|
257
|
+
# TODO(cais): Add the semantically meaningful tag names such as
|
|
258
|
+
# 'execution_digests_book', 'alerts_book'
|
|
259
|
+
"debugger-v2": []
|
|
260
|
+
}
|
|
261
|
+
}
|
|
262
|
+
else:
|
|
263
|
+
return {}
|
|
264
|
+
|
|
265
|
+
def _checkBeginEndIndices(self, begin, end, total_count):
|
|
266
|
+
if begin < 0:
|
|
267
|
+
raise errors.InvalidArgumentError(
|
|
268
|
+
"Invalid begin index (%d)" % begin
|
|
269
|
+
)
|
|
270
|
+
if end > total_count:
|
|
271
|
+
raise errors.InvalidArgumentError(
|
|
272
|
+
"end index (%d) out of bounds (%d)" % (end, total_count)
|
|
273
|
+
)
|
|
274
|
+
if end >= 0 and end < begin:
|
|
275
|
+
raise errors.InvalidArgumentError(
|
|
276
|
+
"end index (%d) is unexpectedly less than begin index (%d)"
|
|
277
|
+
% (end, begin)
|
|
278
|
+
)
|
|
279
|
+
if end < 0: # This means all digests.
|
|
280
|
+
end = total_count
|
|
281
|
+
return end
|
|
282
|
+
|
|
283
|
+
def Alerts(self, run, begin, end, alert_type_filter=None):
|
|
284
|
+
"""Get alerts from the debugged TensorFlow program.
|
|
285
|
+
|
|
286
|
+
Args:
|
|
287
|
+
run: The tfdbg2 run to get Alerts from.
|
|
288
|
+
begin: Beginning alert index.
|
|
289
|
+
end: Ending alert index.
|
|
290
|
+
alert_type_filter: Optional filter string for alert type, used to
|
|
291
|
+
restrict retrieved alerts data to a single type. If used,
|
|
292
|
+
`begin` and `end` refer to the beginning and ending indices within
|
|
293
|
+
the filtered alert type.
|
|
294
|
+
"""
|
|
295
|
+
from tensorflow.python.debug.lib import debug_events_monitors
|
|
296
|
+
|
|
297
|
+
runs = self.Runs()
|
|
298
|
+
if run not in runs:
|
|
299
|
+
# TODO(cais): This should generate a 400 response instead.
|
|
300
|
+
return None
|
|
301
|
+
alerts = []
|
|
302
|
+
alerts_breakdown = dict()
|
|
303
|
+
alerts_by_type = dict()
|
|
304
|
+
for monitor in self._monitors:
|
|
305
|
+
monitor_alerts = monitor.alerts()
|
|
306
|
+
if not monitor_alerts:
|
|
307
|
+
continue
|
|
308
|
+
alerts.extend(monitor_alerts)
|
|
309
|
+
# TODO(cais): Replace this with Alert.to_json() when
|
|
310
|
+
# monitor.alert_type() is available.
|
|
311
|
+
if isinstance(monitor, debug_events_monitors.InfNanMonitor):
|
|
312
|
+
alert_type = "InfNanAlert"
|
|
313
|
+
else:
|
|
314
|
+
alert_type = "__MiscellaneousAlert__"
|
|
315
|
+
alerts_breakdown[alert_type] = len(monitor_alerts)
|
|
316
|
+
alerts_by_type[alert_type] = monitor_alerts
|
|
317
|
+
num_alerts = len(alerts)
|
|
318
|
+
if alert_type_filter is not None:
|
|
319
|
+
if alert_type_filter not in alerts_breakdown:
|
|
320
|
+
raise errors.InvalidArgumentError(
|
|
321
|
+
"Filtering of alerts failed: alert type %s does not exist"
|
|
322
|
+
% alert_type_filter
|
|
323
|
+
)
|
|
324
|
+
alerts = alerts_by_type[alert_type_filter]
|
|
325
|
+
end = self._checkBeginEndIndices(begin, end, len(alerts))
|
|
326
|
+
return {
|
|
327
|
+
"begin": begin,
|
|
328
|
+
"end": end,
|
|
329
|
+
"alert_type": alert_type_filter,
|
|
330
|
+
"num_alerts": num_alerts,
|
|
331
|
+
"alerts_breakdown": alerts_breakdown,
|
|
332
|
+
"per_type_alert_limit": DEFAULT_PER_TYPE_ALERT_LIMIT,
|
|
333
|
+
"alerts": [_alert_to_json(alert) for alert in alerts[begin:end]],
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
def ExecutionDigests(self, run, begin, end):
|
|
337
|
+
"""Get ExecutionDigests.
|
|
338
|
+
|
|
339
|
+
Args:
|
|
340
|
+
run: The tfdbg2 run to get `ExecutionDigest`s from.
|
|
341
|
+
begin: Beginning execution index.
|
|
342
|
+
end: Ending execution index.
|
|
343
|
+
|
|
344
|
+
Returns:
|
|
345
|
+
A JSON-serializable object containing the `ExecutionDigest`s and
|
|
346
|
+
related meta-information
|
|
347
|
+
"""
|
|
348
|
+
runs = self.Runs()
|
|
349
|
+
if run not in runs:
|
|
350
|
+
return None
|
|
351
|
+
# TODO(cais): For scalability, use begin and end kwargs when available in
|
|
352
|
+
# `DebugDataReader.execution()`.`
|
|
353
|
+
execution_digests = self._reader.executions(digest=True)
|
|
354
|
+
end = self._checkBeginEndIndices(begin, end, len(execution_digests))
|
|
355
|
+
return {
|
|
356
|
+
"begin": begin,
|
|
357
|
+
"end": end,
|
|
358
|
+
"num_digests": len(execution_digests),
|
|
359
|
+
"execution_digests": [
|
|
360
|
+
digest.to_json() for digest in execution_digests[begin:end]
|
|
361
|
+
],
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
def ExecutionData(self, run, begin, end):
|
|
365
|
+
"""Get Execution data objects (Detailed, non-digest form).
|
|
366
|
+
|
|
367
|
+
Args:
|
|
368
|
+
run: The tfdbg2 run to get `ExecutionDigest`s from.
|
|
369
|
+
begin: Beginning execution index.
|
|
370
|
+
end: Ending execution index.
|
|
371
|
+
|
|
372
|
+
Returns:
|
|
373
|
+
A JSON-serializable object containing the `ExecutionDigest`s and
|
|
374
|
+
related meta-information
|
|
375
|
+
"""
|
|
376
|
+
runs = self.Runs()
|
|
377
|
+
if run not in runs:
|
|
378
|
+
return None
|
|
379
|
+
execution_digests = self._reader.executions(digest=True)
|
|
380
|
+
end = self._checkBeginEndIndices(begin, end, len(execution_digests))
|
|
381
|
+
execution_digests = execution_digests[begin:end]
|
|
382
|
+
executions = self._reader.executions(digest=False, begin=begin, end=end)
|
|
383
|
+
return {
|
|
384
|
+
"begin": begin,
|
|
385
|
+
"end": end,
|
|
386
|
+
"executions": [execution.to_json() for execution in executions],
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
def GraphExecutionDigests(self, run, begin, end, trace_id=None):
|
|
390
|
+
"""Get `GraphExecutionTraceDigest`s.
|
|
391
|
+
|
|
392
|
+
Args:
|
|
393
|
+
run: The tfdbg2 run to get `GraphExecutionTraceDigest`s from.
|
|
394
|
+
begin: Beginning graph-execution index.
|
|
395
|
+
end: Ending graph-execution index.
|
|
396
|
+
|
|
397
|
+
Returns:
|
|
398
|
+
A JSON-serializable object containing the `ExecutionDigest`s and
|
|
399
|
+
related meta-information
|
|
400
|
+
"""
|
|
401
|
+
runs = self.Runs()
|
|
402
|
+
if run not in runs:
|
|
403
|
+
return None
|
|
404
|
+
# TODO(cais): Implement support for trace_id once the joining of eager
|
|
405
|
+
# execution and intra-graph execution is supported by DebugDataReader.
|
|
406
|
+
if trace_id is not None:
|
|
407
|
+
raise NotImplementedError(
|
|
408
|
+
"trace_id support for GraphExecutionTraceDigest is "
|
|
409
|
+
"not implemented yet."
|
|
410
|
+
)
|
|
411
|
+
graph_exec_digests = self._reader.graph_execution_traces(digest=True)
|
|
412
|
+
end = self._checkBeginEndIndices(begin, end, len(graph_exec_digests))
|
|
413
|
+
return {
|
|
414
|
+
"begin": begin,
|
|
415
|
+
"end": end,
|
|
416
|
+
"num_digests": len(graph_exec_digests),
|
|
417
|
+
"graph_execution_digests": [
|
|
418
|
+
digest.to_json() for digest in graph_exec_digests[begin:end]
|
|
419
|
+
],
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
def GraphExecutionData(self, run, begin, end, trace_id=None):
|
|
423
|
+
"""Get `GraphExecutionTrace`s.
|
|
424
|
+
|
|
425
|
+
Args:
|
|
426
|
+
run: The tfdbg2 run to get `GraphExecutionTrace`s from.
|
|
427
|
+
begin: Beginning graph-execution index.
|
|
428
|
+
end: Ending graph-execution index.
|
|
429
|
+
|
|
430
|
+
Returns:
|
|
431
|
+
A JSON-serializable object containing the `ExecutionDigest`s and
|
|
432
|
+
related meta-information
|
|
433
|
+
"""
|
|
434
|
+
runs = self.Runs()
|
|
435
|
+
if run not in runs:
|
|
436
|
+
return None
|
|
437
|
+
# TODO(cais): Implement support for trace_id once the joining of eager
|
|
438
|
+
# execution and intra-graph execution is supported by DebugDataReader.
|
|
439
|
+
if trace_id is not None:
|
|
440
|
+
raise NotImplementedError(
|
|
441
|
+
"trace_id support for GraphExecutionTraceData is "
|
|
442
|
+
"not implemented yet."
|
|
443
|
+
)
|
|
444
|
+
digests = self._reader.graph_execution_traces(digest=True)
|
|
445
|
+
end = self._checkBeginEndIndices(begin, end, len(digests))
|
|
446
|
+
graph_executions = self._reader.graph_execution_traces(
|
|
447
|
+
digest=False, begin=begin, end=end
|
|
448
|
+
)
|
|
449
|
+
return {
|
|
450
|
+
"begin": begin,
|
|
451
|
+
"end": end,
|
|
452
|
+
"graph_executions": [
|
|
453
|
+
graph_exec.to_json() for graph_exec in graph_executions
|
|
454
|
+
],
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
def GraphInfo(self, run, graph_id):
|
|
458
|
+
"""Get the information regarding a TensorFlow graph.
|
|
459
|
+
|
|
460
|
+
Args:
|
|
461
|
+
run: Name of the run.
|
|
462
|
+
graph_id: Debugger-generated ID of the graph in question.
|
|
463
|
+
This information is available in the return values
|
|
464
|
+
of `GraphOpInfo`, `GraphExecution`, etc.
|
|
465
|
+
|
|
466
|
+
Returns:
|
|
467
|
+
A JSON-serializable object containing the information regarding
|
|
468
|
+
the TensorFlow graph.
|
|
469
|
+
|
|
470
|
+
Raises:
|
|
471
|
+
NotFoundError if the graph_id is not known to the debugger.
|
|
472
|
+
"""
|
|
473
|
+
runs = self.Runs()
|
|
474
|
+
if run not in runs:
|
|
475
|
+
return None
|
|
476
|
+
try:
|
|
477
|
+
graph = self._reader.graph_by_id(graph_id)
|
|
478
|
+
except KeyError:
|
|
479
|
+
raise errors.NotFoundError(
|
|
480
|
+
'There is no graph with ID "%s"' % graph_id
|
|
481
|
+
)
|
|
482
|
+
return graph.to_json()
|
|
483
|
+
|
|
484
|
+
def GraphOpInfo(self, run, graph_id, op_name):
|
|
485
|
+
"""Get the information regarding a graph op's creation.
|
|
486
|
+
|
|
487
|
+
Args:
|
|
488
|
+
run: Name of the run.
|
|
489
|
+
graph_id: Debugger-generated ID of the graph that contains
|
|
490
|
+
the op in question. This ID is available from other methods
|
|
491
|
+
of this class, e.g., the return value of `GraphExecutionDigests()`.
|
|
492
|
+
op_name: Name of the op.
|
|
493
|
+
|
|
494
|
+
Returns:
|
|
495
|
+
A JSON-serializable object containing the information regarding
|
|
496
|
+
the op's creation and its immediate inputs and consumers.
|
|
497
|
+
|
|
498
|
+
Raises:
|
|
499
|
+
NotFoundError if the graph_id or op_name does not exist.
|
|
500
|
+
"""
|
|
501
|
+
runs = self.Runs()
|
|
502
|
+
if run not in runs:
|
|
503
|
+
return None
|
|
504
|
+
try:
|
|
505
|
+
graph = self._reader.graph_by_id(graph_id)
|
|
506
|
+
except KeyError:
|
|
507
|
+
raise errors.NotFoundError(
|
|
508
|
+
'There is no graph with ID "%s"' % graph_id
|
|
509
|
+
)
|
|
510
|
+
try:
|
|
511
|
+
op_creation_digest = graph.get_op_creation_digest(op_name)
|
|
512
|
+
except KeyError:
|
|
513
|
+
raise errors.NotFoundError(
|
|
514
|
+
'There is no op named "%s" in graph with ID "%s"'
|
|
515
|
+
% (op_name, graph_id)
|
|
516
|
+
)
|
|
517
|
+
data_object = self._opCreationDigestToDataObject(
|
|
518
|
+
op_creation_digest, graph
|
|
519
|
+
)
|
|
520
|
+
# Populate data about immediate inputs.
|
|
521
|
+
for input_spec in data_object["inputs"]:
|
|
522
|
+
try:
|
|
523
|
+
input_op_digest = graph.get_op_creation_digest(
|
|
524
|
+
input_spec["op_name"]
|
|
525
|
+
)
|
|
526
|
+
except KeyError:
|
|
527
|
+
input_op_digest = None
|
|
528
|
+
if input_op_digest:
|
|
529
|
+
input_spec["data"] = self._opCreationDigestToDataObject(
|
|
530
|
+
input_op_digest, graph
|
|
531
|
+
)
|
|
532
|
+
# Populate data about immediate consuming ops.
|
|
533
|
+
for slot_consumer_specs in data_object["consumers"]:
|
|
534
|
+
for consumer_spec in slot_consumer_specs:
|
|
535
|
+
try:
|
|
536
|
+
digest = graph.get_op_creation_digest(
|
|
537
|
+
consumer_spec["op_name"]
|
|
538
|
+
)
|
|
539
|
+
except KeyError:
|
|
540
|
+
digest = None
|
|
541
|
+
if digest:
|
|
542
|
+
consumer_spec["data"] = self._opCreationDigestToDataObject(
|
|
543
|
+
digest, graph
|
|
544
|
+
)
|
|
545
|
+
return data_object
|
|
546
|
+
|
|
547
|
+
def _opCreationDigestToDataObject(self, op_creation_digest, graph):
|
|
548
|
+
if op_creation_digest is None:
|
|
549
|
+
return None
|
|
550
|
+
json_object = op_creation_digest.to_json()
|
|
551
|
+
del json_object["graph_id"]
|
|
552
|
+
json_object["graph_ids"] = self._getGraphStackIds(
|
|
553
|
+
op_creation_digest.graph_id
|
|
554
|
+
)
|
|
555
|
+
# TODO(cais): "num_outputs" should be populated in to_json() instead.
|
|
556
|
+
json_object["num_outputs"] = op_creation_digest.num_outputs
|
|
557
|
+
del json_object["input_names"]
|
|
558
|
+
|
|
559
|
+
json_object["inputs"] = []
|
|
560
|
+
for input_tensor_name in op_creation_digest.input_names or []:
|
|
561
|
+
input_op_name, output_slot = parse_tensor_name(input_tensor_name)
|
|
562
|
+
json_object["inputs"].append(
|
|
563
|
+
{"op_name": input_op_name, "output_slot": output_slot}
|
|
564
|
+
)
|
|
565
|
+
json_object["consumers"] = []
|
|
566
|
+
for _ in range(json_object["num_outputs"]):
|
|
567
|
+
json_object["consumers"].append([])
|
|
568
|
+
for src_slot, consumer_op_name, dst_slot in graph.get_op_consumers(
|
|
569
|
+
json_object["op_name"]
|
|
570
|
+
):
|
|
571
|
+
json_object["consumers"][src_slot].append(
|
|
572
|
+
{"op_name": consumer_op_name, "input_slot": dst_slot}
|
|
573
|
+
)
|
|
574
|
+
return json_object
|
|
575
|
+
|
|
576
|
+
def _getGraphStackIds(self, graph_id):
|
|
577
|
+
"""Retrieve the IDs of all outer graphs of a graph.
|
|
578
|
+
|
|
579
|
+
Args:
|
|
580
|
+
graph_id: Id of the graph being queried with respect to its outer
|
|
581
|
+
graphs context.
|
|
582
|
+
|
|
583
|
+
Returns:
|
|
584
|
+
A list of graph_ids, ordered from outermost to innermost, including
|
|
585
|
+
the input `graph_id` argument as the last item.
|
|
586
|
+
"""
|
|
587
|
+
graph_ids = [graph_id]
|
|
588
|
+
graph = self._reader.graph_by_id(graph_id)
|
|
589
|
+
while graph.outer_graph_id:
|
|
590
|
+
graph_ids.insert(0, graph.outer_graph_id)
|
|
591
|
+
graph = self._reader.graph_by_id(graph.outer_graph_id)
|
|
592
|
+
return graph_ids
|
|
593
|
+
|
|
594
|
+
def SourceFileList(self, run):
|
|
595
|
+
runs = self.Runs()
|
|
596
|
+
if run not in runs:
|
|
597
|
+
return None
|
|
598
|
+
return self._reader.source_file_list()
|
|
599
|
+
|
|
600
|
+
def SourceLines(self, run, index):
|
|
601
|
+
runs = self.Runs()
|
|
602
|
+
if run not in runs:
|
|
603
|
+
return None
|
|
604
|
+
try:
|
|
605
|
+
host_name, file_path = self._reader.source_file_list()[index]
|
|
606
|
+
except IndexError:
|
|
607
|
+
raise errors.NotFoundError(
|
|
608
|
+
"There is no source-code file at index %d" % index
|
|
609
|
+
)
|
|
610
|
+
return {
|
|
611
|
+
"host_name": host_name,
|
|
612
|
+
"file_path": file_path,
|
|
613
|
+
"lines": self._reader.source_lines(host_name, file_path),
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
def StackFrames(self, run, stack_frame_ids):
|
|
617
|
+
runs = self.Runs()
|
|
618
|
+
if run not in runs:
|
|
619
|
+
return None
|
|
620
|
+
stack_frames = []
|
|
621
|
+
for stack_frame_id in stack_frame_ids:
|
|
622
|
+
if stack_frame_id not in self._reader._stack_frame_by_id:
|
|
623
|
+
raise errors.NotFoundError(
|
|
624
|
+
"Cannot find stack frame with ID %s" % stack_frame_id
|
|
625
|
+
)
|
|
626
|
+
# TODO(cais): Use public method (`stack_frame_by_id()`) when
|
|
627
|
+
# available.
|
|
628
|
+
# pylint: disable=protected-access
|
|
629
|
+
stack_frames.append(self._reader._stack_frame_by_id[stack_frame_id])
|
|
630
|
+
# pylint: enable=protected-access
|
|
631
|
+
return {"stack_frames": stack_frames}
|