This article is a continuation of the articles:
Simple test libjit vs llvmA simple llvm / libjit part II test, the same + gnu lightning .
Introductory curtsy
In previous articles, the performance of llvm, libjit and gnu lightning was examined using the example of the sieve of eratosthenes. All of the options considered are low-level libraries that have a good rate of fire, but are essentially specialized assemblers, and, for example, you will have to implement work with strings yourself.
')
There are other virtual machines that you can include in your program as a backend for your
DSL . For example - born as a result of
April Fool's joke -
parrot is the basis of the future pearl.
There, the possibilities are much greater, including strings, hash tables, dimensionless arrays, garbage collection, console and file I / O, and other nice things. The question is - what is the price (in performance loss) for all these nice additions?
Let's try.
Eratosthene sieve on parrot
As before - these are two procedures, one of them (erato) is implemented by the algorithm itself, the second (main) runs 100_000 times erato to search for prime numbers from 1 to 50_000.
.loadlib 'trans_ops'
.loadlib 'math_ops'
.sub 'erato'
.param int n
$P0 = new 'ResizableIntegerArray' # a = P0
$P0 = n
$N0 = sqrt n # q = I0
$I0 = floor $N0 # i = I1
$I1 = 2
for_cond:
if $I1 > $I0 goto for_end
$I2 = $P0[$I1]
if $I2 == 1 goto end_if
$I3 = $I1 * $I1 # j = I3
while_cond:
if $I3 > n goto while_end
$P0[$I3] = 1
$I3 += $I1
goto while_cond
while_end:
end_if:
$I1 += 1
goto for_cond
for_end:
.end
.sub main :main
$I10 = 0
for_test1:
if $I0>100000 goto for_end1
erato(50000)
$I0 += 1
goto for_test1
for_end1:
.end
And - a control program that runs all this:
001 : #include <parrot/embed.h>
002: #include <parrot/extend.h>
003:
004: int main ( int argc, char * argv[])
005: {
006: Parrot_Interp interp;
007: Parrot_PackFile pf;
008:
009: interp = Parrot_new( NULL );
010: if ( ! interp) {
011: return 1 ;
012: }
013:
014: pf = Parrot_pbc_read(interp, "erato.pbc" , 0 );
015: Parrot_pbc_load(interp, pf);
016: Parrot_runcode(interp, argc, argv);
017:
018: Parrot_destroy(interp);
019:
020: return 0 ;
021: }
022:
So, compile a new version:
parrot -o erato.pbc erato.ptr
gcc -O2 erato.c -I /usr/include/parrot/2.0.0/ -lparrot -o erato
And launch:
/usr/bin/time -f "%U" ./erato
2361.2
Products and fruits of the author's movement of thought
Total, our table takes the form:
VM | Runtime in seconds, (less = better) |
---|
Llvm | 13.77 |
---|
LIBJIT | 14.17 |
---|
GNU LIGHTNING | 32.59 |
---|
PARROT | 2361 |
---|
And just for information: |
gcc -O0 | 50.09 |
---|
gcc -O1 | 13.79 |
---|
similar perl program | 4288 |
---|
That is, the parrot virtual machine runs on our example 150 times slower than the jit of the machine. But 2 times faster than the program on the pearl. This is actually good news, it looks like the following versions of the pearl, based on parrot, are going to work faster than today ... However, parrot is clearly not a replacement for the other machines considered if speed is needed.
Final chord
In general, parrot left a very pleasant impression, everything works as described, there were no pitfalls, opportunities — the sea, and the documentation is good. Write on it after llvm - a pleasure. So
for myself, I made up the following recommendations:
- need speed - llvm or libjit, llvm is preferable (better infrastructure, more tools)
- constrained conditions, such as low memory and disk space — gnu lightning;
- if speed is not too important, but you need convenience, working with strings or complex structures - parrot