code: def build_tree(  # noqa: C901
      self, hostnodes, runtimenodes, devicenodes, memnodes
  ):
      thread2host_event_nodes = collections.defaultdict(list)
      thread2runtime_event_nodes = collections.defaultdict(list)
      thread2mem_event_nodes = collections.defaultdict(list)
      correlation_id2runtime_event_node = {}
      thread_event_trees = {}
      thread_ids = set()
      for hostnode in hostnodes:
          thread2host_event_nodes[hostnode.thread_id].append(hostnode)
          thread_ids.add(hostnode.thread_id)
      # construct thread2runtime_event_nodes and correlation_id2runtime_event_node
      for runtimenode in runtimenodes:
          thread2runtime_event_nodes[runtimenode.thread_id].append(
              runtimenode
          )
          thread_ids.add(runtimenode.thread_id)
          correlation_id2runtime_event_node[
              runtimenode.correlation_id
          ] = runtimenode
  
      # associate CudaRuntimeTraceEventNode and DeviceTraceEventNode
      # construct correlation_id2device_event_nodes
      for devicenode in devicenodes:
          if (
              devicenode.correlation_id
              not in correlation_id2runtime_event_node
          ):
              continue
          runtimenode = correlation_id2runtime_event_node[
              devicenode.correlation_id
          ]
          runtimenode.device_node.append(devicenode)
  
      # construct thread2mem_event_nodes
      for memnode in memnodes:
          thread2mem_event_nodes[memnode.thread_id].append(memnode)
      # sort host event nodes and runtime event nodes according to start_ns and
      # end_ns
      # the smaller start_ns is, the further ahead position is.
      # when start_ns of two nodes are equal, the one with bigger end_ns should be
      # ahead.
  
      def compare_hostnode_func(hostnode1, hostnode2):
          if hostnode1.start_ns < hostnode2.start_ns:
              return -1
          if hostnode1.start_ns == hostnode2.start_ns:
              if hostnode1.end_ns > hostnode2.end_ns:
                  return -1
          return 1
  
      def compare_memnode_func(memnode1, memnode2):
          if memnode1.timestamp_ns <= memnode2.timestamp_ns:
              return -1
          return 1
  
      for threadid, hostnodes in thread2host_event_nodes.items():
          thread2host_event_nodes[threadid] = sorted(
              hostnodes, key=functools.cmp_to_key(compare_hostnode_func)
          )
      for threadid, runtimenodes in thread2runtime_event_nodes.items():
          thread2runtime_event_nodes[threadid] = sorted(
              runtimenodes,
              key=functools.cmp_to_key(compare_hostnode_func),
          )
      for threadid, memnodes in thread2mem_event_nodes.items():
          thread2mem_event_nodes[threadid] = sorted(
              memnodes, key=functools.cmp_to_key(compare_memnode_func)
          )
  
      # construct trees
      for threadid in thread_ids:
          thread_event_trees[threadid] = self._build_tree_relationship(
              thread2host_event_nodes[threadid],
              thread2runtime_event_nodes[threadid],
              thread2mem_event_nodes[threadid],
          )
  
      return thread_event_trees
  
imports: import collections
  import functools
  import json
  import re
  import sys
  import tempfile
  from .utils import traverse_tree
label_desc: Use image node_id 4 for calling the ProfilerResult obj's underlying member method code with example usage: obj.build_tree(hostnodes, runtimenodes, devicenodes, memnodes) and returns: thread_event_trees, int, int, unknown, unknown, unknown