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_class(self, file=sys.stderr, N=None):
      if self.apply_time:
          local_time = sum(self.apply_time.values())
      else:
          local_time = 0
      if local_time == 0:
          print(
              (
                  "ProfileStats.summary_class: total time 0"
                  " (did you forget to enable counters?)"
              ),
              file=file,
          )
          return
      class_time = self.class_time()
      class_call = self.class_callcount()
      class_apply = self.class_nodes()
      class_impl = self.class_impl()
      if N is None:
          N = len(self.class_time)
      otimes = [
          (
              t * 100 / local_time,
              t,
              clas,
              class_impl.get(clas, "  "),
              class_call.get(clas, 0),
              class_apply.get(clas, 0),
          )
          for clas, t in class_time.items()
      ]
      otimes.sort(key=lambda t: (t[1], t[4], t[5]), reverse=True)
      tot = 0
      print("Class", file=file)
      print("---", file=file)
      hs = []
      # formatting string
      es = []
  
      hs += ["<% time>"]
      es += ["  %4.1f%% "]
  
      hs += ["<sum %>"]
      es += [" %5.1f%% "]
  
      hs += ["<apply time>"]
      es += ["   %7.3fs "]
  
      hs += ["<time per call>"]
      es += ["     %8.2es "]
  
      hs += ["<type>"]
      es += ["   %2s "]
  
      hs += ["<#call>"]
      es += ["%6d  "]
  
      hs += ["<#apply>"]
      es += [" %4d  "]
  
      upto_length = sum(len(x) for x in hs) + len(hs)
      maxlen = max(self.line_width - upto_length, 0)
      hs += ["<Class name>"]
      es += ["%s"]
      header_str = " ".join(hs)
      format_str = " ".join(es)
  
      print(header_str, file=file)
  
      for f, t, a, impl, nb_call, nb_apply in otimes[:N]:
          if nb_call == 0:
              assert t == 0
              continue
          tot += t
          ftot = tot * 100 / local_time
          # Remove the useless start and end of the class name:
          # "<class 'pytensor.backend.blas.Dot22'>" ->
          #  "pytensor.backend.blas.Dot22"
          class_name = str(a)[8:-2][:maxlen]
          print(
              format_str
              % (
                  f,
                  ftot,
                  t,
                  t / nb_call,
                  impl,
                  nb_call,
                  nb_apply,
                  class_name,
              ),
              file=file,
          )
          # While this carries over less information, it is arranged such
          # that it is way more readable than the previous output of the
          # profiler
      print(
          "   ... (remaining %i Classes account for %6.2f%%(%.2fs) of "
          "the runtime)"
          % (
              max(0, len(otimes) - N),
              sum(f for f, t, a, ci, nb_call, nb_op in otimes[N:]),
              sum(t for f, t, a, ci, nb_call, nb_op in otimes[N:]),
          ),
          file=file,
      )
      print("", file=file)
  
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 13 for calling the ProfileStats obj's underlying member method code with example usage: obj.summary_class(file, N) without return types