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","."]
code: def _parse_step(self, profile_step_node):
      step = profile_step_node.name.split("#")[1]
      self.profile_steps_time[step] = (
          profile_step_node.end_ns - profile_step_node.start_ns
      )
      nodes = []
      stack = []
      stack.append(profile_step_node)
      while stack:
          current_node = stack.pop()
          nodes.append(current_node)
          for childnode in current_node.children_node:
              stack.append(childnode)
      for hostnode in nodes:
          if hostnode.type == "Communication":
              self.steps_data[step]["cpu_communication_range"].append(
                  (hostnode.start_ns, hostnode.end_ns)
              )
              self.steps_data["All"]["cpu_communication_range"].append(
                  (hostnode.start_ns, hostnode.end_ns)
              )
              device_nodes = get_device_nodes(hostnode)
              for device_node in device_nodes:
                  if device_node.type == "Kernel":
                      self.steps_data[step][
                          "gpu_communication_range"
                      ].append(
                          (device_node.start_ns, device_node.end_ns)
                      )
                      self.steps_data["All"][
                          "gpu_communication_range"
                      ].append(
                          (device_node.start_ns, device_node.end_ns)
                      )
  
          # case 2: TracerEventType is Operator but is communication op
          elif hostnode.type == "Operator" and any(
              [
                  name in hostnode.name.lower()
                  for name in _CommunicationOpName
              ]
          ):
              self.steps_data[step]["cpu_communication_range"].append(
                  (hostnode.start_ns, hostnode.end_ns)
              )
              self.steps_data["All"]["cpu_communication_range"].append(
                  (hostnode.start_ns, hostnode.end_ns)
              )
              device_nodes = get_device_nodes(hostnode)
              for device_node in device_nodes:
                  if device_node.type == "Kernel":
                      self.steps_data[step][
                          "gpu_communication_range"
                      ].append(
                          (device_node.start_ns, device_node.end_ns)
                      )
                      self.steps_data["All"][
                          "gpu_communication_range"
                      ].append(
                          (device_node.start_ns, device_node.end_ns)
                      )
  
          # case 3: Others, filter kernels named with nccl
          else:
              for runtimenode in hostnode.runtime_node:
                  for devicenode in runtimenode.device_node:
                      if devicenode.type == "Kernel":
                          if "nccl" in devicenode.name.lower():
                              self.steps_data[step][
                                  "gpu_communication_range"
                              ].append(
                                  (
                                      devicenode.start_ns,
                                      devicenode.end_ns,
                                  )
                              )
                              self.steps_data["All"][
                                  "gpu_communication_range"
                              ].append(
                                  (
                                      devicenode.start_ns,
                                      devicenode.end_ns,
                                  )
                              )
                          else:
                              self.steps_data[step][
                                  "computation_range"
                              ].append(
                                  (
                                      devicenode.start_ns,
                                      devicenode.end_ns,
                                  )
                              )
                              self.steps_data["All"][
                                  "computation_range"
                              ].append(
                                  (
                                      devicenode.start_ns,
                                      devicenode.end_ns,
                                  )
                              )
  
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 3 for calling the DistributedParser obj's underlying member method code with example usage: obj._parse_step(profile_step_node) without return types