零成本异常处理 vs setjmp/longjmp
假设与设置恢复点相关的成本,可以像这样优化循环:
while (doContinue) {尝试 {做一些工作 ();}抓住 (...) {}}
变成这样:
while (doContinue) {尝试 {做 {做一些工作 ();} while (doContinue);休息;} 抓住 (...) {}}
但是如果平台支持零成本的异常处理,这种优化就没有任何意义了.
有人能指出如何在不同的架构上实现零成本异常处理吗?有没有办法弄清楚编译器/代码生成器可以使用哪些底层机制来在编译时决定是否像这样进行优化.例如,如果编译器可以假设 doSomeWork ()
没有与循环相关的副作用,编译器是否可以为您优化它?
只有在使用中的目标可用时才能使用零成本方法.如果可用,它会被大多数生产质量的 C++ 编译器使用.否则编译器将使用 setjmp/longjmp
方法.
setjmp/longjmp
的执行速度较慢.
但是,即使使用 setjmp/longjmp
方法,使用异常机制也可能比检查每个函数的返回代码具有更高的性能,例如问题中的双循环优化.
确定目标是否支持零成本方法以及编译器是否正在使用它的唯一方法是将 C++ 代码转换为汇编并对其进行分析.另一种解决方案是使用 --RTS=zcx
调用 gnat
并检查错误(如果 gnat
可用).但这并不能保证它会被 C++ 编译器使用.
因此,一般来说,如果程序大小不是问题并且可以使用零成本异常,那么使用异常来处理意外情况要比检查每个函数的返回码要好得多.否则,在某些情况下可以使用异常来优化代码.
使用,但不要滥用!
PS:我最终为此写了一篇文章.p>
Assuming that there is a cost associated with setting recovery point, one could optimize a loop like this:
while (doContinue) {
try {
doSomeWork ();
}
catch (...) {}
}
Into something like this:
while (doContinue) {
try {
do {
doSomeWork ();
} while (doContinue);
break;
} catch (...) {}
}
But if platform supports zero cost exception handling, this optimization does not make any sense.
Could someone point me out how zero cost exception handling is implemented on different architectures and is there a way to figure what underlying mechanisms are available to compiler/code generator to decide in compile-time whether to optimize like this or not. And could compiler, for example, optimize it for you if it can assume doSomeWork ()
has no side effects related to loop?
Zero-cost approach can be used only if available for the target in use. If available, it is used by the most production-quality C++ compilers. Otherwise compiler will use setjmp/longjmp
approach.
Execution speed of setjmp/longjmp
is slower.
However, even with setjmp/longjmp
approach in use, using exceptions mechanism can result in higher performance than checking for return code of every function, as in example with double-loop optimization in the question.
The only way to find out if target supports zero-cost approach and if it is being used by compiler is to translate C++ code into assembly and analyze it. Another solution could be to invoke gnat
with --RTS=zcx
and check for errors, if gnat
is available. But that won't guarantee that it will be used by C++ compiler.
So in general, if program size is not a concern and zero-cost exceptions are available, using exceptions to handle unexpected situations is much better then checking for return code of every function. Otherwise, exceptions can be used to optimize code in certain cases.
Use, but don't abuse!
P.S.: I ended up writing an article on this.
相关文章