-
Notifications
You must be signed in to change notification settings - Fork 1.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Make text plugin's is_active method check for data in multiplexer first before checking plugin assets. #1021
Conversation
We make the text plugin's is_active method short-circuit if it detects relevant data present within the multiplexer. Subsequently, there would be no more need to check for data stored within plugin assets.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the fix! I maybe would adjust the PR title slightly - the text plugin does already short-circuit in is_active(). What this PR fixes is that it always defaults to False on the first attempt; it can be smarter than that by checking the multiplexer first, since that part is cheap (it's just the plugin assets reads that aren't).
|
||
def _fetch_run_to_series_from_multiplexer(self): | ||
run_to_series = collections.defaultdict(list) | ||
# TensorBoard is obtaining summaries related to the text plugin based on | ||
# SummaryMetadata stored within Value protos. | ||
mapping = self._multiplexer.PluginRunToTagToContent(metadata.PLUGIN_NAME) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The "Augment the summaries..." comment a few lines down (grrrr github disallowing comments outside diffs) no longer applies here, it should probably be relocated - though I'm not actually sure introducing this helper is necessary? think the main thing is just checking the multiplexer in is_active(), otherwise index_impl() should work fine as is.
If we do keep the helper, the logic can also be simplified, this is pretty much just
return {run: list(tag_to_content.keys()) for run, tag_to_content in six.iteritems(mapping)}
I guess you're actually using the fact that it's a defaultdict(list) up in index_impl() but I might opt to avoid that dependency, since defaultdict is a bit subtle and relying on a given dict return value to actually be a defaultdict seems a bit hazardous unless clearly documented.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, indeed! We can concisely write the expression like that. And yes, lets use a normal dict since runs with no data map to empty lists. I kept the helper since we also use it within tags_impl
so that route is consistent with the plugin being active.
Also, removed the duplicate comment.
name = 'tensorboard_text' | ||
run_to_assets = self._multiplexer.PluginAssets(name) | ||
for run, assets in run_to_assets.items(): | ||
if 'tensors.json' in assets: | ||
tensors_json = self._multiplexer.RetrievePluginAsset( | ||
run, name, 'tensors.json') | ||
tensors = json.loads(tensors_json) | ||
run_to_series[run] = tensors | ||
run_to_series[run] += tensors |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we change these to += we probably want to do deduping, since I doubt we want duplicated tags if there are cases during the transition from legacy to new formats where the same tags were recorded in both places.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+1, now, new-style summaries override old-style ones per prior behavior.
else: | ||
run_to_series[run] = [] | ||
run_to_series[run] += [] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
+= [] on a list has no effect, might as well just omit this whole else
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done - changed to = []
. Added a comment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, but text_plugin_test.py is failing:
======================================================================
FAIL: testPluginIsActiveWhenTextRuns (__main__.TextPluginTest)
The plugin should be active when there are runs with text.
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/travis/.bazel-output-base/bazel-sandbox/2750984358386572954/execroot/org_tensorflow_tensorboard/bazel-out/k8-fastbuild/bin/tensorboard/plugins/text/text_plugin_test.runfiles/org_tensorflow_tensorboard/tensorboard/plugins/text/text_plugin_test.py", line 372, in testPluginIsActiveWhenTextRuns
self.assertIsActive(plugin, True)
File "/home/travis/.bazel-output-base/bazel-sandbox/2750984358386572954/execroot/org_tensorflow_tensorboard/bazel-out/k8-fastbuild/bin/tensorboard/plugins/text/text_plugin_test.runfiles/org_tensorflow_tensorboard/tensorboard/plugins/text/text_plugin_test.py", line 336, in assertIsActive
self.assertFalse(plugin.is_active())
AssertionError: True is not false
======================================================================
FAIL: testPluginTagsImpl (__main__.TextPluginTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/travis/.bazel-output-base/bazel-sandbox/2750984358386572954/execroot/org_tensorflow_tensorboard/bazel-out/k8-fastbuild/bin/tensorboard/plugins/text/text_plugin_test.runfiles/org_tensorflow_tensorboard/tensorboard/plugins/text/text_plugin_test.py", line 391, in testPluginTagsImpl
self.assertEqual({}, self.plugin.tags_impl())
AssertionError: {} != {'fry': [u'message', u'vector'], 'leela': [u'message', u'vector']}
- {}
+ {'fry': [u'message', u'vector'], 'leela': [u'message', u'vector']}
----------------------------------------------------------------------
@@ -234,9 +235,15 @@ def is_active(self): | |||
if any(self._index_cached.values()): | |||
return True | |||
|
|||
if bool(self._multiplexer.PluginRunToTagToContent(metadata.PLUGIN_NAME)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think having if bool(expr)
is redundant - you can just do if expr
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
else: | ||
run_to_series[run] += [] | ||
# The mapping should contain all runs among its keys. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah ok, good catch. I feel like some plugins expect this (that index_impl()
includes all runs, not just those with plugin data for that plugin) but not all of them? Do we have a set standard or is this just up to any plugin?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For all plugins, the "runs"/"tags" route should list all runs, not just those that include text summaries. Without this, the existing infrastructure breaks when it tries to look up non-plugin-specific runs in the run-to-tag mapping. There's a brief description within the internal change that removes the tf-sidebar-helper
component.
for (run, tags) in mapping.items(): | ||
run_to_series[run] += tags.keys() | ||
return run_to_series | ||
mapping = six.iteritems( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: strictly speaking this isn't a mapping, it's an iterable of dict items - maybe rename to "items" or conversely, move the six.iteritems() call to inside the dict comprehension.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Done.
Modified tests to check for correct behavior when the plugin detects relevant data within the multiplexer. Specifically, in that case, 1. The thread that seeks plugin assets data should not start. 2. The plugin should be active despite how that thread had not started. 3. The tags route should respond with multiplexer data.
Previously, text_plugin_test sometimes failed because tensorflow#1021 made the test check for complete dictionary equality, and tags may appear in different orders. This fix makes the test check for equality of content within lists, regardless of order. This makes the test parallel previous test logic for tags.
Previously, text_plugin_test sometimes failed because #1021 made the test check for complete dictionary equality, and tags may appear in different orders for each test run. This fix makes the test check for equality of content within lists, regardless of order. This makes the test parallel previous test logic for tags.
We make the text plugin's is_active method return true if it detects
relevant data present within the multiplexer. Subsequently, there would
be no more need to check for data stored within plugin assets.
This solves an issue: The text plugin used to be inactive when the user
initially loads into it because the thread for computing whether the plugin
is active would not have completed executing yet.
Part of #625.
Test plan:
Run the text demo. Verify behavior. The text plugin should be active on
the first load.