Drake
Drake C++ Documentation
DependencyTracker Class Reference

Detailed Description

Manages value interdependencies for a particular value or set of values in a Context.

A DependencyTracker ("tracker" for short) provides notifications of changes to the managed value to downstream subscribers, and may invalidate an associated cache entry. The "managed value" can be a source like time or state, or a cached computation. A particular tracker is selected using a DependencyTicket ("ticket") which provides very fast access to the tracker. The ticket is used by both the System and Context as a way to identify dependencies, while trackers exist only in the Context.

Each DependencyTracker manages dependencies for a value, or group of related values, upon which some downstream computations may depend, and maintains lists of downstream dependents (subscribers) and upstream prerequisites. An optional CacheEntryValue may be registered with a tracker in which case the tracker will mark the cache value out of date when one of its prerequisites has changed.

A single DependencyTracker can represent interdependencies within its subcontext, and to and from other subcontexts within the same containing Context tree. Trackers are always owned by a DependencyGraph that is part of a particular subcontext, and should always be created through methods of DependencyGraph; don't construct them directly yourself.

DependencyTracker objects within a Context are nodes in a directed acylic graph formed by "is-prerequisite-of" edges leading from source values (like time, state, parameters, and input ports) to dependent cached computations and output ports. A DependencyTracker maintains lists of both its downstream subscribers and its upstream prerequisites. The entries in both lists are pointers to other DependencyTrackers. That requires special handling when cloning a Context, since the internal pointers to the DependencyTracker objects in the source must be replaced by their corresponding pointers in the copy.

DependencyTrackers may simply group upstream values, without representing a new value or computation. For example, the three continuous state subgroups q, v, and z are each associated with their own DependencyTracker. There is also a tracker that monitors changes to any variable within the entire collection of continuous variables xc≜{q,v,z}; that tracker subscribes to the three individual trackers. Similarly, individual discrete variable groups dᵢ collectively determine the discrete state xd≜{dᵢ}, individual abstract state variables aᵢ determine the abstract state xa≜{aᵢ}, and the full state is x≜{xc,xd,xa}. Here is a graph showing time and state trackers and some hypothetical cache entry trackers.

                   (q)--------➙(position kinematics)
                      ➘
                 (v)--➙(xc)---     (time)----➙(xc_dot)
                 (z)--➚       ╲              ➚
                               ➘            ╱
                (d₀)--➙(xd)---➙(x)----------
                (d₁)--➚        ➚
                              ╱
                (a₀)--➙(xa)---
                (a₁)--➚

The parenthesized nodes are DependencyTrackers for the indicated values, and a directed edge (a)->(b) can be read as "a is-prerequisite-of b" or "a determines b". The graph also maintains reverse-direction edges (not shown). A reversed edge (a)<-(b) could be read as "b subscribes-to a" or "b depends-on a".)

These grouped trackers simplify dependency specification for quantities that depend on many sources, which is very common. For example, they allow a user to express a dependence on "all the inputs" without actually having to know how many inputs there are, which might change over time. Grouped trackers also serve to reduce the total number of edges in the dependency graph, providing faster invalidation. For example, if there are 10 computations dependent on q, v, and z (which frequently change together) we would have 30 edges. Introducing (xc) reduces that to 13 edges.

Downstream computations may subscribe to any of the individual or grouped nodes.

#include <drake/systems/framework/dependency_tracker.h>

Public Types

using PointerMap = std::unordered_map< const DependencyTracker *, const DependencyTracker * >
 (Internal use only) More...
 

Public Member Functions

const std::string & description () const
 Returns the human-readable description for this tracker. More...
 
std::string GetPathDescription () const
 Returns the description, preceded by the full pathname of the subsystem associated with the owning subcontext. More...
 
DependencyTicket ticket () const
 Returns the DependencyTicket for this DependencyTracker in its containing DependencyGraph. More...
 
void set_cache_entry_value (CacheEntryValue *cache_value)
 (Internal use only) Sets the cache entry value to be marked out-of-date when this tracker's prerequisites change. More...
 
const CacheEntryValuecache_entry_value () const
 (Internal use only) Returns a pointer to the CacheEntryValue if this tracker is a cache entry tracker, otherwise nullptr. More...
 
void suppress_notifications ()
 (Internal use only) Instructs this tracker to suppress notifications to downstream subscribers. More...
 
bool notifications_are_suppressed () const
 Returns true if suppress_notifications() has been called on this tracker. More...
 
void NoteValueChange (int64_t change_event) const
 Notifies this DependencyTracker that its managed value was directly modified or made available for mutable access. More...
 
Does not allow copy, move, or assignment
 DependencyTracker (const DependencyTracker &)=delete
 
DependencyTrackeroperator= (const DependencyTracker &)=delete
 
 DependencyTracker (DependencyTracker &&)=delete
 
DependencyTrackeroperator= (DependencyTracker &&)=delete
 
Prerequisites and subscribers

These methods deal with dependencies associated with this tracker.

void SubscribeToPrerequisite (DependencyTracker *prerequisite)
 Subscribes this tracker to an upstream prerequisite's tracker. More...
 
void UnsubscribeFromPrerequisite (DependencyTracker *prerequisite)
 Unsubscribes this tracker from an upstream prerequisite tracker to which we previously subscribed. More...
 
void AddDownstreamSubscriber (const DependencyTracker &subscriber)
 Adds a downstream subscriber to this DependencyTracker, which will keep a pointer to the subscribing tracker. More...
 
void RemoveDownstreamSubscriber (const DependencyTracker &subscriber)
 Removes a downstream subscriber from this DependencyTracker. More...
 
bool HasPrerequisite (const DependencyTracker &prerequisite) const
 Returns true if this tracker has already subscribed to prerequisite. More...
 
bool HasSubscriber (const DependencyTracker &subscriber) const
 Returns true if subscriber is one of this tracker's subscribers. More...
 
int num_prerequisites () const
 Returns the total number of "depends-on" edges emanating from this tracker, pointing to its upstream prerequisites. More...
 
const std::vector< const DependencyTracker * > & prerequisites () const
 Returns a reference to the prerequisite trackers. More...
 
int num_subscribers () const
 Returns the total number of "is-prerequisite-of" edges emanating from this tracker, pointing to its downstream subscribers. More...
 
const std::vector< const DependencyTracker * > & subscribers () const
 Returns a reference to the subscribing trackers. More...
 
Runtime statistics

These methods track runtime operations and are useful for debugging and for performance analysis.

int64_t num_notifications_received () const
 What is the total number of notifications received by this tracker? This is the sum of managed-value change event notifications and prerequisite change notifications received. More...
 
int64_t num_ignored_notifications () const
 How many times did we receive a repeat notification for the same change event that we ignored? More...
 
int64_t num_notifications_sent () const
 What is the total number of notifications sent to downstream subscribers by this trackers? More...
 
int64_t num_value_change_events () const
 How many times was this tracker notified of a change event for a direct change to a value it tracks? More...
 
int64_t num_prerequisite_change_events () const
 How many times was this tracker notified of a change to one of its value's prerequisites? More...
 
Testing/debugging utilities

Methods used in test cases or for debugging.

void ThrowIfBadDependencyTracker (const internal::ContextMessageInterface *owning_subcontext=nullptr, const CacheEntryValue *cache_value=nullptr) const
 Throws an std::exception if there is something clearly wrong with this DependencyTracker object. More...
 

Friends

class DependencyGraph
 

Member Typedef Documentation

◆ PointerMap

using PointerMap = std::unordered_map<const DependencyTracker*, const DependencyTracker*>

(Internal use only)

Constructor & Destructor Documentation

◆ DependencyTracker() [1/2]

DependencyTracker ( const DependencyTracker )
delete

◆ DependencyTracker() [2/2]

Member Function Documentation

◆ AddDownstreamSubscriber()

void AddDownstreamSubscriber ( const DependencyTracker subscriber)

Adds a downstream subscriber to this DependencyTracker, which will keep a pointer to the subscribing tracker.

The subscriber will be notified whenever this DependencyTracker is notified of a value or prerequisite change.

Precondition
The subscriber has already recorded its dependency on this tracker in its prerequisite list.

◆ cache_entry_value()

const CacheEntryValue* cache_entry_value ( ) const

(Internal use only) Returns a pointer to the CacheEntryValue if this tracker is a cache entry tracker, otherwise nullptr.

◆ description()

const std::string& description ( ) const

Returns the human-readable description for this tracker.

◆ GetPathDescription()

std::string GetPathDescription ( ) const

Returns the description, preceded by the full pathname of the subsystem associated with the owning subcontext.

◆ HasPrerequisite()

bool HasPrerequisite ( const DependencyTracker prerequisite) const

Returns true if this tracker has already subscribed to prerequisite.

This is slow and should not be used in performance-sensitive code.

◆ HasSubscriber()

bool HasSubscriber ( const DependencyTracker subscriber) const

Returns true if subscriber is one of this tracker's subscribers.

This is slow and should not be used in performance-sensitive code.

◆ NoteValueChange()

void NoteValueChange ( int64_t  change_event) const

Notifies this DependencyTracker that its managed value was directly modified or made available for mutable access.

That is, this is the initiating event of a value modification. All of our downstream subscribers are notified but the associated cache entry (if any) is not invalidated (see below for why). A unique, positive change_event should have been obtained from the owning Context and supplied here.

Why don't we invalidate the cache entry? Recall that this method is for initiating a change event, meaning that the quantity that this tracker tracks is initiating an invalidation sweep, as opposed to just reacting to prerequisite changes. Normally cache entries become invalid because their prerequisites change; they are not usually the first step in an invalidation sweep. So it is unusual for NoteValueChange() to be called on a cache entry's dependency tracker. But if it is called, that is likely to mean the cache entry was just given a new value, and is therefore valid; invalidating it now would be an error.

◆ notifications_are_suppressed()

bool notifications_are_suppressed ( ) const

Returns true if suppress_notifications() has been called on this tracker.

◆ num_ignored_notifications()

int64_t num_ignored_notifications ( ) const

How many times did we receive a repeat notification for the same change event that we ignored?

◆ num_notifications_received()

int64_t num_notifications_received ( ) const

What is the total number of notifications received by this tracker? This is the sum of managed-value change event notifications and prerequisite change notifications received.

◆ num_notifications_sent()

int64_t num_notifications_sent ( ) const

What is the total number of notifications sent to downstream subscribers by this trackers?

◆ num_prerequisite_change_events()

int64_t num_prerequisite_change_events ( ) const

How many times was this tracker notified of a change to one of its value's prerequisites?

◆ num_prerequisites()

int num_prerequisites ( ) const

Returns the total number of "depends-on" edges emanating from this tracker, pointing to its upstream prerequisites.

◆ num_subscribers()

int num_subscribers ( ) const

Returns the total number of "is-prerequisite-of" edges emanating from this tracker, pointing to its downstream subscribers.

◆ num_value_change_events()

int64_t num_value_change_events ( ) const

How many times was this tracker notified of a change event for a direct change to a value it tracks?

◆ operator=() [1/2]

DependencyTracker& operator= ( DependencyTracker &&  )
delete

◆ operator=() [2/2]

DependencyTracker& operator= ( const DependencyTracker )
delete

◆ prerequisites()

const std::vector<const DependencyTracker*>& prerequisites ( ) const

Returns a reference to the prerequisite trackers.

◆ RemoveDownstreamSubscriber()

void RemoveDownstreamSubscriber ( const DependencyTracker subscriber)

Removes a downstream subscriber from this DependencyTracker.

Precondition
The subscriber has already removed the dependency on this tracker from its prerequisite list.

◆ set_cache_entry_value()

void set_cache_entry_value ( CacheEntryValue cache_value)

(Internal use only) Sets the cache entry value to be marked out-of-date when this tracker's prerequisites change.

Precondition
The supplied cache entry value is non-null.
No cache entry value has previously been assigned.

◆ subscribers()

const std::vector<const DependencyTracker*>& subscribers ( ) const

Returns a reference to the subscribing trackers.

◆ SubscribeToPrerequisite()

void SubscribeToPrerequisite ( DependencyTracker prerequisite)

Subscribes this tracker to an upstream prerequisite's tracker.

The upstream tracker will keep a const pointer back to this tracker in its subscriber list, and this tracker will keep a pointer to the prerequisite tracker in its prerequisites list.

◆ suppress_notifications()

void suppress_notifications ( )

(Internal use only) Instructs this tracker to suppress notifications to downstream subscribers.

This can be used by the framework during Context allocation to disable built-in trackers that have nothing to track. For example, if there are no q's we can improve performance and avoid spurious notifications to q-subscribers like configuration_tracker by disabling q's tracker.

◆ ThrowIfBadDependencyTracker()

void ThrowIfBadDependencyTracker ( const internal::ContextMessageInterface *  owning_subcontext = nullptr,
const CacheEntryValue cache_value = nullptr 
) const

Throws an std::exception if there is something clearly wrong with this DependencyTracker object.

If the owning subcontext is known, provide a pointer to it here and we'll check that this tracker agrees. If you know which cache entry is supposed to be associated with this tracker, supply a pointer to that and we'll check it (trackers that are not associated with a real cache entry are still associated with the CacheEntryValue::dummy()). In addition we check for other internal inconsistencies.

Exceptions
std::exceptionfor anything that goes wrong, with an appropriate explanatory message.

◆ ticket()

DependencyTicket ticket ( ) const

Returns the DependencyTicket for this DependencyTracker in its containing DependencyGraph.

The ticket is unique within the containing subcontext.

◆ UnsubscribeFromPrerequisite()

void UnsubscribeFromPrerequisite ( DependencyTracker prerequisite)

Unsubscribes this tracker from an upstream prerequisite tracker to which we previously subscribed.

Both the prerequisite list in this tracker and the subscriber list in prerequisite are modified.

Precondition
The supplied pointer must not be null.
This tracker must already be subscribed to the given prerequisite.

Friends And Related Function Documentation

◆ DependencyGraph

friend class DependencyGraph
friend

The documentation for this class was generated from the following file: