I've found that a large amount of CPU time is spent in the fpe_check() function (wrspice/include/fpe_check.h). In some tests I've made, this function uses more than a third of the total CPU time. Most of the time is spent in feclearexcept().
There's little point in clearing an exception that hasn't happened, so I rewrote the code so that feclearexcept() is called only if an exception is discovered. I also modified the code so that fetestexcept() is only called once.
This is essentially what I ended up with:
if (!noerrret && Sp.GetFPEmode() == FPEcheck) {
const int exflags_tested = FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID;
// read FP exception status into a temporary, which
// can then be tested with minimal overhead
int exflags = fetestexcept(exflags_tested);
if (exflags != 0) {
if (exflags & FE_DIVBYZERO)
err = E_MATHDBZ;
else if (exflags & FE_OVERFLOW)
err = E_MATHOVF;
// Ignore underflow, these really shouldn't be a problem.
// else if (fetestexcept(FE_UNDERFLOW))
// err = E_MATHUNF;
else if (exflags & FE_INVALID)
err = E_MATHINV;
// feclearexcept() is slow (at least on x86-64), so try to
// make sure we call it only when necessary.
feclearexcept(FE_ALL_EXCEPT);
}
}
I haven't tested it thoroughly, but it seems to be considerably quicker. Any thoughts?
I've found that a large amount of CPU time is spent in the fpe_check() function (wrspice/include/fpe_check.h). In some tests I've made, this function uses more than a third of the total CPU time. Most of the time is spent in feclearexcept().
There's little point in clearing an exception that hasn't happened, so I rewrote the code so that feclearexcept() is called only if an exception is discovered. I also modified the code so that fetestexcept() is only called once.
This is essentially what I ended up with:
I haven't tested it thoroughly, but it seems to be considerably quicker. Any thoughts?