class_docstr: Execute an FX graph Node-by-Node and record the meta data of the result
  into the corresponding node.
  
  Usage:
      >>> model = MyModule()
      >>> x = torch.rand(10, 10)
      >>> gm = colossalai.fx.symbolic_trace(model, meta_args = {'x': x}})
      >>> shape_interp = ShapeProp(gm)    # must do this first
      >>> shape_interp.propagate(x)
      >>> profiler = FlopProfiler(gm)
      >>> profiler.propagate(x)
  
  Args:
      module (GraphModule): The module to be executed
  
  Hints:
      If you want to add a new flop count rule, you can first
      check the existing files in ``../_subclasses/flop_tensor.py``.
      If your flop count rules are incompatible with the existing
      ones, you can do so by adding a new method to this class
      with the ``@register_flop_count_impl`` decorator. The method
      should take (*args, **kwargs) instance as its input and
      generate flop count for both forward and backward as its
      output.
  
      For example, if you want to add a flop count rule for
      ``my_fn``, which is a hand-written operand not detected by
      PyTorch, you can do so by adding a new method to this
      class with the ``@register_flop_count_impl`` decorator:
  
      >>> @register_flop_count_impl(my_fn)
      >>> def my_fn_flop_count_impl(*args, **kwargs):
      >>>     return 0, 0
docstr: Run a specific node ``n`` and profile its execution time and memory usage.
  Calls into call_function, call_method, and call_module only.
  
  Args:
      n (Node): The Node to profile
  
  Returns:
      Any: The output of the node
  
  Raises:
      RuntimeError: If the node is not profileable.
docstr_tok: ["Run","a","specific","node","``","n","``","and","profile","its","execution","time","and","memory","usage",".","Calls","into","call_function",",","call_method",",","and","call_module","only",".","Args",":","n","(","Node",")",":","The","Node","to","profile","Returns",":","Any",":","The","output","of","the","node","Raises",":","RuntimeError",":","If","the","node","is","not","profileable","."]
code: def run_node(self, n: torch.fx.Node) -> Any:
      """
      Run a specific node ``n`` and profile its execution time and memory usage.
      Calls into call_function, call_method, and call_module only.
  
      Args:
          n (Node): The Node to profile
  
      Returns:
          Any: The output of the node
  
      Raises:
          RuntimeError: If the node is not profileable.
      """
      args, kwargs = self.fetch_args_kwargs_from_env(n)
      n_info = MetaInfo(n)
  
      if n.op in self._profileable:
          try:
              (
                  n_info.fwd_flop,
                  n_info.bwd_flop,
              ) = getattr(
                  self, n.op
              )(n.target, args, kwargs)
          except Exception as e:
              raise RuntimeError(
                  f"Error {str(e)} occurred when profiling node {n}, node.target = {n.target}. "
                  f"Please refer to function's docstring to register the relevant profile_impl for this node!"
              ) from e
  
      # retain the autograd graph
      for param in self.module.parameters():
          param.grad = None
  
      return _denormalize_tuple(n_info.outputs)
  
imports: from typing import Any, Dict, Iterator, List, Optional, Tuple
  import torch
  import torch.fx
  from torch.autograd.profiler_util import _format_memory
  from torch.fx import GraphModule
  from torch.fx.node import Argument, Node, Target
  from colossalai._analyzer._subclasses import flop_count
  from colossalai._analyzer.fx.node_util import MetaInfo
label_desc: Use image node_id 1 for calling the FlopProfiler obj's underlying member method code with example usage: obj.run_node(n) and returns: _denormalize_tuple