<SYSTEM_TASK:>
Solve the following problem using Python, implementing the functions described below, one line at a time
<END_TASK>
<USER_TASK:>
Description:
 def generate_run_to_tools(self):
 """Generator for pairs of "run name" and a list of tools for that run. The "run name" here is a "frontend run name" - see _run_dir() for the definition of a "frontend run name" and how it maps to a directory of profile data for a specific profile "run". The profile plugin concept of "run" is different from the normal TensorBoard run; each run in this case represents a single instance of profile data collection, more similar to a "step" of data in typical TensorBoard semantics. These runs reside in subdirectories of the plugins/profile directory within any regular TensorBoard run directory (defined as a subdirectory of the logdir that contains at least one tfevents file) or within the logdir root directory itself (even if it contains no tfevents file and would thus not be considered a normal TensorBoard run, for backwards compatibility). Within those "profile run directories", there are files in the directory that correspond to different profiling tools. The file that contains profile for a specific tool "x" will have a suffix name TOOLS["x"]. Example: logs/ plugins/ profile/ run1/ hostA.trace train/ events.out.tfevents.foo plugins/ profile/ run1/ hostA.trace hostB.trace run2/ hostA.trace validation/ events.out.tfevents.foo plugins/ profile/ run1/ hostA.trace Yields: A sequence of tuples mapping "frontend run names" to lists of tool names available for those runs. For the above example, this would be: ("run1", ["trace_viewer"]) ("train/run1", ["trace_viewer"]) ("train/run2", ["trace_viewer"]) ("validation/run1", ["trace_viewer"]) """

    self.start_grpc_stub_if_necessary()

    plugin_assets = self.multiplexer.PluginAssets(PLUGIN_NAME)
    tb_run_names_to_dirs = self.multiplexer.RunPaths()

    # Ensure that we also check the root logdir, even if it isn't a recognized
    # TensorBoard run (i.e. has no tfevents file directly under it), to remain
    # backwards compatible with previously profile plugin behavior. Note that we
    # check if logdir is a directory to handle case where it's actually a
    # multipart directory spec, which this plugin does not support.
    if '.' not in plugin_assets and tf.io.gfile.isdir(self.logdir):
      tb_run_names_to_dirs['.'] = self.logdir
      plugin_assets['.'] = plugin_asset_util.ListAssets(
          self.logdir, PLUGIN_NAME)

    for tb_run_name, profile_runs in six.iteritems(plugin_assets):
      tb_run_dir = tb_run_names_to_dirs[tb_run_name]
      tb_plugin_dir = plugin_asset_util.PluginDirectory(
          tb_run_dir, PLUGIN_NAME)
      for profile_run in profile_runs:
        # Remove trailing slash; some filesystem implementations emit this.
        profile_run = profile_run.rstrip('/')
        if tb_run_name == '.':
          frontend_run = profile_run
        else:
          frontend_run = '/'.join([tb_run_name, profile_run])
        profile_run_dir = os.path.join(tb_plugin_dir, profile_run)
        if tf.io.gfile.isdir(profile_run_dir):
          yield frontend_run, self._get_active_tools(profile_run_dir)