code: def process_data(data, func_info, so_ld_addr):
      """Process data"""
      # Keep an ordered list of loop IDs as they are being visited. This is used
      # to match entry and exit pairs. Once the function/loop is processed, it's
      # removed from the list.
      ordered_visited_list = []
      # Store information regarding visited nodes as they are being processed. Once
      # the function/loop is processed, it's removed from the set.
      visited_set = {}
      # Dictionary to store cycles for the entire model which is grouped into functions.
      overall_cycles = {}
      func_cycles = {}
  
      func_idx = -1
      func_name = ""
      prev_func_name = ""
      func_start = 0
      func_end = 0
      save_data = False
      # Iterate over all the entries in the LWP data file and process them
      # to construct a report.
      for entry in data["entries"]:
          id = entry["id"]
          offset = entry["ret"] - so_ld_addr
  
          # Recorded return address should fall within the function begin and end
          # offsets. If not, find the function it belongs to.
          if offset < func_start or offset > func_end:
              prev_func_name = func_name
              if ENABLE_DEBUG:
                  print("offset : ", offset)
                  print("id : ", id)
  
              func_idx = find_func(func_info, offset)
              func_name = func_info[func_idx]["name"]
              func_start = func_info[func_idx]["start"]
              func_end = func_info[func_idx]["end"]
              if ENABLE_DEBUG:
                  print("func_name : ", func_name)
  
              if save_data:
                  # overall_cycles = save_func_cycles(prev_func_name, overall_cycles, func_cycles, ordered_visited_list)
                  # Done processing the previous function, copy its info into 'overall_cycles'.
                  if prev_func_name not in overall_cycles:
                      overall_cycles[
                          prev_func_name
                      ] = func_cycles.copy()
                  else:
                      # Accumulate cycles into existing function entry.
                      overall_cycles = accumulate_cycles(
                          overall_cycles, func_cycles, prev_func_name
                      )
                  # We don't allow for fused operators (functions) calling another operator.
                  if ENABLE_DEBUG:
                      print(
                          "ordered_visited_list : ",
                          ordered_visited_list,
                      )
  
                  assert len(ordered_visited_list) == 0, (
                      f"\nDone processing function [{prev_func_name}] but ordered_visited_list not empty.\n"
                      f"\t Possible reasons -- \n"
                      f"\t\t1) Mismatch between model .so and json file.\n"
                      f"\t\t2) LWP buffer may have overflowed resulting into missing entries!"
                  )
                  func_cycles.clear()
  
              save_data = True
  
          if id not in visited_set:  # Found 'entry' record
              visited_info = {
                  "func_idx": func_idx,
                  "ret": offset,
                  "cyc": entry["cyc"],
              }
              visited_set[id] = visited_info
              ordered_visited_list.append(id)
          else:  # Found 'exit' record
              # This should be the last entry in the ordered_visited_list. If not, error out.
              assert ordered_visited_list[-1] == id, (
                  "Problem with LWP output - Interleaved handler calls found."
                  f"Loop [{ordered_visited_list[-1]}] hasn't exited yet."
              )
              ordered_visited_list.pop()
              entry_node = visited_set.pop(id)
              assert (
                  entry_node["func_idx"] == func_idx
              ), f'Error - Found under a different function name : {entry_node["func_idx"]}'
              cycles = entry["cyc"] - entry_node["cyc"]
              parent = -1
              if ordered_visited_list:
                  parent = int(ordered_visited_list[-1])
              if id in func_cycles:
                  fcycles = func_cycles[id]
                  fcycles["cycles"] += cycles
                  fcycles["count"] += 1
                  func_cycles[id] = fcycles
              else:
                  func_cycles[id] = {
                      "cycles": cycles,
                      "start": entry_node["ret"],
                      "end": offset,
                      "parent": parent,
                      "count": 1,
                  }
  
      # Done processing the previous function, copy its info into 'overall_cycles'.
      if func_name not in overall_cycles:
          overall_cycles[func_name] = func_cycles.copy()
      else:
          # Accumulate cycles into existing function entry.
          overall_cycles = accumulate_cycles(
              overall_cycles, func_cycles, func_name
          )
      # We don't allow for fused operators (functions) calling another operator.
      if ENABLE_DEBUG:
          print("ordered_visited_list : ", ordered_visited_list)
  
      assert len(ordered_visited_list) == 0, (
          f"\nDone processing function [{prev_func_name}] but ordered_visited_list not empty.\n"
          f"\t Possible reasons -- \n"
          f"\t\t1) Mismatch between model .so and json file.\n"
          f"\t\t2) LWP buffer may have overflowed resulting into missing entries!"
      )
  
      overall_cycles = adjust_per_loop_counts(overall_cycles, data)
      return overall_cycles
  
file_path: tvm/python/tvm/contrib/hexagon/profiling/process_lwp_data.py
imports: import json
  import csv
  import subprocess
  import argparse
  import os
  from re import search, compile
  from collections import OrderedDict
label_desc: Use image node_id 6 for calling a global function with example usage: process_data(data, func_info, so_ld_addr) and returns: overall_cycles