class_docstr: Object to store runtime and memory profiling information for all of
  PyTensor's operations: compilation, rewriting, execution.
  
  Parameters
  ----------
  atexit_print : bool
      True means that this object will be printed to stderr (using .summary())
      at the end of the program.
  **kwargs : misc initializers
      These should (but need not) match the names of the class vars declared
      in this class.
class_docstr_tok: ["Object","to","store","runtime","and","memory","profiling","information","for","all","of","PyTensor","'s","operations",":","compilation",",","rewriting",",","execution",".","Parameters","--","--","--","--","--","atexit_print",":","bool","True","means","that","this","object","will","be","printed","to","stderr","(","using",".summary","(",")",")","at","the","end","of","the","program",".","*","*","kwargs",":","misc","initializers","These","should","(","but","need","not",")","match","the","names","of","the","class","vars","declared","in","this","class","."]
code: def summary_function(self, file):
      print("Function profiling", file=file)
      print("==================", file=file)
      print(f"  Message: {self.message}", file=file)
      print(
          f"  Time in {self.fct_callcount} calls to Function.__call__: {self.fct_call_time:e}s",
          file=file,
      )
      if self.fct_call_time > 0:
          print(
              f"  Time in Function.vm.__call__: {self.vm_call_time}s ({100 * self.vm_call_time / self.fct_call_time:.3f}%)",
              file=file,
          )
          local_time = sum(self.apply_time.values())
          if local_time > 0:
              print(
                  f"  Time in thunks: {local_time}s ({100 * local_time / self.fct_call_time:.3f}%)",
                  file=file,
              )
      print(
          f"  Total compilation time: {self.compile_time:e}s", file=file
      )
      print(
          f"    Number of Apply nodes: {int(self.nb_nodes)}", file=file
      )
      print(
          f"    PyTensor rewrite time: {self.rewriting_time:e}s",
          file=file,
      )
      print(
          f"       PyTensor validate time: {self.validate_time:e}s",
          file=file,
      )
      print(
          (
              "    PyTensor Linker time (includes C, CUDA code "
              f"generation/compiling): {self.linker_time}s"
          ),
          file=file,
      )
      print(
          f"       C-cache preloading {self.preload_cache_time:e}s",
          file=file,
      )
      print(f"       Import time {self.import_time:e}s", file=file)
      print(
          f"       Node make_thunk time {self.linker_node_make_thunks:e}s",
          file=file,
      )
  
      for node, t in sorted(
          self.linker_make_thunk_time.items(),
          key=operator.itemgetter(1),
      )[::-1][:5]:
          print(f"           Node {node} time {t:e}s", file=file)
      print("", file=file)
  
      if self.rewriting_time > 0:
          assert self.validate_time < self.rewriting_time
  
imports: import atexit
  import copy
  import logging
  import operator
  import sys
  import time
  from collections import defaultdict
  from contextlib import contextmanager
  from typing import TYPE_CHECKING, Any, Optional, Union
  import numpy
  import pytensor
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, Constant, Variable
  from pytensor.link.utils import get_destroy_dependencies
label_desc: Use image node_id 16 for calling the ProfileStats obj's underlying member method code with example usage: obj.summary_function(file) without return types