Gambas-it

Gambas3 => Domande tecniche => Topic aperto da: vuott - 23 Maggio 2012, 23:49:20

Titolo: New JIT Compiler
Inserito da: vuott - 23 Maggio 2012, 23:49:20
Ambasciata della Comunità italiana di Gambas sulla mailing list internazionale

Comunicazione n. 6 dal vostro Ambasciatore     ;D

Questa Ambasciata porta a conoscenza un avviso inviato oggi da Emil Lenngren (della mailing list internazionale di Gambas):


Hi everybody.

I've been working on a JIT-compiler for Gambas for some months, and I'm now
ready to release an alpha-version in the latest svn of Gambas.
The compiler uses LLVM to produce machine code for x86 or x86_64. You need
LLVM on your computer for it to work, preferably the latest version from
svn (3.0 from Ubuntu repos does not seem to work any well). Find more
instructions in the README file.

To use it, place the word "Fast" at the top of a Gambas Class file, for a
class that you want all functions JIT-compiled instead of interpreted. (At
the moment you cannot make individual functions JIT-compiled, but that is
limited by the gbc compiler.)

As it takes some milliseconds for LLVM to emit machine code and do
optimizations, you should only use it for functions you really need
optimizations.

As the JIT compiler analyses the whole function before execution starts,
some extra type safety is added. In interpreter mode, you can normally do
things like:
Print "hello"
Print 1.3 \ 5
and you will first see hello on the screen, and then an error message
complaining you can't do integer division on floats.
If you run the same function in the JIT compiler, the error message will be
thrown before execution starts instead, hopefully in order to make programs
less buggier.
As a consequence, you can not have code like "Try Print 1.3 \ 5" either. At
the moment the incorrect line is reported in the error message...

The best speed-ups will be in functions that use a lot of low-level
calculations and control flows (except For Each loops), like functions that
do a lot of math. If the function mostly calls other libraries, you won't
see speed-ups either.
There are still the same overhead when calling functions, since the gambas
stack must be maintained as before, to make error handling work.
Using Try/Catch is probably slightly slower too because a real exception
handler must be set up.

Something the LLVM optimizer is very good at is transforming a chain of
if-else statements to a jump table, so code like:
Select Case x
  Case 1:
    ..
  Case 2:
    ..
  Case 3:
    ..
End Select
will be much faster than before, so you don't have to use the "On Goto"
syntax and a lot of labels. This will produce identical machine code.

Most things are implemented, but there are still many bugs to fix.
Some of the (so far) unimplemented features are
Calling external C libraries (the Extern keyword).
The use of "_unknown" special method.
IIf and Choose with different argument data types.
The possibility to use Component.Load to load functions that are executed
right after in the same function.
Profiling
Breakpoints

Some of the benchmarks from http://gambasdoc.org/help/doc/benchmark
Polynom: 102.7 seconds to 4.7 seconds
Primes: 18.3 seconds to 3.5 seconds
Nbody: 16.0 seconds to 1.8 seconds

If you are curious and want to see the optimized LLVM IR you can uncomment
the line M->dump() at the bottom of the jit_codegen.cpp file in gb.jit/src.

I hope the JIT compiler will be useful for you ;)

/Emil

Forgot to mention that the 64-bit version is probably more bug-free than
the 32-bit version, since I myself have a 64-bit computer and therefore
have run only some few tests on 32-bit...
Titolo: Re: New JIT Compiler
Inserito da: vuott - 24 Maggio 2012, 00:26:51
Aggiornando normalmente Gambas-3 da SVN, al termine di ./configure -C si avrà questo avviso:

||
|| Unable to find file: llvm/LLVMContext.h
|| Unable to find file: libLLVM-3.2svn.so
|| gb.jit is disabled
||


ed alla fine:

||
|| THESE COMPONENTS ARE DISABLED:
|| - gb.jit
||


Per chi volesse installare quel componente:
https://www.google.it/#q=gb.jit+is+disabled


Successivamente è molto probabile che occorra posizionarsi nella directory ~ $ trunk/gb.jit. Quindi lanciare lì: ./configure senza il flag -C.

Si può quindi provare a continuare l'aggiornamento di Gambas. Si consiglia di rilanciare come di consueto: ~ $ trunk ./reconf, poi ~ $ trunk ./configure -C .

Se al termine di ~ $ trunk ./configure -C dovesse comparire l'avviso:

||
|| THESE COMPONENTS ARE DISABLED:
|| - gb.jit
||


si può provare rimuovendo i file gb.jit/DISABLED* rimasti (comando: ~/trunk/gb.jit $ rm gb.jit/DISABLED*, e sempre restando nella directory ~ $ trunk/gb.jit lanciare quindi il comando make seguito da sudo make install .

Al termine, ripetere il completamento dell'aggiornamento di Gambas ripetendo i passaggi come di consueto: ~ $ trunk ./reconf, poi ~ $ trunk ./configure -C ; quindi dando gli ultimi due comandi make seguito da sudo make install.
Titolo: Re: New JIT Compiler
Inserito da: vuott - 24 Maggio 2012, 16:18:51
Potete quindi provare le fuzionalità del componente acceleratore gb.jit lanciando questo codice con e poi senza la parola "Fast" posta all'inizio del codice medesimo):

Codice: gambas [Seleziona]

 Fast

 Public Sub Button1_Click()

 Dim i As Long

   For i = 1 To 1000000000
   Next
  
  Print "Funziona !"
  
 End


Lo scopo è verificare quanto tempo sarà impiegherà per stampare in console la frase "Funziona !".

Oppure potete provare quest'altro (sempre con e poi senza la parola "Fast":
Codice: gambas [Seleziona]

 Fast

Public Sub Button1_Click()

Dim I As Integer

 For I = 1 To 10
   Print Test(0.2)
 Next
 
 End

 
Sub Test(X As Float) As Float

  Dim Mu As Float = 10.0
  Dim Pu, Su As Float
  Dim I, J, N As Integer
  Dim aPoly As New Float[100]

  N = 500000

  For I = 0 To N - 1
    For J = 0 To 99
      Mu = (Mu + 2.0) / 2.0
      aPoly[J] = Mu
    Next
    Su = 0.0
    For J = 0 To 99
      Su = X * Su + aPoly[J]
    Next
    Pu += Su
  Next

  Return Pu

End


Verrà scritta in console una cifra per dieci volte. Se impiegherà pochi secondi, il componente gb.jit funziona, se impiega alcuni minuti il componente non funziona.


Se e quando attivate la parola "Fast" ed il componente gb.jit funziona, noterete la differenza di tempo impiegato !  :o
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 25 Maggio 2012, 10:18:40
Insomma, un ottimizzatore di codice... un pò strano ma se i risultati sono evidenti, allora...

Un paio di dubbi:

1) se è necessario un ottimizzatore (generico in quanto non mi sembra sia parametrizzabile), vuol dire (cosa che già sapevo) che Gambas è da sistemare;
2) da quanto si evince dal messaggio ad inizio thread, ha delle limitazioni. Questo non vuol dire che abbia dei problemi, solo che potrebbe crearli con codice non perfetto.
Titolo: Re: New JIT Compiler
Inserito da: vuott - 25 Maggio 2012, 12:21:41
Insomma, un ottimizzatore di codice... un pò strano ma se i risultati sono evidenti, allora...

Un paio di dubbi:

1) se è necessario un ottimizzatore (generico in quanto non mi sembra sia parametrizzabile), vuol dire (cosa che già sapevo) che Gambas è da sistemare;
2) da quanto si evince dal messaggio ad inizio thread, ha delle limitazioni. Questo non vuol dire che abbia dei problemi, solo che potrebbe crearli con codice non perfetto.

Cosa dire ?  :-\ Io ho apportato 'sta modifica al carburatore  ;D , ed in sé la cosa effettivamente funziona..... se son rose fioriranno.   :-[
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 25 Maggio 2012, 12:47:30
Immagino di sì, dato che hai fornito anche esempi ad-hoc.

Bè, i miei sono solo dubbi in quanto lo vedo un controsenso. Se funziona è un'altro paio di maniche, e và pure bene così.

Tengo sottomano le tue note, nel caso mi venga in mente di utilizzare questa libreria.  :ok:
Titolo: Re: New JIT Compiler
Inserito da: vuott - 25 Maggio 2012, 12:57:41
Comunque sia, come è chiaro, se non si pone la parola chiave "Fast" ad inizio del codice, il... turbo non s'attiva, e tutto funziona semplicemente come prima.
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 25 Maggio 2012, 13:35:43
Sì, ho capito.

La trasformazione avviene durante l'esecuzione, implementando le funzionalità avanzate di questa nuova libreria. Diciamo che è una duplicazione delle librerie base di Gambas, ovviamente ottimizzate...
Titolo: Re: New JIT Compiler
Inserito da: milio - 28 Maggio 2012, 11:05:40
Caspiterina... ho fatto il test con il secondo esempio:

Senza Fast:

00:02:14.683

con Fast:

00:00:05.854

Pazzesco!  :o
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 28 Maggio 2012, 12:14:17
Come ho detto, questo insinua dei dubbi sull'ottimizzazione del codice base di Gambas...

Devo assolutamente dare un'occhiata ai sorgenti...
Titolo: Re: New JIT Compiler
Inserito da: Ceskho - 28 Maggio 2012, 15:23:34
Sarebbe interessante sapere perchè queste novità non vengono introdotto di default...mah....
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 31 Maggio 2012, 18:10:53
Caro vuott, mi hai incuriosito, per cui stò tentando di compilare i sorgenti per testare quest enuove funzionalità.
Il problema è che:
||
|| THESE COMPONENTS ARE DISABLED:
|| - gb.desktop.gnome
|| - gb.jit
||
questi due componenti non vengono compilati, e non c'è alcuna spiegazione nella doc per capire quali librerie mancano.
Tu che hai testato jit, come l'hai compilato?
Titolo: Re: New JIT Compiler
Inserito da: vuott - 31 Maggio 2012, 23:32:30
Caro vuott, mi hai incuriosito, per cui stò tentando di compilare i sorgenti per testare quest enuove funzionalità.
Tu che hai testato jit, come l'hai compilato?

Dai un'occhiata al mio secondo messaggio sopra.

Ad ogni modo ti riporto in sequenza temporale i suggerimenti che ho ricevuto via posta elettronica da Emil Lenngren, che è il realizzatore di quel componente:

Innanzitutto mi ha suggerito questo passaggio (e mi ha chiesto di inviargli il relativo listato del terminale):
Go to the gb.jit directory. Then try to run ./configure without the -C flag.

Dopo che gli ho inviato il listato da ./configure, mi ha scritto:
Try to remove any gb.jit/DISABLED* files left behind and then run make followed by sudo make install in the gb.jit directory.
In gambas top-level: rm gb.jit/DISABLED*


Quindi mi ha precisato di ripetere la procedura di aggiornamento partendo da...:
You must issue a ./reconf before ./configure -C

Minisini, intervenendo, mi precisa che una CPU andrà comunque al 100% facendo il test:
CPU must be at 100% (on one core) in both case. The JIT compiled
function is just faster. Just try with the FAST keyword, and without, and compare the execution time.


.....non so se ho soddisfatto la tua richiesta....  :-X


Se, poi, continui ad avere problemi, non avrai altra possibilità che appellarti a... Papa Ceskho I  !   :devil:
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 01 Giugno 2012, 10:15:25
Nooooo, papa checkho noooooo !!!! (ho detto papa?!?)

In effetti mi era sfuggito qualche tuo passo precedente (è l'età...).

Quindi tocca fare qualche operazioncina manuale in modo da abilitare il modulo...
La cosa brutta, anche se comprensibile, è il fatto del consumo esponenziale delle risorse. Vuol dire che le funzionalità di Fast vanno ad agire pesantemente e direttamente sui cicli macchina. A questo punto è ovvio l'incremento delle prestazioni, solo che a questo punto la vedo dura... Non si può impegnare un sistema per una singola applicazione, magari bloccando il multitasking e il parallelismo insito in Linux. Sicuramente si può considerare un tentativo di miglioramento, ma solo una specie di verifica delle potenzialità di alcune logiche.

Ad ogni modo, appena ho un attimo, cercherò di analizzare la cosa, per saperne di più. Secondo me, al momento, è meglio usare la libreria per soli test...
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 01 Giugno 2012, 16:09:02
Aggiornamento...

Ho dato un'occhiata ai sorgenti della libreria, e ho notato che non è altro che una serie di funzionalità legate ad una linbreria esterna LLVM, che è un ottimizzatore di codice, questo il link

http://llvm.org/ (http://llvm.org/)

Stò leggendo qualcosa sul sito, anche perchè non ne ero a conoscenza, e magari vedo di reportare quanto appreso qui nel forum.

Ad occhio, però, il discorso è un tantino diverso dal quello scaturito dai miei dubbi iniziali, anche se comunque aggiunge uno strato, anzi scavalca totalmente, il motore base di Gambas. Attualmente, dai metodi implementati, sono stati coperti solo alcune funzioni base, ma sicuramente fattibile la copertura totale di tutto il motore.

Non sono ancora andato a spulciare la documentazione e le specifiche, ma come tutti gli ottimizzatori, la cosa ha i suoi pro e suoi contro, ed è quindi pensabile un uso limitato per determinati tipi di applicazione.

Titolo: Re: New JIT Compiler
Inserito da: vuott - 01 Giugno 2012, 17:03:34
La cosa brutta, anche se comprensibile, è il fatto del consumo esponenziale delle risorse. Vuol dire che le funzionalità di Fast vanno ad agire pesantemente e direttamente sui cicli macchina.

Comunque lo stesso Minisini mi aveva sottolineato che facendo quei due esperimenti, sopra riportati, "con" e "senza" FAST, una CPU sarebbe stata utilizzata al 100%. Infatti, ho verificato che è così.
Ho fatto una prova di velocità utilizzando la chiamata ad una brevissima e semplice libreria esterna in C, scritta da me, per contare da 0 a 1 miliardo; ed anche in questo caso l'uso della CPU è andato al 100%.

V'è da notare, in particolare, che la chiamata della funzione esterna, scritta in C, mi è risultata ben meno veloce (ms 2266)  dell'uso di Fast (ms 966). Se in essa è presente l'Assembly, si è mostrata un po' più veloce: in media 650 millisecondi !
Titolo: Re: New JIT Compiler
Inserito da: vuott - 02 Giugno 2012, 00:50:14
...ora però faccio notare che operando al di fuori di Gambas e facendo qualche prova su portatile a contare fino a 1 miliardo in Assembly e anche in C puro, si è avuto:
* in Assembly: 510 millisecondi;
* C compilato con GCC: 2090 millisecondi.
Il che da un lato dimostra che con l'Assembler si va super (che però contemporaneamente bisogna interfacciarlo bene); dall'altro evidentemente se con Gambas si utilizza una libreria esterna, nonostante si usi l'Assembly, vi è qualche difficoltà (come ho rappresentato nel mio precedente messaggio). Forse  :-\ c'è un qualche problema di impostazioni globali e settaggi vari...
Possibile mai che Gambas vada più veloce con Fast piuttosto che con l'uso di una libreria esterna contenente l'Assembly ?  :rolleyes:

bella questione da rivolgere a Minisini.......
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 02 Giugno 2012, 14:05:03
A parte che non ben capito che prova hai fatto con l'asm, cosa hai usato, come l'hai compilato, e via dicendo...
Riguardo al C (ma C o C++ ?), mi pare strano che tu abbia differenze così evidenti con l'asm, dato che una volta compilato è codice puro, a meno con tu non abbia usato funzioni ad alto livello (es. oggetti stringhe), che è da tener presente che questo tipo di oggetti sono molto pesanti a livello di codice macchina. E' anche ovvio che la compilazione necessita di ottimizzazione, nel senso che bisogna operare sui parametri per compilare nel miglior modo possibile.
La cosa che però mi pare strana, nonostante sia stato usato un ottimizzatore, è quella appunto che il codice Gambas è interpretato, e non ha puramente codice a basso livello suo interno, perchè si appoggia a prodotti esterni. Il fatto appunto che ci sia un interprete in mezzo, che poi passa codice precompilato all'ottimizzatore, è già di per sè un inserimento di un fattore ritardo che non può essere minore dei tempi fatti scrivendo codice puramente a livello macchina, che non ha intermediari di mezzo. Posso capire che si possano avere incrementi di prestazione, usando arzigogoli particolari, ma addirittura superare quelli di un codice diretto mi pare alquanto anomalo...
Di certo è passato molto tempo da quando scrivevo programmi realtime in asm/c, ma qui mi pare fuori logica...  :-\
Titolo: Re: New JIT Compiler
Inserito da: vuott - 03 Giugno 2012, 00:19:18
A parte che non ben capito che prova hai fatto con l'asm, cosa hai usato, come l'hai compilato, e via dicendo...

Ho fatto nuovamente una prova in terminale lanciando con uno script con il motore del codice in asm che conta fino a 1 miliardo:

Codice: c [Seleziona]

static unsigned int car asm("raxregistro");
static unsigned int cbr asm("rbxregistro");

int prova(int numero) {
 cbr=numero;
 asm("mov rbxregistro(%rip),%eax");
 asm("ciclo:");
 asm("dec %eax");
 asm("jne ciclo");
 asm("mov %eax,raxregistro(%rip)");
return car;
}

Ha dato mediamente un tempo di 570 millesimi di secondo !


Invece, usando il C puro, sempre lanciato con script da terminale:
Codice: c [Seleziona]

#include <stdio.h>

int prova(int numero) {
int i;
for(i = 0; i < numero;i++){
}
return i;
}

In questo caso il risultato è stato: 2091 millisecondi.


Realizzata, invece, la seguente libreria esterna .so, con il primo codice (quello che presenta il motore in asm), ossia:
Codice: c [Seleziona]

static unsigned int car asm("raxregistro");    
static unsigned int cbr asm("rbxregistro");    

int prova(int numero) {
cbr=numero;
asm("mov rbxregistro(%rip),%eax");
asm("ciclo:");
asm("dec %eax");
asm("jne ciclo");
asm("mov %eax,raxregistro(%rip)");
return car;
}

e richiamata con Gambas, passandole il valore di 1 miliardo, si ha un risultato intorno ai 655 millisecondi !


Riguardo alla strana lentezza del codice asm (ma anche con il C come si vede sotto) con Gambas ho posto la questione a Minisini.  ;D


Faccio comunque notare che usando Gambas il conteggio da 0 ad 1 miliardo:
* con Fast = ms 966;
* con la libreria esterna scritta in C = ms 2430
* con la libreria esterna con motore asm (ovviamente compilato): ms 655
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 03 Giugno 2012, 12:01:16
Quindi, se ho capito bene, hai provato ad eseguire il test con asm e c da terminale (spero), e per i tempi hai usato time?

Riguardo all'esecuzione da gambas, dato che ci sono molte incognite, riguardo al fatto che ci sono chiamate esterne e il passaggio di dati, questo potrebbe influire in maniera notevole sui tempi.

Anche per il C, invece del for... potresti usare lo stesso sistema usato per asm, ovvero con un loop su label...

Visto che ci sei...  ;D
Titolo: Re: New JIT Compiler
Inserito da: vuott - 03 Giugno 2012, 14:10:31
Quindi, se ho capito bene, hai provato ad eseguire il test con asm e c da terminale (spero)
Sì, da terminale.


per i tempi hai usato time?
Nello script:
Codice: [Seleziona]
tempo1=`date +%s%N | cut -b1-13`
LD_LIBRARY_PATH="." ./demo_use
tempo2=`date +%s%N | cut -b1-13`
sottrazione=$(($tempo2 - $tempo1))

Anche per il C, invece del for... potresti usare lo stesso sistema usato per asm, ovvero con un loop su label...
Visto che ci sei...  ;D
Bene, ho fatto, ed ecco i risultati (sempre contando da 0 a 1 miliardo) usando il GOTO all'interno del codice in C puro:
Codice: c [Seleziona]

int prova(int numero) {
 int i;

 zompa:
  if (i < numero){
  i++;
  goto zompa;}
 return i;

}

* con script da terminale: ms 1779   (con For invece: ms 2091);

* con libreria .so in Gambas: ms 2011   (con For invece: ms 2430).

Quindi un miglioramento effettivamente c'è !



Riguardo all'esecuzione da gambas, dato che ci sono molte incognite, riguardo al fatto che ci sono chiamate esterne e il passaggio di dati, questo potrebbe influire in maniera notevole sui tempi.
Bisognerà chiamare un esorcista   ..... Papa Ceskho I !!!   Lui è esperto da quanto so: notare l'antica immagine di Papa Ceskho I eremita che lotta contro il demone che tenta di inserire molte incognite in una libreria esterna .so  .
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 03 Giugno 2012, 17:29:02
Il mio suggerimento riguardo il test con c proviene dall'esperienza fatta in campo realtime, e come vedi le differenze sono tangibili.

Il tutto riporta a come sono state costruite le librerie cui fai uso.

A suo tempo, quando avevo iniziato a programmare in C++, meravigliato dalle nuove potenzialità di una programmazione ad oggetti, avevo iniziato a lavoraci sopra, scoprendo poi quanta differenza e quanti problemi dava questa trasformazione. La cosa ovviamente era ed è di poca importanza quando un'applicazione aveva il solo scopo di fornire un'interfaccia con un utente, ma diventava problematica quando si dovevavo fare calcoli e rispondere ad un evento entro tempi strettissimi (nell'ordine del microsecondo e addirittura molto minori). Il discorso assumeva aspetti preoccupanti quando ci si accorgeva che l'accumulo di un ritardo (anche del millisecondo) dipendeva ovviamente dal numero di eventi, che portava di conseguenza a ritardi mostruosi...
Quando si ha a che fare con applicazioni, la cui interazione è dipendente dalla reazione umana, i ritardi assumono un'importanza marginale. Tenendo conto che, nella migliore delle ipotesi, la reazione umana ha un velocità di circa 300ms, il fatto che poi un'operazione ci metta 50/100ms non crea preoccupazione. Se già il numero minimo di fotogrammi necessari per non far notare all'occhio la transazione è di circa 25/sec, ovvero 40ms a fotogramma, questo ti dà un'idea della cosa (e stiamo parlando dell'occhio, che è sicuramente superiore come velocità di una mano su una tastiera...).

A parte i piccoli ritocchi che uno può fare su un codice per migliorarne le prestazioni, si possono intraprendere anche altre tecniche, ma questo discorso credo vada oltre a questa discussione.

Da quello che ho notato nella nuova libreria, è che la stessa và a sostituire quasi completamente alcune funzioni base di gambas, traducendole direttamente e trasferendole alle funzioni di llvm. Queste trasformazioni riguardano principalmente le funzioni e le operazioni di calcolo (ovvero la parte matematica), e di certo non possono influire sulle logiche più ad alto livello, come ad esempio l'interfacciamento di un database e/o l'i/o verso/da fonti esterne. Anche le classi sono esclude da questa trasformazione, in quanto oggetti facenti parte di uno strato software complesso e altamente dinamico.
Titolo: Re: New JIT Compiler
Inserito da: vuott - 04 Giugno 2012, 13:53:14
Anche per il C, invece del for... potresti usare lo stesso sistema usato per asm, ovvero con un loop su label...
Ho effettuato la prova del conteggio da 0 a 1 miliardo con uso del GOTO in C con sistema Kubuntu a 32bit, montato in modo "persistente" su penna. Ebbene, i risultati - provati più volte - del ciclo con libreria esterna contenente il ciclo Goto e con altra libreria esterna contenente il ciclo For, entrambe scritte in C puro, sono stati del tutto diversi da quelli che ho segnalato sopra effettuati su un 64bit.

In particolare, con quel 32bit ho ottenuto:
* con ciclo GOTO = ms 4850
* con ciclo FOR = ms 2190
  :rolleyes:
Titolo: Re: New JIT Compiler
Inserito da: md9327 - 02 Luglio 2012, 14:00:13
Caro vuott, sarà sicuramente il caldo di questi giorni, ma mi sono completamente perso...

Tanto per capire e fare un confronto immediato, non riesci a fare una tabellina con i valori riscontrati dai tuoi test?

Andando su e giù tra i post, mi dimentico di cosa stò cercando e qual'era il primo valore...  :D