class_docstr: Object to store runtime and memory profiling information for all of
  Theano's operations: compilation, optimization, 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","Theano","'s","operations",":","compilation",",","optimization",",","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_nodes(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_nodes: total time 0"
                  " (did you forget to enable counters?)"
              ),
              file=file,
          )
          return
  
      print("Apply", file=file)
      print("------", file=file)
      # headers
      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 += ["<#call>"]
      es += [" %4d  "]
  
      hs += ["<id>"]
      es += ["%3d"]
  
      es += ["%s", "%s"]
      if self.variable_shape:
          hs += ["<Mflops>", "<Gflops/s>"]
  
      upto_length = np.sum([len(x) for x in hs]) + len(hs)
      maxlen = max(self.line_width - upto_length, 0)
      hs += ["<Apply name>"]
      es += ["%s"]
  
      header_str = " ".join(hs)
      format_str = " ".join(es)
  
      print(header_str, file=file)
  
      topos = {}  # Only do the topo once per fct.
      atimes = []
      for a, t in iteritems(self.apply_time):
          if a.fgraph not in topos:
              topo = a.fgraph.toposort()
              topos[a.fgraph] = topo
          else:
              topo = topos[a.fgraph]
          atimes.append(
              (
                  t * 100 / local_time,
                  t,
                  a,
                  topo.index(a),
                  self.apply_callcount[a],
              )
          )
      del topos
  
      atimes.sort(reverse=True, key=lambda t: (t[1], t[3]))
      tot = 0
      for f, t, a, nd_id, nb_call in atimes[:N]:
          tot += t
          ftot = tot * 100 / local_time
          if nb_call == 0:
              continue
          if not self.variable_shape:
              flops = ""
              flops_s = ""
          elif hasattr(a.op, "flops"):
              fl = a.op.flops(
                  [self.variable_shape[var] for var in a.inputs],
                  [self.variable_shape[var] for var in a.outputs],
              )
              flops = "%8.1f" % (fl / 1024.0 / 1024)
              flops_s = "%10.1f" % (fl / 1024.0 / 1024 / 1024 / t)
          else:
              flops = "        "
              flops_s = "          "
          print(
              format_str
              % (
                  f,
                  ftot,
                  t,
                  t / nb_call,
                  nb_call,
                  nd_id,
                  flops,
                  flops_s,
                  str(a)[:maxlen],
              ),
              file=file,
          )
          if not config.profile_memory:
              continue
          for idx, var in enumerate(a.inputs):
              sh = self.variable_shape.get(var, "no shape")
              st = self.variable_strides.get(var, "no strides")
              off = self.variable_offset.get(var, "")
              if off != "":
                  off = ", offset=%s" % off
              dtype = getattr(var, "dtype", "no dtype")
              print(
                  "    input %d: dtype=%s, shape=%s, strides=%s%s"
                  % (idx, dtype, sh, st, off),
                  file=file,
              )
          for idx, var in enumerate(a.outputs):
              sh = self.variable_shape.get(var, "no shape")
              st = self.variable_strides.get(var, "no strides")
              off = self.variable_offset.get(var, "")
              if off != "":
                  off = ", offset=%s" % off
              dtype = getattr(var, "dtype", "no dtype")
              print(
                  "    output %d: dtype=%s, shape=%s, strides=%s%s"
                  % (idx, dtype, sh, st, off),
                  file=file,
              )
          # Same as before, this I've sacrificied some information making
          # the output more readable
      print(
          "   ... (remaining %i Apply instances account for "
          "%.2f%%(%.2fs) of the runtime)"
          % (
              max(0, len(atimes) - N),
              sum(f for f, t, a, nd_id, nb_call in atimes[N:]),
              sum(t for f, t, a, nd_id, nb_call in atimes[N:]),
          ),
          file=file,
      )
      print("", file=file)
  
imports: from __future__ import absolute_import, print_function, division
  import atexit
  import copy
  import logging
  import operator
  import os
  import sys
  import time
  from collections import defaultdict
  from six import iteritems
  import warnings
  import numpy
  import theano
  from theano.gof import graph
label_desc: Use image node_id 15 for calling the ProfileStats obj's underlying member method code with example usage: obj.summary_nodes(file, N) without return types