odin-blend2d

Odin bindings to Blend2D
Log | Files | Refs | README | LICENSE

asmjit_bench_overhead.cpp (12511B)


      1 #include <stdint.h>
      2 #include <asmjit/host.h>
      3 
      4 #include "../commons/asmjitutils.h"
      5 #include "../commons/cmdline.h"
      6 #include "../commons/performancetimer.h"
      7 
      8 using namespace asmjit;
      9 
     10 static void print_app_info(size_t n) noexcept {
     11   printf("AsmJit Benchmark Overhead v%u.%u.%u [Arch=%s] [Mode=%s]\n\n",
     12     unsigned((ASMJIT_LIBRARY_VERSION >> 16)       ),
     13     unsigned((ASMJIT_LIBRARY_VERSION >>  8) & 0xFF),
     14     unsigned((ASMJIT_LIBRARY_VERSION      ) & 0xFF),
     15     asmjit_arch_as_string(Arch::kHost),
     16     asmjit_build_type()
     17   );
     18 
     19   printf("This benchmark was designed to benchmark the cost of initialization and\n"
     20          "reset (or reinitialization) of CodeHolder and Emitters; and the cost of\n"
     21          "moving a minimal assembled function to executable memory. Each output line\n"
     22          "uses \"<Test> [Func] [Finalize] [RT]\" format, with the following meaning:\n"
     23          "\n"
     24          "  - <Test>     - test case name - either 'CodeHolder' only or an emitter\n"
     25          "  - [Func]     - function was assembled\n"
     26          "  - [Finalize] - function was finalized (Builder/Compiler)\n"
     27          "  - [RT]       - function was added to JitRuntime and then removed from it\n"
     28          "\n"
     29          "Essentially the output provides an insight into the cost of reusing\n"
     30          "CodeHolder and other emitters, and the cost of assembling, finalizing,\n"
     31          "and moving the assembled code into executable memory by separating each\n"
     32          "phase.\n\n"
     33   );
     34 
     35   printf("The number of iterations benchmarked: %zu (override by --count=n)\n", n);
     36   printf("\n");
     37 }
     38 
     39 #if !defined(ASMJIT_NO_JIT)
     40 
     41 class MyErrorHandler : public ErrorHandler {
     42 public:
     43   void handle_error(asmjit::Error err, const char* message, asmjit::BaseEmitter* origin) override {
     44     Support::maybe_unused(err, origin);
     45     fprintf(stderr, "AsmJit error: %s\n", message);
     46   }
     47 };
     48 
     49 enum class InitStrategy : uint32_t {
     50   kInitReset,
     51   kReinit
     52 };
     53 
     54 static inline void bench_codeholder(InitStrategy strategy, size_t count) {
     55   JitRuntime rt;
     56   CodeHolder code;
     57 
     58   if (strategy == InitStrategy::kInitReset) {
     59     for (size_t i = 0; i < count; i++) {
     60       code.init(rt.environment());
     61       code.reset();
     62     }
     63   }
     64   else {
     65     code.init(rt.environment());
     66     for (size_t i = 0; i < count; i++) {
     67       code.reinit();
     68     }
     69   }
     70 }
     71 
     72 #if ASMJIT_ARCH_X86 != 0 && !defined(ASMJIT_NO_X86)
     73 template<typename EmitterT>
     74 static ASMJIT_INLINE void emit_raw_func(EmitterT& emitter) {
     75   emitter.mov(x86::eax, 0);
     76   emitter.ret();
     77 }
     78 
     79 template<typename CompilerT>
     80 static ASMJIT_INLINE void compile_raw_func(CompilerT& cc) {
     81   x86::Gp r = cc.new_gp32();
     82   cc.mov(r, 0);
     83   cc.ret(r);
     84 }
     85 #endif
     86 
     87 #if ASMJIT_ARCH_ARM == 64 && !defined(ASMJIT_NO_AARCH64)
     88 template<typename EmitterT>
     89 static ASMJIT_INLINE void emit_raw_func(EmitterT& emitter) {
     90   emitter.mov(a64::w0, 0);
     91   emitter.ret(a64::x30);
     92 }
     93 
     94 template<typename CompilerT>
     95 static ASMJIT_INLINE void compile_raw_func(CompilerT& cc) {
     96   a64::Gp gp = cc.new_gp32();
     97   cc.mov(gp, 0);
     98   cc.ret(gp);
     99 }
    100 #endif
    101 
    102 #if defined(ASMJIT_HAS_HOST_BACKEND)
    103 template<typename AssemblerT>
    104 static inline void bench_assembler(InitStrategy strategy, size_t count) {
    105   JitRuntime rt;
    106   CodeHolder code;
    107   AssemblerT a;
    108   MyErrorHandler eh;
    109 
    110   if (strategy == InitStrategy::kInitReset) {
    111     for (size_t i = 0; i < count; i++) {
    112       code.init(rt.environment());
    113       code.set_error_handler(&eh);
    114       code.attach(&a);
    115       code.reset();
    116     }
    117   }
    118   else {
    119     code.init(rt.environment());
    120     code.set_error_handler(&eh);
    121     code.attach(&a);
    122 
    123     for (size_t i = 0; i < count; i++) {
    124       code.reinit();
    125     }
    126   }
    127 }
    128 
    129 template<typename AssemblerT>
    130 static inline void bench_assembler_func(InitStrategy strategy, size_t count) {
    131   JitRuntime rt;
    132   CodeHolder code;
    133   AssemblerT a;
    134   MyErrorHandler eh;
    135 
    136   if (strategy == InitStrategy::kInitReset) {
    137     for (size_t i = 0; i < count; i++) {
    138       code.init(rt.environment());
    139       code.set_error_handler(&eh);
    140       code.attach(&a);
    141       emit_raw_func(a);
    142       code.reset();
    143     }
    144   }
    145   else {
    146     code.init(rt.environment());
    147     code.set_error_handler(&eh);
    148     code.attach(&a);
    149 
    150     for (size_t i = 0; i < count; i++) {
    151       code.reinit();
    152       emit_raw_func(a);
    153     }
    154   }
    155 }
    156 
    157 template<typename AssemblerT>
    158 static inline void bench_assembler_func_rt(InitStrategy strategy, size_t count) {
    159   JitRuntime rt;
    160   CodeHolder code;
    161   AssemblerT a;
    162   MyErrorHandler eh;
    163 
    164   using Func = uint32_t(*)(void);
    165 
    166   if (strategy == InitStrategy::kInitReset) {
    167     for (size_t i = 0; i < count; i++) {
    168       code.init(rt.environment());
    169       code.set_error_handler(&eh);
    170       code.attach(&a);
    171       emit_raw_func(a);
    172 
    173       Func fn;
    174       rt.add(&fn, &code);
    175       rt.release(fn);
    176 
    177       code.reset();
    178     }
    179   }
    180   else {
    181     code.init(rt.environment());
    182     code.set_error_handler(&eh);
    183     code.attach(&a);
    184 
    185     for (size_t i = 0; i < count; i++) {
    186       code.reinit();
    187       emit_raw_func(a);
    188 
    189       Func fn;
    190       rt.add(&fn, &code);
    191       rt.release(fn);
    192     }
    193   }
    194 }
    195 #endif
    196 
    197 #if defined(ASMJIT_HAS_HOST_BACKEND) && !defined(ASMJIT_NO_BUILDER)
    198 template<typename BuilderT>
    199 static inline void bench_builder(InitStrategy strategy, size_t count) {
    200   JitRuntime rt;
    201   CodeHolder code;
    202   BuilderT b;
    203   MyErrorHandler eh;
    204 
    205   if (strategy == InitStrategy::kInitReset) {
    206     for (size_t i = 0; i < count; i++) {
    207       code.init(rt.environment());
    208       code.set_error_handler(&eh);
    209       code.attach(&b);
    210       code.reset();
    211     }
    212   }
    213   else {
    214     code.init(rt.environment());
    215     code.set_error_handler(&eh);
    216     code.attach(&b);
    217 
    218     for (size_t i = 0; i < count; i++) {
    219       code.reinit();
    220     }
    221   }
    222 }
    223 
    224 template<typename BuilderT>
    225 static inline void bench_builder_func(InitStrategy strategy, size_t count, bool finalize) {
    226   JitRuntime rt;
    227   CodeHolder code;
    228   BuilderT b;
    229   MyErrorHandler eh;
    230 
    231   if (strategy == InitStrategy::kInitReset) {
    232     for (size_t i = 0; i < count; i++) {
    233       code.init(rt.environment());
    234       code.set_error_handler(&eh);
    235       code.attach(&b);
    236       emit_raw_func(b);
    237 
    238       if (finalize) {
    239         b.finalize();
    240       }
    241       code.reset();
    242     }
    243   }
    244   else {
    245     code.init(rt.environment());
    246     code.set_error_handler(&eh);
    247     code.attach(&b);
    248 
    249     for (size_t i = 0; i < count; i++) {
    250       code.reinit();
    251       emit_raw_func(b);
    252 
    253       if (finalize) {
    254         b.finalize();
    255       }
    256     }
    257   }
    258 }
    259 
    260 template<typename BuilderT>
    261 static inline void bench_builder_func_finalize_rt(InitStrategy strategy, size_t count) {
    262   JitRuntime rt;
    263   CodeHolder code;
    264   BuilderT b;
    265   MyErrorHandler eh;
    266 
    267   using Func = uint32_t(*)(void);
    268 
    269   if (strategy == InitStrategy::kInitReset) {
    270     for (size_t i = 0; i < count; i++) {
    271       code.init(rt.environment());
    272       code.set_error_handler(&eh);
    273       code.attach(&b);
    274       emit_raw_func(b);
    275       b.finalize();
    276 
    277       Func fn;
    278       rt.add(&fn, &code);
    279       rt.release(fn);
    280 
    281       code.reset();
    282     }
    283   }
    284   else {
    285     code.init(rt.environment());
    286     code.set_error_handler(&eh);
    287     code.attach(&b);
    288 
    289     for (size_t i = 0; i < count; i++) {
    290       code.reinit();
    291       emit_raw_func(b);
    292       b.finalize();
    293 
    294       Func fn;
    295       rt.add(&fn, &code);
    296       rt.release(fn);
    297     }
    298   }
    299 }
    300 #endif // ASMJIT_HAS_HOST_BACKEND && !ASMJIT_NO_BUILDER
    301 
    302 #if defined(ASMJIT_HAS_HOST_BACKEND) && !defined(ASMJIT_NO_COMPILER)
    303 template<typename CompilerT>
    304 static inline void bench_compiler(InitStrategy strategy, size_t count) {
    305   JitRuntime rt;
    306   CodeHolder code;
    307   CompilerT cc;
    308   MyErrorHandler eh;
    309 
    310   if (strategy == InitStrategy::kInitReset) {
    311     for (size_t i = 0; i < count; i++) {
    312       code.init(rt.environment());
    313       code.set_error_handler(&eh);
    314       code.attach(&cc);
    315       code.reset();
    316     }
    317   }
    318   else {
    319     code.init(rt.environment());
    320     code.set_error_handler(&eh);
    321     code.attach(&cc);
    322 
    323     for (size_t i = 0; i < count; i++) {
    324       code.reinit();
    325     }
    326   }
    327 }
    328 
    329 template<typename CompilerT>
    330 static inline void bench_compiler_func(InitStrategy strategy, size_t count, bool finalize) {
    331   JitRuntime rt;
    332   CodeHolder code;
    333   CompilerT cc;
    334   MyErrorHandler eh;
    335 
    336   if (strategy == InitStrategy::kInitReset) {
    337     for (size_t i = 0; i < count; i++) {
    338       code.init(rt.environment());
    339       code.set_error_handler(&eh);
    340       code.attach(&cc);
    341 
    342       (void)cc.add_func(FuncSignature::build<uint32_t>());
    343       compile_raw_func(cc);
    344       cc.end_func();
    345 
    346       if (finalize) {
    347         cc.finalize();
    348       }
    349 
    350       code.reset();
    351     }
    352   }
    353   else {
    354     code.init(rt.environment());
    355     code.set_error_handler(&eh);
    356     code.attach(&cc);
    357 
    358     for (size_t i = 0; i < count; i++) {
    359       code.reinit();
    360 
    361       (void)cc.add_func(FuncSignature::build<uint32_t>());
    362       compile_raw_func(cc);
    363       cc.end_func();
    364 
    365       if (finalize) {
    366         cc.finalize();
    367       }
    368     }
    369   }
    370 }
    371 
    372 template<typename CompilerT>
    373 static inline void bench_compiler_func_rt(InitStrategy strategy, size_t count) {
    374   JitRuntime rt;
    375   CodeHolder code;
    376   CompilerT cc;
    377   MyErrorHandler eh;
    378 
    379   using Func = uint32_t(*)(void);
    380 
    381   if (strategy == InitStrategy::kInitReset) {
    382     for (size_t i = 0; i < count; i++) {
    383       code.init(rt.environment());
    384       code.set_error_handler(&eh);
    385       code.attach(&cc);
    386 
    387       (void)cc.add_func(FuncSignature::build<uint32_t>());
    388       compile_raw_func(cc);
    389       cc.end_func();
    390       cc.finalize();
    391 
    392       Func fn;
    393       rt.add(&fn, &code);
    394       rt.release(fn);
    395 
    396       code.reset();
    397     }
    398   }
    399   else {
    400     code.init(rt.environment());
    401     code.set_error_handler(&eh);
    402     code.attach(&cc);
    403 
    404     for (size_t i = 0; i < count; i++) {
    405       code.reinit();
    406 
    407       (void)cc.add_func(FuncSignature::build<uint32_t>());
    408       compile_raw_func(cc);
    409       cc.end_func();
    410       cc.finalize();
    411 
    412       Func fn;
    413       rt.add(&fn, &code);
    414       rt.release(fn);
    415     }
    416   }
    417 }
    418 #endif // ASMJIT_HAS_HOST_BACKEND && !ASMJIT_NO_COMPILER
    419 
    420 template<typename Lambda>
    421 static inline void test_perf(const char* bench_name, InitStrategy strategy, size_t n, Lambda&& fn) {
    422   PerformanceTimer timer;
    423   const char* strategy_name = strategy == InitStrategy::kInitReset ? "init/reset" : "reinit    ";
    424 
    425   timer.start();
    426   fn(strategy, n);
    427   timer.stop();
    428 
    429   printf("%-31s [%s]: %8.3f [ms]\n", bench_name, strategy_name, timer.duration());
    430 }
    431 
    432 static inline void test_perf_all(InitStrategy strategy, size_t n) {
    433   using IS = InitStrategy;
    434 
    435   test_perf("CodeHolder (Only)"              , strategy, n, [](IS s, size_t n) { bench_codeholder(s, n); });
    436 
    437 #if defined(ASMJIT_HAS_HOST_BACKEND)
    438   test_perf("Assembler"                      , strategy, n, [](IS s, size_t n) { bench_assembler<host::Assembler>(s, n); });
    439   test_perf("Assembler + Func"               , strategy, n, [](IS s, size_t n) { bench_assembler_func<host::Assembler>(s, n); });
    440   test_perf("Assembler + Func + RT"          , strategy, n, [](IS s, size_t n) { bench_assembler_func_rt<host::Assembler>(s, n); });
    441 #endif
    442 
    443 #if defined(ASMJIT_HAS_HOST_BACKEND) && !defined(ASMJIT_NO_BUILDER)
    444   test_perf("Builder"                        , strategy, n, [](IS s, size_t n) { bench_builder<host::Builder>(s, n); });
    445   test_perf("Builder + Func"                 , strategy, n, [](IS s, size_t n) { bench_builder_func<host::Builder>(s, n, false); });
    446   test_perf("Builder + Func + Finalize"      , strategy, n, [](IS s, size_t n) { bench_builder_func<host::Builder>(s, n, true); });
    447   test_perf("Builder + Func + Finalize + RT" , strategy, n, [](IS s, size_t n) { bench_builder_func_finalize_rt<host::Builder>(s, n); });
    448 #endif
    449 
    450 #if defined(ASMJIT_HAS_HOST_BACKEND) && !defined(ASMJIT_NO_COMPILER)
    451 
    452   test_perf("Compiler"                       , strategy, n, [](IS s, size_t n) { bench_compiler<host::Compiler>(s, n); });
    453   test_perf("Compiler + Func"                , strategy, n, [](IS s, size_t n) { bench_compiler_func<host::Compiler>(s, n, false); });
    454   test_perf("Compiler + Func + Finalize"     , strategy, n, [](IS s, size_t n) { bench_compiler_func<host::Compiler>(s, n, true); });
    455 
    456   test_perf("Compiler + Func + Finalize + RT", strategy, n, [](IS s, size_t n) { bench_compiler_func_rt<host::Compiler>(s, n); });
    457 #endif
    458 }
    459 
    460 int main(int argc, char* argv[]) {
    461   CmdLine cmd_line(argc, argv);
    462   size_t n = cmd_line.value_as_uint("--count", 1000000);
    463 
    464   print_app_info(n);
    465 
    466   test_perf_all(InitStrategy::kInitReset, n);
    467   printf("\n");
    468   test_perf_all(InitStrategy::kReinit, n);
    469 
    470   return 0;
    471 }
    472 
    473 #else
    474 
    475 int main() {
    476   print_app_info(0);
    477   printf("!!AsmJit Benchmark Reuse is currently disabled: <ASMJIT_NO_JIT> or unsuitable target architecture !!\n");
    478   return 0;
    479 }
    480 
    481 #endif