MokaByte Numero 32  -  Luglio Agosto 99
 
HotSpot
Promesse mantenute o delusione?
di 
Mauro Molino
Esaminiamo lo stato della nuova virtual machine di Sun, analizzando le differenza fra le promesse fatte e ciò che è stato realmente realizzato

 

    Preistoria

    Siamo in tanti ad aver seguito Java fin dalla sua comparsa, e dopo esserne rimasti irrimediabilmente ammaliati ci siamo buttati a capofitto nella sua evoluzione. 
    La maturazione è stata costante e ora ci troviamo di fronte non più ad un semplice linguaggio object oriented dalle belle speranze, ma ad una tecnologia completa e in grado di soddisfare qualsiasi tipo di approccio richiesto. Abbiamo man mano visto nascere JDBC per l'interfacciamento a database, Swing per mettere fine all'incubo delle AWT in ambito di interfaccia utente, Java 2D, Java 3D e Advanced Image Processing per la grafica avanzata, Java Speech per il riconoscimento vocale, i Servlet e le JSP per i servizi web server side e la maturazione dei Java Beans, fino ad arrivare a JINI, la tecnologia delle federazioni di hardware. 
    In tutto questo però, ci siamo sempre dovuti confrontare con un problema in alcuni casi estremamente limitante: la velocità. E' vero che spesso la limitazione non è così pressante, però nella maggior parte dei casi le prestazioni risultavano realmente inaccettabili. Ad alleviare i dolori dei giovani ( e meno giovani) virgulti della religione Javaica sono arrivati i vari JIT ( Just in Time Compilers). Questi si comportano come un compilatore statico, con la differenza che la compilazione avviene al momento dell'esecuzione del programma per cui, dopo un iniziale overhead di tempo dovuto proprio alla compilazione, l'applicativo verrà eseguito come codice nativo in memoria. 
    Grosso modo possiamo dire che mentre con l'interprete JVM un programma Java risultava da 50 a 100 volte più lento rispetto ad uno corrispondente ottimizzato in C/C++, con i JIT il rapporto è drasticamente diminuito, attestandosi su un molto più accettabile 5-10 volte. Il vantaggio è che comunque viene conservata la portabilità dei programmi. Ma volendo proporre Java come linguaggio ad altissima diffusione gli sforzi non erano ancora sufficienti. Sono comparsi dei compilatori in grado di trasformare un programma Java in codice nativo, come quello IBM ( da non confondere con altri prodotti che generano un eseguibile .exe, ma che in realtà non fanno altro che creare un wrapper intorno al programma, che comunque viene eseguito dalla VM). Il contro naturalmente è che un siffatto programma rimane vincolato alla piattaforma hardware sulla quale è stato compilato.E poi ?
     
     

    Sun annuncia HotSpot 

    Ricordo quando, a metà tra il commosso e l'incredulo , ho per la prima volta letto di una nuova fantomatica Virtual Machine, annunciata da mamma Sun . Era grosso modo il primo quarto del 1998 e quello stesso giorno ho vagato per tutta la rete accumulando notizie e informazioni su HotSpot. Ma cosa è questa panacea di tutti i mali prestazionali informatici ?
    HotSpot è una virtual machine con numerose caratteristiche innovative. Innanzitutto contiene in se sia l'interprete della VM classica (seppur con alcune revisioni) sia un compilatore per cui, una volta lanciata l'esecuzione del programma, questo viene trattato così come siamo abituati dalla VM originale. Ma da questo momento in poi le cose cambiano radicalmente, in quanto entra in scena il compilatore, che si occupa di compilare quei metodi che risultino particolarmente critici per l'applicazione. Un compilatore di questo tipo viene generalmente definito"adattivo", in quanto, a differenza di un compilatore statico , è in grado durante l'esecuzione del programma di rendersi conto di quali metodi vengano richiamati più spesso, compilarli e renderli così estremamente più veloci. I metodi compilati risiedono in memoria cache. Quando il programma chiama un metodo, se esiste la versione compilata viene utilizzata questa, altrimenti sarà eseguita la versione interpretata. Questo tipo di approccio è stato scelto perché in realtà, in genere è il 20% dei metodi di un programma a utilizzare gran parte del tempo richiesto, mentre il restante 80% viene richiamato raramente o mai. Il vantaggio rispetto ad un JIT, che compila tutti i metodi, è che quest'ultimo ha bisogno di utilizzare una quantità di memoria molto maggiore, dovendo "appoggiarvi" tutti i metodi compilati, senza peraltro apportare una significativa differenza di prestazioni, dato che appunto, gran parte dei metodi compilati saranno eseguiti pochissime volte. Per di più HotSpot è in grado di fare quella operazione nota come "inlining" del codice, cioè di sostituire alla chiamata ad un metodo, il codice del metodo stesso, risparmiando preziosi cicli macchina. Ma dato che questa operazione per contro ingrandisce il blocco del codice, viene fatta solo dove sia ritenuto necessario in base alle informazioni raccolte durante l'esecuzione.
    Paradossalmente però, queste caratteristiche potrebbero venire oscurate da altre due novità di HotSpot. Infatti da un lato è stato migliorato il Garbage Collector (GC), e dall'altra la sincronizzazione dei Thread. Se da un lato GC e Thread rappresentano un enorme punto di forza di Java, dall'altro sono entrambi dei processi avidi di millisecondi. Il GC è comodissimo, in quanto permette (quasi sempre) di non occuparsi della gestione degli oggetti non più utilizzati, i quali vengono "spazzolati" automaticamente evitando di lasciare oggetti zombie in giro per la VM. Fino ad ora, il processo di GC, periodicamente "spazzolava" tutta l'area di memoria dei processi, in cerca di oggetti da pulire. Il nuovo GC tratta gli oggetti in maniera "generazionale", cioè considera gruppi di oggetti cronologicamente omogenei (coetanei), e nella sua opera di spazzolamento si limita a controllare all'interno di questi gruppi periodicamente. In questo modo, il processo dura pochissimo e può essere ripetuto più spesso. In più nell'implementazione del nuovo GC si sono abbandonati gli handles a favore dei puntatori diretti a locazioni di memoria. In pratica, dato che un handle non è altro che un puntatore ad un puntatore, si è eliminato un passaggio supplementare.
    Per quanto riguarda la sincronizzazione dei Thread, si è provveduto ad un notevole snellimento , consentendo una minore richiesta di CPU da parte di questo prezioso processo.
    Non basta: sono state migliorate alcune classi quali quelle per I/O , String e StringBuffer. 
     
     

    In teoria tutto bello, ma in pratica ? 

    Eh si, abbiamo tutti sperato che finalmente Java avrebbe potuto "girare" alla stessa velocità di un programma scritto in C++. In realtà le cose non stanno esattamente così. Inizialmente era stato annunciato il rilascio di HotSpot come prodotto commerciale. In seguito Sun ha rilasciato la prima versione gratuitamente, facendo intendere che la versione successiva sarà molto più potente e commerciale. 
    Appena ho scaricato ed installato HotSpot, ho voluto provarne le prestazioni su programmi già testati sulla VM del JDK1.2 .Devo ammettere che la delusione non è stata poca quando mi sono accorto che la differenza di velocità fra le due VM non era così accentuata come mi sarei aspettato. Dopo le prime prove comparative l'impressione non era mutata. Mi sembrava niente di più che una versione un po' migliorata della "vecchia" VM. Ho lasciato perdere. A distanza di un paio di settimane, mi sono imbattuto in una serie di scambi di news su un news-group specialistico internazionale, dove si scontravano le due scuole di pensiero dei denigratori e dei difensori di HotSpot. 
    Leggendo ho capito alcune cose che, preso dalla foga e dalla speranza , avevo inizialmente trascurato. Intanto, il processo di ottimizzazione applicato da HotSpot non è istantaneo, in quanto i metodi da ottimizzare vengono selezionati durante l'esecuzione stessa del programma, e poi non è detto che il metodo di compilazione adattiva sia quello giusto per tutti i tipi di applicazioni. Ad esempio: un programma che debba svolgere una serie di azioni predefinite e poi chiudersi, come ad esempio un processo lanciato periodicamente per fare qualcosa ( tipo controllare la posta elettronica) , non potrà godere di alcun giovamento da un compilatore adattivo, in quanto i metodi sono eseguiti pochissime volte prima della fine del programma, e il "profiler" non ha così la possibilità di decidere quali metodi compilare. Per di più, le informazioni che il profiler raccoglie, non sono salvate , per cui ogni sessione riparte da zero. 
    Probabilmente questa potrebbe essere una interessante caratteristica da implementare: pensiamo ad un programma in cui l'utente svolga sempre certe azioni e non altre. Se il profiler tenesse traccia di questo, se fosse cioè serializzabile, ai successivi lanci del programma ci sarebbe già un alto grado di ottimizzazione. 
    Andiamo avanti: per contro un programma che rimanga attivo a lungo e che ripeta più volte nel suo ciclo vitale alcune azioni rappresenta il target ideale per una compilazione adattiva. E' il caso degli applicativi server; vengono caricati in memoria per rimanere attivi potenzialmente indefinitamente ed eseguono le stesse funzioni ogni volta che ci sia una richiesta. Sun stessa avverte che HotSpot Profiler Engine ( questo è il suo nome), è stato testato soprattutto su Windows NT4.0 con SP3 e 48 Mb di memoria, piattaforma consigliata, specificando che il motore è inteso per applicativi server, anche se, dice ancora Sun è stato testato anche su Windows 95/98. Per la cronaca, c'è anche la versione per SPARC Solaris.
    Per testare HotSpot sul terreno che sembrava il più congeniale, ho scritto un piccolo programma server, in grado di ricevere richieste via TCP/IP, alle quali rispondeva effettuando una serie di calcoli a seconda della richiesta fatta e restituendo un risultato al client. Per il benchmarking c'è stato subito un problema: i normali test di benchmark non sono adatti ad un compilatore adattivo, in quanto concepiti per testare programmi immediati. Per ovviare ho usato il metodo degli antenati: un timer azzerato e avviato all'arrivo della richiesta del client e stoppato all'invio della risposta, salvando i responsi su un database. Ho fatto in modo che cinque client inviassero una richiesta ogni secondo, ed ho lasciato andare il programma per 30 minuti. I risultati non sono certo accurati come un test tipo Caffeine Mark, però possono dare un quadro abbastanza vicino alla realtà: per i primi minuti si è verificato un miglioramento delle prestazioni quasi irrilevante rispetto alla partenza, seguito invece da un andamento sempre più ripido verso l'alto, fino ad arrivare ad una inclinazione perpendicolare all'asse delle ascisse. A questa fase ne è succeduta una di nuovo orizzontale che si è mantenuta costante per tutto il resto del test. A ben pensarci questo andamento è del tutto logico, in quanto per il primo periodo di attività il profiler è impegnato ad individuare i metodi da ottimizzare, trascurando così il processo stesso di ottimizzazione, ma una volta fatto questo c'è tutta la fase in cui i metodi selezionati vengono compilati e cominciano a funzionare al meglio. Una volta ottimizzato tutto l'ottimizzabile, le prestazioni si stabilizzano verso un valore limite. 
    Il miglioramento globale dall'inizio del processo alla fine è stato notevole; si è passati da un tempo medio di risposta di 250 ms a meno di 100 ms. Non mi arrischio a dare percentuali, anche perché ripeto, il test effettuato non può ritenersi in alcun modo rigoroso ma solo significativo di una tendenza ben evidente.
    Dopo queste prove ho rivalutato la nuova VM ed ho provato ad osservare anche programmi client. In realtà si vedono anche lì gli effetti di HotSpot, anche se in maniera molto meno marcata. Grezzamente, provando ad esempio ad eseguire la stessa operazione più volte durante una sessione del programma, si può apprezzare la differenza nella velocità di esecuzione man mano che l'operazione venga ripetuta.
     
     

    Conclusioni

    Anche per questa volta non abbiamo avuto la nostra panacea, però tutto sommato non possiamo lamentarci più di tanto. Ancora una volta conta spesso molto di più l'accuratezza nello scrivere un programma che il compilatore che ci stà sotto, e comunque probabilmente la strada intrapresa con HotSpot può portare ad ulteriori significativi miglioramenti.
    Il prodotto deve maturare e il limite pare ancora ben lontano dall'essere raggiunto. 

  
 

MokaByte rivista web su Java

MokaByte ricerca nuovi collaboratori
Chi volesse mettersi in contatto con noi può farlo scrivendo a mokainfo@mokabyte.it