The Cost of C++ Exceptions and setjmp/longjmp -
i wrote test measure cost of c++ exceptions threads.
#include <cstdlib> #include <iostream> #include <vector> #include <thread> static const int n = 100000; static void dosomething(int& n) { --n; throw 1; } static void throwmanymanytimes() { int n = n; while (n) { try { dosomething(n); } catch (int n) { switch (n) { case 1: continue; default: std::cout << "error" << std::endl; std::exit(exit_failure); } } } } int main(void) { int ncpus = std::thread::hardware_concurrency(); std::vector<std::thread> threads(ncpus); (int = 0; < ncpus; ++i) { threads[i] = std::thread(throwmanymanytimes); } (int = 0; < ncpus; ++i) { threads[i].join(); } return exit_success; }
here's c version wrote fun.
#include <stdio.h> #include <stdlib.h> #include <setjmp.h> #include <glib.h> #define n 100000 static gprivate jumpbuffer; static void dosomething(volatile int *pn) { jmp_buf *pjb = g_private_get(&jumpbuffer); --*pn; longjmp(*pjb, 1); } static void *throwmanymanytimes(void *p) { jmp_buf jb; volatile int n = n; (void)p; g_private_set(&jumpbuffer, &jb); while (n) { switch (setjmp(jb)) { case 0: dosomething(&n); case 1: continue; default: printf("error\n"); exit(exit_failure); } } return null; } int main(void) { int ncpus = g_get_num_processors(); gthread *threads[ncpus]; int i; (i = 0; < ncpus; ++i) { threads[i] = g_thread_new(null, throwmanymanytimes, null); } (i = 0; < ncpus; ++i) { g_thread_join(threads[i]); } return exit_success; }
the c++ version runs slow compared c version.
$ g++ -o3 -g -std=c++11 test.cpp -o cpp-test -pthread $ gcc -o3 -g -std=c89 test.c -o c-test `pkg-config glib-2.0 --cflags --libs` $ time ./cpp-test real 0m1.089s user 0m2.345s sys 0m1.637s $ time ./c-test real 0m0.024s user 0m0.067s sys 0m0.000s
so ran callgrind profiler.
for cpp-test
, __cxz_throw
called 400,000 times self-cost of 8,000,032.
for c-test
, __longjmp_chk
called 400,000 times self-cost of 5,600,000.
the whole cost of cpp-test
4,048,441,756.
the whole cost of c-test
60,417,722.
i guess more saving state of jump-point , later resuming done c++ exceptions. couldn't test larger n
because callgrind profiler run forever c++ test.
what cost involved in c++ exceptions making many times slower setjmp
/longjmp
pair @ least in example?
this design.
c++ exceptions expected exceptional in nature , optimized thusly. program compiled efficient when exception not happen.
you can verify commenting out exception tests.
in c++:
//throw 1; $ g++ -o3 -g -std=c++11 test.cpp -o cpp-test -pthread $ time ./cpp-test real 0m0.003s user 0m0.004s sys 0m0.000s
in c:
/*longjmp(*pjb, 1);*/ $ gcc -o3 -g -std=c89 test.c -o c-test `pkg-config glib-2.0 --cflags --libs` $ time ./c-test real 0m0.008s user 0m0.012s sys 0m0.004s
what cost involved in c++ exceptions making many times slower setjmp/longjmp pair @ least in example?
g++ implements zero-cost model exceptions, have no effective overhead* when exception not thrown. machine code produced if there no try
/catch
block.
the cost of zero-overhead table lookup must performed on program counter when exception is thrown, determine jump appropriate code performing stack unwinding. puts entire try
/catch
block implementation within code performing throw
.
your cost table lookup.
*some minor timing voodoo may occur, presence of pc lookup table may affect memory layout, may affect cpu cache misses.
Comments
Post a Comment