VX_FP_TASK forces the task context switch to include the FP registers. This increases context switch time. If in your application time, deadlines and performance targets can be met even with this overhead, then there is little problem I suggest is doing this. Not having VX_FP_TASK might be considered an optimisation to be applied with care only if and when necessary. So if the default case is to use VX_FP_TASK, you will probably have less checking to do in the few cases where you might need to optimise performance, since often optimisation is unnecessary to achieve the required results. If the context switch performance overhead this imposes makes or breaks your project, it may be marginal in any case.
On the other hand although in embedded systems FPUs are becoming more common, it is also common for embedded systems designers to use FP as the exception rather than the rule because of the traditional lack of hardware FP support. One solution is therefore to have an in-house design rule that floating point shall not be used without formal justification and sign-off: i.e. use of floating point must be in the design, rather than a programmer decision. Checking is generally a simple case of scanning the source for float
, double
, and math.h
. (since it is probably difficult to use floating point without either of these occurring in the code). You might for example add a pre-build static analysis check that looks for these and flags a warning.
In many applications it is possible to design so that FP math operations are naturally confined to specific tasks. A problem occurs however when someone chooses to use an existing function intended for use in one of these tasks in another that is not FP safe. This may be difficult to spot; a solution to this is to have functions that use floating point and which may be used in other tasks to include a debug ASSERT that tests the task options using taskOptionsGet().
So a combination of scanning for use of float
, double
, and math.h
, and adding an ASSERT check to the functions that uses these will probably protect you from introducing errors in code maintenance.
[added 2010Feb14]
As much as complex macros are generally a bad thing, I suggest that the following may be useful (as alluded to above):
#if NDEBUG
#define ASSERT_FP_SAFE() ((void) 0)
#else
#define ASSERT_FP_SAFE() do{ int opt; \
STATUS st = taskGetOptions( taskIdSelf(), &opt ); \
assert( st == OK && (opt & VX_FP_TASK) != 0 ) ; \
}while(0) ;
#endif
This macro should be inserted in any function that uses float or double, or which includes <math.h>
or any other FP dependent library you may use (which you can achieve by textual search). The assertion will then fail when such a function is called from a non-FP task.
Note the check of the return from taskGetOptions() will catch use of floating point in interrupt contexts. Although if the assert occurs in an interrupt, you may not get any output. A call to logMsg() may be safer perhaps; you could use that if st != OK and assert() otherwise.
Unfortunately it is a run-time assertion, so the code has to run for it to be checked. It would be better if it could be detected through static analysis, but I cannot think of a simple method. If however you also use code coverage analysis, then this may be sufficient. It may be a good habit even if you do choose to make all tasks VX_FP_TASK; that way if anyone forgets to do one or the other, you have a chance of catching it.