class_docstr: Analysis communication and computation time range, and their overlap.
  The computation time is all kernel except kernels for communication like nccl.
class_docstr_tok: ["Analysis","communication","and","computation","time","range",",","and","their","overlap",".","The","computation","time","is","all","kernel","except","kernels","for","communication","like","nccl","."]
docstr: Collect all communication and computation time ranges.
docstr_tok: ["Collect","all","communication","and","computation","time","ranges","."]
code: def parse(self, nodetrees):
      """
      Collect all communication and computation time ranges.
      """
      total_time = 0.0
      nodetrees = rebuild_node_trees(nodetrees)
      thread2hostnodes = traverse_tree(nodetrees)
      thread_count = 0
      for threadid, hostnodes in thread2hostnodes.items():
          for hostnode in hostnodes[1:]:  # skip root node
              # case 1: TracerEventType is Communication
              if hostnode.type == "ProfileStep":
                  if thread_count == 0:
                      total_time += hostnode.end_ns - hostnode.start_ns
                  self._parse_step(hostnode)
                  continue
          thread_count += 1
  
      new_steps_data = defaultdict(lambda: defaultdict(list))
      self.profile_steps_time["All"] = total_time
      for step, step_data in self.steps_data.items():
          self.calls[step]["cpu_communication_range"] = len(
              step_data["cpu_communication_range"]
          )
          self.calls[step]["gpu_communication_range"] = len(
              step_data["gpu_communication_range"]
          )
          new_steps_data[step][
              "cpu_communication_range"
          ] = merge_self_ranges(
              step_data["cpu_communication_range"], is_sorted=False
          )
          new_steps_data[step][
              "gpu_communication_range"
          ] = merge_self_ranges(
              step_data["gpu_communication_range"], is_sorted=False
          )
          new_steps_data[step]["communication_range"] = merge_ranges(
              new_steps_data[step]["cpu_communication_range"],
              new_steps_data[step]["gpu_communication_range"],
              is_sorted=True,
          )
          new_steps_data[step]["computation_range"] = merge_self_ranges(
              step_data["computation_range"], is_sorted=False
          )
          new_steps_data[step]["overlap_range"] = intersection_ranges(
              new_steps_data[step]["communication_range"],
              new_steps_data[step]["computation_range"],
              is_sorted=True,
          )
          self.steps_time[step]["communication_time"] = sum_ranges(
              new_steps_data[step]["communication_range"]
          )
          self.steps_time[step]["computation_time"] = sum_ranges(
              new_steps_data[step]["computation_range"]
          )
          self.steps_time[step]["overlap_time"] = sum_ranges(
              new_steps_data[step]["overlap_range"]
          )
          self.steps_time[step]["others_time"] = (
              self.profile_steps_time[step]
              - self.steps_time[step]["communication_time"]
              - self.steps_time[step]["computation_time"]
              + self.steps_time[step]["overlap_time"]
          )
      self.steps_data = new_steps_data
  
file_path: VisualDL/visualdl/component/profiler/parser/distributed_parser.py
imports: from collections import defaultdict
  from .utils import get_device_nodes
  from .utils import intersection_ranges
  from .utils import merge_ranges
  from .utils import merge_self_ranges
  from .utils import rebuild_node_trees
  from .utils import sum_ranges
  from .utils import traverse_tree
label_desc: Use image node_id 2 for calling the DistributedParser obj's underlying member method code with example usage: obj.parse(nodetrees) without return types