3 ms·
>Also, presumably your change doesn't affect the 0%-error-rate case, where exceptions should still be faster? In my earlier test, it looked like it was pretty
by juliangoldsmith 10y ago
>Also, presumably your change doesn't affect the 0%-error-rate case, where exceptions should still be faster?
In my earlier test, it looked like it was pretty much even between the two. I haven't looked at assembly or anything, but I'd imagine SEH has a bit of overhead.
As for the type for exceptions, I'm seeing what happens when the C++ version throws ints. I'll update here once I have results.
EDIT: Full results can be found at https://juliangoldsmith.com/excspeed%20results%202.txt https://juliangoldsmith.com/excspeed%20results%202.txt , graph reproduced below. I've also updated the code on my copy of the Github repo.
ecCCCCCCCC
ccccCCCCCC
cccCCCCCcC
cccccCCCCC
ccccccccCc
ecccccccCc
eecccccCcC
cccccccCcc
eccccccccc
cccccccccc
EDIT2: I'm also testing it without optimization enabled, to see whether optimization was making the C version faster than the C++ version.
EDIT3: Apparently turning off optimization makes the C version very significantly faster on my platform: https://juliangoldsmith.com/excspeed%20results%203.txt https://juliangoldsmith.com/excspeed%20results%203.txt
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
cCCCCCCCCC
- kentonv 10y agoC++ exceptions, in modern implementations, should have no time overhead when no exception is thrown. C error codes have the overhead of comparisons to check if the return value is an error return. EDIT: To expand on this: Modern implementations of C++ exceptions build tables mapping code addresses to information about the exception context at that address. The table is created by the compiler and stored in a separate segment of the executable. If no exception is thrown, the table is never consulted. When an exception is thrown, the exception-handling code consults the tables while unwinding the stack. For each return address, the EH tables tell it what destructors need to be run to unwind that stack frame. So, there's no need for comparisons or branching in the code itself. Of course, table-driven execution is expected to be slow (for the same reason interpreted languages are slow), but the idea is to optimize for the common case where there are no exceptions.
- kentonv 10y agoI looked closer at the C code and noticed that it's not really realistic error checking (both before and after your changes). Each level of function is simply tail-calling to the next level. No level is checking whether the return code indicates an error. Instead, an error pointer is passed all the way down the stack and then possibly filled in or not at the bottom, but never inspected in the intermediate frames. This means all the extra branching that is normally associated with error code checking is being skipped in this test. It's not surprising, then, that you're seeing the exception-based code and the error-code-based code performing the same (one or the other winning at random) in the 0% error rate case -- they are actually the same code. In a more realistic test, each intermediate function would call the next function, then inspect its result to see if it indicated an error. If so, the intermediate function would return early (probably passing along the same error code). Otherwise it should do some additional processing on the result (maybe increment it or something, for testing purposes) before returning. In the C++ exceptions version, the error code check could be skipped. With all that said, I would still expect that when exceptions are actually thrown, they should be slower than error code checking.