Data Coherency Considerations

The coherency of the data used by a model must be considered when it is executing in multi-threaded environment. MotoHawk utilizes a a multi-threaded execution environment, which is discussed in more detail here. Proper management of coherent data transfer is essential to ensure data remains consistent (or unchanged) within the context of the thread that is executing. Three examples of different "types" of data coherency will illustrate what can occur.

Data Coherency Examples

High Priority Task Write - Low Priority Task Read

A high priority task write - low priority task read type of data coherency occurs when a higher priority task (say FGND Time Task) updates a shared variable that is used in calculations implemented in a lower priority task (say BGND Time Task). Consider the following example that illustrates what can happen without coherent data transfer of the shared variable in the lower priority task's calculation:

DataCoherency_Example1-1

Let say we have a vector of 10 elements for which we are filling in with the result of a calculation implemented in the BGND task that uses the shared variable A that gets updated by the higher priority FGND task. At the start of the BGND task we begin calculating the vector elements in the lower priority task, in which A = x1. We get half way through the vector calculations and the FGND task interrupts the process and updates shared variable A = x2, then gives the CPU back to the BGND task to resume execution. What has changed? The calculation that uses the shared variable is now using the updated value which is different from the original value used to calculate the first 5 elements. This is an example of incoherent data. Since we did not take care of ensuring the calculation was done atomically or simply taking a "snapshot" (copy) of A before starting the vector calculations, we have half the vector calculated using an old value and the other half calculated using a more up-to-date value. Issues associated with a lack of data coherency will appear to manifest randomly in the application since for the most part the data will remain coherent. The issue only presents when the update occurs at the wrong time. Taking copies overcomes the issue, but at the cost of higher execution and memory resource consumption. Thus the need for data coherency should be evaluated and the necessary steps taken to handle it only when coherency is required.

Low Priority Task Write - High Priority Task Read

A low priority task write - high priority task read type of data coherency occurs when a lower priority task (say BGND Time Task) updates a shared variable that is used in calculations implemented in a higher priority task (say FGND Time Task). Consider the following example that illustrates what can happen without coherent data transfer of the shared variable in the higher priority task's calculation:

DataCoherency_Example1-2

As opposed to the previous example, data coherency issues arise under this condition if multiple variables are used in a higher priority task calculation, but are updated in the lower task priority calculation. Consider a simple calculation implemented in the FGND task such as C = B + A, where A and B both are updated in the BGND task. As shown in the illustration above, A obtains a new value, then the FGND task interrupts the BGND task before it can update variable B.  The end result is that the calculation of C was from a more up-to-date value of A and an older value of B (i.e. C = x2 + y1 instead of C = x2 + y2).

This "type" of data coherency may or may not be an issue depending on the application, but is important to understand what can happen if your calculation shares data across task boundaries.

Data Inconsistency / Data Corruption

The third type of data coherency involves datatypes whose bit-widths are larger than the processor's register size. Consider 32-bit integers or floating point types that are implemented on a processor with 16-bit registers or 64-bit datatypes on a processor with 32-bit registers. It is possible to have data that is only partially updated if a higher priority task interrupts a lower priority task in the middle of a non-protected update or copy of the value (i.e. one half of the value's bits are old, the other half are new) because the value is not atomic on the system. In situations like these it is critical that these values are copied atomically (non-interrupted) when crossing task boundaries.

Achieving Coherent Data Transfer

Atomic copy operations of shared variables must occur when crossing task boundaries in order to avoid data coherency issues. MotoHawk provides the Critical Buffer block to allow non-interruptable copy to occur.

MotoHawk Critical Buffer

Use of the buffer ensures safe data transfer, but it is important to consider how the data is used in a calculation because performing this action multiple times has an adverse effect on efficiency and performance. It is also important to minimize the time spent during any critical code section, as interrupts will be ignored and remain in a pending state until the critical section of code completes. Also, note that if multiple events occur for the same interrupt during a critical section of code, the interrupt will only be serviced once at the end of the critical code section since the processor only knows an interrupt has occurred, not how many times it has occurred.

Consider the example of performing logic in a lower priority task that sets a fault condition using multiple shared variables that are calculated in a higher priority task. In this case, depending on the application, it may be more desirable to have the fault condition determined based on any or all most up-to-date values, in which case the requirement for coherent data transfer may not be necessary.

Coherent Data Transfer Strategy

A common strategy for implementing coherent data transfer is to first consider task priorities and where the shared variable is being produced and consumed. If a high priority task trigger is the producer and the low priority task trigger is the consumer, the atomic copy operation should occur at the start of the low priority task trigger. On the other hand, if a lower priority task trigger is the producer the the higher priority task trigger is the consumer, then the atomic copy operation should occur at the end of the low priority task trigger.

Data Coherency Strategy

Data Coherency Example

Consider the following model template illustrating proper data transfer management for the following three triggers, listed from highest to lowest priority, which are executing in different tasks and sharing data:

Data Coherency Example

Priority numbers of 0, 1, and 2 were assigned to each triggered subsystem to further illustrate each trigger's relative priority, where lowest number = highest priority.

Now let's peek into each triggered subsystem to show the internal layout.