code: def torch_profiler_time_cpu_gpu(func):
      """
      A decorator which measures the execution time of both the CPU and GPU components
      of the decorated function, printing both results.
      Note: Enforces a gpu sync point which could slow down pipelines.
      """
  
      @wraps(func)
      def wrapper(*args, **kwargs):
          with torch.autograd.profiler.profile(use_cuda=True) as prof:
              result = func(*args, **kwargs)
  
          cpu_time = prof.self_cpu_time_total
          gpu_time = sum(
              evt.self_cuda_time_total for evt in prof.function_events
          )
  
          cpu_time = torch.autograd.profiler.format_time(cpu_time)  # type: ignore
          gpu_time = torch.autograd.profiler.format_time(gpu_time)  # type: ignore
  
          print(
              f"cpu time: {cpu_time}, gpu time: {gpu_time}", flush=True
          )
  
          return result
  
      return wrapper
  
imports: from __future__ import annotations
  import csv
  import datetime
  import multiprocessing
  import os
  import sys
  import threading
  from collections import defaultdict, namedtuple
  from contextlib import contextmanager
  from functools import wraps
  from inspect import getframeinfo, stack
  from queue import Empty
  from time import perf_counter, perf_counter_ns
  from typing import TYPE_CHECKING, Any, cast
  import numpy
  import torch
  from monai.utils import optional_import
label_desc: Use image node_id 2 for calling a global function with example usage: torch_profiler_time_cpu_gpu(func) and returns: wrapper, result