A simple llvm / libjit test part II, same + gnu lightning

    This article is a continuation of the Simple libjit vs llvm test , which compared the performance of libraries for Just In Time compiling llvm and libjit using the example of the sieve of eratosthenes.

    This article solves exactly the same problem - the sieve of eratosthenes using another JIT library - GNU lightning .

    A few words about gnu lightning - in fact, this is not a library at all, but a set of macros that form an executable buffer.

    So the same solution with

    GNU Lightning



    001:  #include 
    002:  #include 
    003:  #include 
    004:  #include 
    005:  
    006:  static jit_insn codeErato[1024];
    007:  static jit_insn codemain[1024];
    008:  
    009:  typedef int (*pifi)(int); /* Pointer to Int Function of Int */
    010:  typedef void (*pvfv)(void); /* Pointer to void Function of void */
    011:  char a[100000];
    012:  
    013:  int main()
    014:  {
    015:      pifi erato = (pifi) (jit_set_ip(codeErato).iptr);
    016:      pvfv func_main;
    017:      int n, ii;
    018:      jit_insn *for_cond, *for_end, *end_if, *while_cond, *while_end,
    019:      *main_for_beg, *main_for_end;
    020:  
    021:      jit_prolog(1); 
    022:      n = jit_arg_i();          /* n = arg_i  */
    023:  
    024:      jit_getarg_ui(JIT_V0, n); /*  V0 = n   */
    025:      jit_extr_i_f(JIT_FPR0, JIT_V0);
    026:      jit_prepare(1);
    027:      jit_pusharg_f( JIT_FPR0);
    028:      jit_finish( sqrtf);
    029:      jit_retval(JIT_FPR0);
    030:      jit_roundr_f_i(JIT_V1, JIT_FPR0); /*  V1 = q */
    031:  
    032:      jit_movi_p(JIT_V2, a);           /* V2 = a*/
    033:      jit_movi_i(JIT_R0, 1);
    034:      jit_prepare(3);
    035:      jit_pusharg_i(JIT_V0);        /* size_t n */
    036:      jit_pusharg_i(JIT_R0);        /* int c - fillcahr */
    037:      jit_pusharg_p(JIT_V2);        /* array to fill */
    038:      jit_finish(memset);
    039:  
    040:      jit_movi_ui(JIT_R0, 2);       /* i = 1 (R0)*/
    041:      for_cond = jit_get_label();
    042:      for_end = jit_bgtr_ui(jit_forward(), JIT_R0, JIT_V1);
    043:      jit_ldxr_c(JIT_R2, JIT_V2, JIT_R0);
    044:      end_if = jit_beqi_ui(jit_forward(), JIT_R2, 0);
    045:      jit_mulr_ui(JIT_R1, JIT_R0, JIT_R0); /* j = R1 */
    046:      while_cond = jit_get_label();
    047:      while_end = jit_bgtr_ui(jit_forward(), JIT_R1, JIT_V0);
    048:      jit_stxr_c(JIT_V2, JIT_R1, 0);
    049:      jit_addr_ui(JIT_R1, JIT_R1, JIT_R0);
    050:      jit_jmpi(while_cond);
    051:      jit_patch(while_end);
    052:      jit_patch(end_if);
    053:      jit_addi_ui(JIT_R0, JIT_R0, 1);
    054:      jit_jmpi(for_cond);
    055:      jit_patch(for_end);
    056:  
    057:      jit_movr_ui(JIT_RET, JIT_R1);
    058:      jit_ret(); 
    059:      jit_flush_code(codeErato, jit_get_ip().ptr);
    060:  
    061:      func_main = (pvfv) (jit_set_ip(codemain).iptr);
    062:      jit_prolog(0);
    063:      jit_movi_ui(JIT_V0, 1);
    064:      main_for_beg = jit_get_label();
    065:      main_for_end = jit_bgti_ui(jit_forward(), JIT_V0, 100000 );
    066:      jit_movi_ui(JIT_R0, 50000);
    067:      jit_prepare(1);
    068:      jit_pusharg_ui( JIT_R0);
    069:      jit_finish(erato);
    070:      jit_addi_ui(JIT_V0,JIT_V0,1);
    071:      jit_jmpi(main_for_beg);
    072:      jit_patch(main_for_end);
    073:      jit_ret();
    074:      jit_flush_code(codemain, jit_get_ip().ptr);
    075:  
    076:      puts("Go");
    077:      func_main();
    078:      return 0;
    079:  }
    080:  


    We compile and run: Total average runtime 32.59 Combining the results with those that were obtained in the previous article:
    $ gcc lightest.c -lm -o lightest
    $ for i in `seq 1 10`; do /usr/bin/time -f '%U' ./lightest ; done
    32.80
    32.59
    32.57
    32.55
    32.53
    32.59
    32.53
    32.69
    32.54
    32.53






    Jit libraryExecution time in seconds, (less = better)
    LLVM13.77
    Libjit14.17
    GNU LIGHTNING32.59
    And just for information:
    gcc -O050.09
    gcc -O113.79


    That is, gnu lightning results in rate of fire are approximately between the “without” and “with” optimization compiled with the C program.
    I must say that gnu lighning presents a much lower level interface than llvm and libjit. Many things remain on the conscience of the programmer. For example, the allocation of registers (lightning does not do this, there are just 6 registers for int and 6 for float / double, and spin as you want). For example - optimization.

    Of the unpleasant things, I would also note that for lightinig before broadcastyou need to allocate a buffer for the code yourself. Which can be a problem, since the required size of this buffer can be estimated only approximately, and there is a risk of catching a segmentation fault if you make a mistake. In addition, the documentation on the site is inaccurate. For example, it uses jit_allocai (), which is no longer in the current version of lightning.

    On the positive side, the command system in the API in lightning is well thought out, so if you compare by verbosity, it can be seen that the solution on lightning is almost twice as short as on libjit or llvm. Since all lightning is just a set of macros, we get programs that are independent of any third-party libraries. The size of the resulting executable file is very modest (this is a pebble in the llvm garden, where the file size is quite large).

    Morality.


    I would use GNU lightning only if the resulting program should work under very severe conditions in terms of memory and disk space. In all other cases - libjit or llvm is objectively better and safer.

    Also popular now: