📜 ⬆️ ⬇️

Simple llvm / libjit part II test, the same + gnu lightning

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

In this article, exactly the same problem is solved - 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 the executable buffer.

So, the same solution with
')

GNU Lightning



001 : #include <stdio.h>
002: #include <lightning.h>
003: #include <math.h>
004: #include <string.h>
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:


Compile and run:
$ 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


Total average run time 32.59

Combining the results with those obtained in the previous article:

JIT libraryRuntime in seconds, (less = better)
Llvm13.77
LIBJIT14.17
GNU LIGHTNING32.59
And just for information:
gcc -O050.09
gcc -O113.79


That is, the results of gnu lightning on the rate of fire are approximately between the "without" and "with" compiled C programs compiled.
It must be said that gnu lighning represents a much lower level interface than llvm and libjit. Many things remain on the programmer's conscience. For example, register allocation (lightning does not do this, there are just 6 registers for int and 6 for float / double, and spin as you like). For example - optimization.

Of the unpleasant things, I would also note that for lightinig, before broadcasting, you need to allocate the buffer for the code yourself. What can be a problem, since the required size of this buffer can only be estimated approximately, and there is a risk to catch the 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.

From the positives - the system of commands in the API in lightning is well thought out, so if you compare by verbosity - it is clear that the decision on lightning is almost half as long as libjit or llvm. Since all lightning is just a set of macros, programs are obtained that do not depend on any third-party libraries. The size of the resulting used file is very modest (this is a pebble in the llvm garden where the file size is large enough).

Morality.


I would use GNU lightning only if the resulting program should work in very harsh conditions from memory and disk space. In all other cases, libjit or llvm is objectively better and safer.

Source: https://habr.com/ru/post/101769/


All Articles