tags:

views:

270

answers:

2

In vxworks, should every task be spawned with VX_FP_TASK option?

The VX_FP_TASK option is required if your task uses any floating point operations. But how does one predict the future - i mean, how can one know if he/she will use float or not?

While fixing any bug or introducing new code, should the programmer find which all tasks will get effected by his/her code chage and if that task is spawned with this option or not? This is very tedious. Am I missing something?

+3  A: 

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 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.

Clifford
+3  A: 

From experience I can give you a simple answer: Always spawn a task with VX_FP_TASK. Especially if your code could be used for different architectures.

Depending on the compiler (gnu, diab), the compiling flags that you use, and the architechture, the floating point registers can be used for more than just floating point operations. In most architectures FP registers are bigger than regular registers, so they turn into perfect candidates for optimizing code.

For example, in PPC603 processors, if you use C++ instead of plain C, the FP registers will be used for optimization, and if you don't have VX_FP_TASK enabled on that task it could corrupt the FP registers of another task, even though it's not making any calculations!

Correct execution is more important than performance, and most times the performance gain doesn't justify the risk introduced by not enabling it.

If you want to ensure that all tasks have the flag enabled, consider adding a hook that always enables the flag during task creation with taskCreateHookAdd( )

Marcelo
I wonder if the optimisation from using FP registers for non FP operations might sometimes be outweighed by the additional context switch overhead - the compiler would not be aware of that. Sounds like an optimisation worth disabling if the application thrashed tasks a lot. That said, I agree; always avoid a premature optimisation and start with VX_FP_TASK as the default, even if you implement the 'defensive' techniques I suggested.
Clifford
Hi Marcelo, Thanks for the reply. I didn't understand the last sentence - "If you want to ensure that all tasks have the flag enabled, consider adding a hook that always enables the flag during task creation with taskCreateHookAdd( )" . Did you mean if the designer has not included the VX_FP_TASK option while creating the task, this hook will put it while compiling the code?Can you please elaborate it and explain detailedly. Thanks in advance.
aks