class_docstr: An abstract class for evaluating PyTensor programs.
  
  The `VM.__call__` method evaluates an PyTensor program.
  
  `Stack` should be considered the reference `VM`/`Linker` implementation.
  It can correctly evaluate all graphs and is the easiest to read. The `CVM`
  is a port of `Stack` and should have the same behavior, but run faster.
  The `CVM`'s code is harder to read though.
  
  The other python `VM`\s are perhaps not necessary anymore, and don't take
  advantage of lazy computation, although they still produce the correct
  output for lazy nodes.
  
  Attributes
  ----------
  call_counts
      List of integers, one for each thunk. ``call_count[i]`` is the number
      of times ``thunks[i]`` was called in the course of computations
      performed by `call_with_timers`.
  call_times
      List of floats, one for each thunk. ``call_times[i]`` is the amount of
      runtime spent on ``thunks[i]`` in the course of computations performed
      by `call_with_timers`.
  
  need_update_inputs : bool
      ``True`` indicates that `Function.__call__` must implement the feedback
      from output storage to input storage. ``False`` means it *must not*
      repeat that feedback.
class_docstr_tok: ["An","abstract","class","for","evaluating","PyTensor","programs",".","The","`","VM.__call__","`","method","evaluates","an","PyTensor","program",".","`","Stack","`","should","be","considered","the","reference","`","VM","`","\/","`","Linker","`","implementation",".","It","can","correctly","evaluate","all","graphs","and","is","the","easiest","to","read",".","The","`","CVM","`","is","a","port","of","`","Stack","`","and","should","have","the","same","behavior",",","but","run","faster",".","The","`","CVM","`","'s","code","is","harder","to","read","though",".","The","other","python","`","VM","`","\\s","are","perhaps","not","necessary","anymore",",","and","do","n't","take","advantage","of","lazy","computation",",","although","they","still","produce","the","correct","output","for","lazy","nodes",".","Attributes","--","--","--","--","--","call_counts","List","of","integers",",","one","for","each","thunk",".","``","call_count","[","i","]","``","is","the","number","of","times","``","thunks","[","i","]","``","was","called","in","the","course","of","computations","performed","by","`","call_with_timers","`",".","call_times","List","of","floats",",","one","for","each","thunk",".","``","call_times","[","i","]","``","is","the","amount","of","runtime","spent","on","``","thunks","[","i","]","``","in","the","course","of","computations","performed","by","`","call_with_timers","`",".","need_update_inputs",":","bool","``","True","``","indicates","that","`","Function.__call__","`","must","implement","the","feedback","from","output","storage","to","input","storage",".","``","False","``","means","it","*","must","not","*","repeat","that","feedback","."]
docstr: Update a profile object.
docstr_tok: ["Update","a","profile","object","."]
code: def update_profile(self, profile):
      """Update a profile object."""
      for node, thunk, t, c in zip(
          self.nodes, self.thunks, self.call_times, self.call_counts
      ):
          profile.apply_time.setdefault((self.fgraph, node), 0.0)
          profile.apply_time[(self.fgraph, node)] += t
  
          profile.apply_callcount.setdefault((self.fgraph, node), 0)
          profile.apply_callcount[(self.fgraph, node)] += c
  
          profile.apply_cimpl[node] = hasattr(thunk, "cthunk")
  
      if hasattr(self, "variable_shape"):
          profile.variable_shape = self.variable_shape.copy()
          profile.variable_strides = self.variable_strides.copy()
          profile.variable_offset = self.variable_offset.copy()
  
      if hasattr(self, "node_executed_order"):
          profile.node_executed_order = self.node_executed_order[:]
  
      if hasattr(self, "node_cleared_order"):
          profile.node_cleared_order = self.node_cleared_order[:]
  
      if hasattr(self, "dependencies"):
          profile.dependencies = self.dependencies
  
      # clear the timer info out of the buffers
      for i in range(len(self.call_times)):
          self.call_times[i] = 0.0
          self.call_counts[i] = 0
  
imports: import platform
  import sys
  import time
  import warnings
  from abc import ABC, abstractmethod
  from collections import defaultdict
  from collections.abc import Sequence
  from itertools import zip_longest
  from typing import TYPE_CHECKING, Any, Optional
  from pytensor.configdefaults import config
  from pytensor.graph.basic import Apply, Constant, Variable
  from pytensor.link.basic import Container, LocalLinker
  from pytensor.link.c.exceptions import MissingGXX
  from pytensor.link.utils import gc_helper, get_destroy_dependencies, map_storage, raise_with_op
label_desc: Use image node_id 4 for calling the VM obj's underlying member method code with example usage: obj.update_profile(profile) without return types