Is it possible to {activate|de-activate} SIGFPE generation only for some specific C++11 code segments?

Viewed 555

I am writing a path tracer in C++11, on Linux, for the numerical simulation of light transport and I am using

#include <fenv.h>
...
feenableexcept( FE_INVALID   | 
                FE_DIVBYZERO | 
                FE_OVERFLOW  | 
                FE_UNDERFLOW );

in order to catch and debug any numerical errors that may eventually occur during execution.

At some point in the code I have to compute the intersection of rays (line segments) against axis-aligned bounding boxes (AABBs). For this computation I am using a very optimized and robust ray-box intersection algorithm which relies on the generation of some special values (e.g. NaN and inf) described in the IEEE 754 standard. Obviously, I am not interested in catching floating point exceptions generated specifically by this ray-box intersection routine.

Thus, my questions are:

  1. Is it possible to deactivate the generation of floating point exception signals (SIGFPE) for only some sections of the code (i.e. for the ray-box intersection code section)?
  2. When we are calculating simulations we are very concerned about performance. In the case that it is possible to suppress exception signals only for specific code sections, can this be done at compile time (i.e. instrumenting/de-instrumenting code during its generation, such that we could avoid expensive function calls)?

Thank you for any help!

UPDATE

It is possible to instrument/deinstrument code through the use of feenableexcept and fedisableexcept function calls (actually, I posted this question because I was not aware about the fedisableexcept, only feenableexcept... shame on me!). For instance:

#include <fenv.h>

int main() {
    float a = 1.0f;

    fedisableexcept(FE_DIVBYZERO);   // disable div by zero catching

    // generates an inf that **won't be** catched
    float c = a / 0.0f;

    feenableexcept(FE_DIVBYZERO);   // enable div by zero catching

    // generates an inf that **will be** catched
    float d = a / 2.0f;

    return 0
}
1 Answers

Standard C++ does not provide any way to mark code at compile-time as to whether it should run with floating-point trapping enabled or disabled. In fact, support for manipulating the floating-point environment is not required by the standard, so whether an implementation has it at all is implementation-dependent. Any answer beyond standard C++ depends on the particular hardware and software you are using, but you have not reported that information.

On typical processors, enabling and disabling floating-point trapping is achieved by changing a processor control register. You do not need a function call to do this, but it is not the function call that is expensive, as you suggest in your question. The actual instruction may consume time as it may require the processor to serialize instruction execution. (Modern processors may have hundreds of instructions executing at the same time—some being decoded, some waiting for a subunit within the processor, some in various stages of calculation, some waiting to write their results to general registers, and so on. When changing a control register, the processor may have to wait for all currently executing instructions to finish, then change the register, then start executing new instructions.) If your hardware behaves this way, there is no way to get around it. (With such hardware, which is common, it is not possible to compile code to run with or without trapping without actually executing the run-time instruction to change the control register.)

You might be able to mitigate the time cost by batching path-tracing calculations, so they are performed in groups with only two changes to the floating-point control register (one to turn traps off, one to turn them on) for the entire group.

Related