Le chiacchierate di Salvatore: Cristiano Bozza
La prima chiacchierata di questa serie è con il Cristiano Bozza, validissimo ricercatore presso l’Università di Salerno con cui ho avuto il piacere di lavorare a fine anni 90 fino al 2002 circa. Il gruppo di Fisica delle Emulsioni di Salerno, fondato dal Prof. Giorgio Romano con la collaborazione del Prof. Pino Grella (che conoscerete presto), ha il merito di aver fatto una scelta di campo ben precisa e di averla mantenuta per tutti questi anni: l’uso delle tecnologie Microsoft nell’ambito della Fisica Sperimentale. Grazie a loro ho scoperto il Visual Basic, C#, il Visual Studio, i database relazionali, la MSDN, i manuali della Wrox, etc etc. Basta ciò, dunque, per capire che importanza abbia avuto questo gruppo di persone nella mia vita.
***************************************************
S. – Partiamo proprio da zero. Una rapida presentazione e poi le tue origini informatiche che risalgono, immagino, agli anni 80.
K. – Salve! Sono Cristiano Bozza, classe 1972. Attualmente Ricercatore in Fisica presso l’Università degli Studi di Salerno. Le mie origini informatiche risalgono al 1982 con un TI-99/4A della Texas Instruments che si programmava in Microsoft TI-Basic (un dialetto del BASIC implementato dalla Texas Instruments) e successivamente in TI Extended Basic. Come tutti i ragazzini di 9-10 anni di quel periodo, la mia aspirazione era quella di creare videogiochi. Dopo circa 2 anni sono migrato all’ Assembler e come risultato ho eseguito il porting di qualche gioco da bar tra cui Q*Bert che conservo ancora su qualche audio cassetta.
S. Nell’82 eri alle scuole medie?
K. Nel passaggio tra le scuole elementari e quelle medie.
S. Caspita! Ed eri completamente autodidatta?
K. Sì. Fortunatamente i computer di quell’epoca costringevano a programmare. Potevi comprare dei giochi su cartucce ma il prezzo tipico era sulle 100000 lire da comparare alle 700000 del prezzo del computer stesso.
S. Ricordiamo le caratteristiche di questo PC del 1982…
K. Sul TI-99 girava un processore a 16 bit TMS9900 a 3 Mhz con una struttura simile ai Motorola perché aveva i registri software. C’era un banco di registri che altro non erano che mapping su indirizzi di memoria. Non c’era accumulatore ma tutti i calcoli venivano eseguiti sulla memoria. I registri sono solo dei nomi di comodo che tu assegni a un’area di memoria. Non aveva stack per cui i branch venivano realizzati mettendo nel registro 11 l’indirizzo di ritorno della nuova funzione. Poi era possibile cambiare il workspace passando a delle variabili locali cambiando, contestualmente al salto, anche il set dei registri. Nei registri 12 e 13 c’erano i puntatori alle aree di memoria del programma chiamato e in questo modo potevi passare dei parametri. Il processore grafico TMS9918A ha avuto applicazione negli MSX.
Tornando al TI-99, era una macchina analoga al Commodore 64 che però uscì sul mercato solo nell’anno seguente. Un’altra fortuna fu che il TI99 fu ritirato dal mercato per scarsa fortuna commerciale e per la pessima politica della Texas Instruments che pretendeva di avere lo sfruttamento esclusivo di tutto il software sviluppato sotto la sua piattaforma
S. La Texas Instruments poi è completamente sparita dal mercato dei PC/home computers, no?
K. Sì, è rimasta essenzialmente come produttrice di semiconduttori. Diciamo che il TI-99 era una macchina particolarmente difficile da programmare. Mentre il Commodore 64 aveva una mappa di memoria unica che ti consentiva di accedere a tutti i 64K in un colpo solo, sul TI-99 avevi 16K di memoria VDP (e potevi utilizzarne solo 13) e i programmi erano residenti sull’area video! (sembra un’assurdità!) C’erano 8K di ROM che in realtà ospitavano solo il codice che serviva a leggere la GROM. La GROM era la cosiddetta ROM grafica auto-incrementante che conteneva i comandi ad alto livello quali ad esempio “Traccia una Linea” che poi venivano utilizzati dall’interprete BASIC. Tutte le cartucce (“Solid State Software”), invece, erano programmate in Assembler. Il computer aveva di vera e propria RAM solo 300 B. Potevi poi acquistare un’espansione di memoria da 32 KB, divisa in due banchi: uno da 24 e uno da 8! In più avevi la Mini memory, 4K addizionali per la bellezza totale di 36 K in cui dovevi mettere un intero gioco ( e oggi ci metti solo un’icona in quello spazio!).
(N.B.: In rete esiste un emulatore del TI-99. In allegato all’articolo troverete un video contenente una mini-sessione sull’emulatore)
S. Ok, quindi che alla tenera età di 11 anni sei passato all’Assembler. A quei tempi non c’era Internet. Come poteva studiare queste cose il ragazzo medio?
K. Fotocopiava le 400 pagine del manuale del TI-99 (che ancora conservo) e poi cominciava a fare prove su prove. Passavano così le estati, con sessioni lunghe anche 14 ore!
S. Il TI-99 era una macchina solida?
K. Si, era proprio un’altra classe di elettronica. Tra l’altro, funziona ancora a differenza di computer più recenti che si sono bruciati! L’unico problema era la vista dato che lavoravi su un monitor da 11” a 20 cm dalla faccia!
S. Le tue prime opere firmate sono state dunque delle con versioni di giochi.
K. Si. Il primo è stato Q*Bert che venne proprio bene! Poi ho ideato e scritto un gioco di corse d’auto. Il numero massimo di giocatori era 4: due col joystick e due con la tastiera. La partita era configurabile tramite un pezzo di codice in Extended Basic. Si potevano scegliere i colori delle auto e il tipo di gomme da montare! Avevo implementato un modello di usura gomme e quindi era necessario tornare ai box per il cambio. La preparazione e la premiazione erano scritte in Basic mentre tutta la fase di gioco vero e proprio era in Assembler. Per la creazione della pista implementai un algoritmo di riempimento di una figura chiusa senza avere uno stack ma implementandone uno. E’ un problema classico di grafica 2D e la soluzione viene molto bene se hai uno stack; se non ce l’hai devi inventartene uno. In effetti sono sempre stato molto interessato alla grafica e alle alte prestazioni. Poi sono passato allo studio della prospettiva…Devo dire che è stata colpa di Piero Angela! In quel tempo c’era la sigla di Quark con la grafica wire frame. Li è nata la curiosità….
S. Andiamo avanti agli anni dell’Università. Tu sei un ingegnere…
K, Si, ingegnere meccanico. Ricordo che a quei tempi comprai un computer compatibile IBM, con uno dei primi processori 486 DX2 a 50 Mhz.
S. Caspita! Quelli col famoso coprocessore matematico integrato!
K. Si. Computer pagato ben 3 milioni e mezzo di lire!. Ricordo che al negozio, col PC ancora nello scatolo, passò uno che mi chiese: “è il 50 o il 60?” Io risposi: “il 50!” e lui; “Ah, è quello vecchio!”; e io “ma come, è nello scatolo!”
S. Sì, a quei tempi era cosi! Parliamo dell’anno?
K. 1993.
S. Quindi il sistema operativo era un Windows 3.1
K.Si. DOS 5.0 e poi 6.2
S Immagino che per te si siano aperti orizzonti sconfinati! Che compilatori c’erano all’epoca?
K. Il TurboPascal, il Turbo C (avevo apprezzato molto la possibilità di mettere l’Assembler inline). Il divertimento mio e dei miei amici era quello di scrivere chiamate TSR (Terminate and Stay Resident) che restituivano il controllo al DOS come se il programma fosse terminato ma in realtà esso si trovava ancora in memoria. I TSR servivano per creare utilities e virus (ma non ho mai scritto un virus, li odio profondamente: li ritengo immorali). Visto che Internet ancora non c’era, ricordo di aver litigato con un mio amico che si rifiutò di farmi fotocopiare il manuale del processore 386. Il problema è che erano libri che non potevi neanche comprare! Le librerie non sapevano neppure cosa ordinare! Dovevi un po’ arrangiarti…ad esempio per scoprire come si elaborava la grafica in risoluzione 800x600, ho eseguito il debug via linea di comando della sequenza di avviamento di Tristan, un Flipper, seguendo tutte le chiamate ad interrupt. Un reverse engineering che allora era pane quotidiano!
Dopodiché ho cominciato a lavorare sotto Windows 3.1 scontrandomi subito con i problemi ben noti all’epoca: i 16 bit e la mappa della memoria con selettore e segmento. In realtà esiste ancora oggi ma un po’ più sofisticata. Molti non lo sanno più ma i computer IBM compatibili continuano a funzionare quasi allo stesso modo (in realtà i selettori di segmento sono degenerati ampiamente, e il sistema operativo ti nasconde molte cose, occupandosene direttamente).
“Meglio non saperle queste cose! E all’università? Hai seguito corsi di Informatica?”
“Si. L’unico buon corso che abbia frequentato è stato quello di Programmazione tenuto dalla Professoressa Wilma Russo. Una cosa che mi mancava come cultura di programmazione era un approccio organico alle reti logiche e alla programmazione strutturata. Avevo sempre scritto tutto io, inventando a volte l’acqua calda. Avere invece una panoramica sugli algoritmi e sulle problematiche più classiche aiuta moltissimo. Dopo ho cominciato a lavorare col C e il C++.
“Quindi il C++ l’hai scoperto con l’università”
“Sì. Mi ci sono buttato a pesce! Mi piaceva molto la possibilità di utilizzare un linguaggio ad alto livello che però di consentisse di controllare anche il basso livello. Il passaggio al C++ mi è stato utile quando da sono entrato nel gruppo di Salerno di Emulsioni Nucleari (Fisica Subnucleare) fondato dal Prof. Giorgio Romano. Infatti la prima cosa che mi han chiesto è stata scrivere un’interfaccia grafica per una scheda di acquisizione Matrox Pulsar e acquisire immagini da una telecamera ad alta risoluzione. L’idea all’epoca era quello di creare un sistema semi-automatico per la misura di tracce di particelle in emulsioni nucleari. Quindi alla fine, tutta la cultura di grafica e di approccio al basso livello mi è servita immediatamente. In effetti, la routine di blob recognition che scrissi nel 1996, con poche modifiche, è quella che gira ancora oggi sul nostro sistema di acquisizione ed è scritta in Assembler: c’è un pezzo di codice in C con un bell’ASM all’inizio e uno alla fine e in mezzo è tutto Assembler!
 |
Nel frattempo ho scoperto altri linguaggi (SQL, HTML, Shockwave) ma la cosa fondamentale è stata l’introduzione del C#. Io considero il C++ un qualcosa di incompleto perché ha problemi di portabilità. Purtroppo il modello di oggetto del C++ è inconsistente, nel senso che di fatto tutti i compilatori per implementare i metodi di un oggetto usano una serie di funzioni che hanno in molti casi la decorazione del nome del C (con l’underscore davanti). Quindi i compilatori continuano ad essere essenzialmente compilatori C. Inoltre, per via della storia dei puntatori, alla fine si può sempre mettere le mani su un oggetto. Si possono certo usare metodi privati ma alla fine, se uno vuole, ci mette poco a capire come un oggetto è veramente fatto. Poi sanno tutti che la probabilità di produrre bug con puntatori che vanno in giro per la memoria è alta. Si possono utilizzare librerie di smart-pointer: ne ho scritte anche io ma alla fine si tratta sempre di estensione di sintassi. Prima o poi qualcosa ti sfugge, soprattutto in progetti grossi, e soprattutto quando poche persone devono occuparsi di milioni di linee di codice. Invece, ciò che mi ha attratto subito del C# è stata la possibilità di poter produrre codice intrinsecamente molto più bug-free e anche lanciarsi in tecniche che usualmente non ci avventura a seguire in C++. Mi spiego: se uno ha in C++ una struttura di 16-20 byte, 30 byte, è molto probabile che la passi per valore per evitare problemi di allocazione/deallocazione e/o stray pointers. Anche in assenza di bugs, ci sono problemi di frammentazione della memoria; e in C++, a meno di utilizzare librerie di garbage collection esplicite, questi permangono. Invece in C# è altamente probabile che uno utilizzi una classe per cui hai solo una reference, un puntatore a questo oggetto senza la preoccupazione di doverlo ri-allocare. A questo punto una chiamata di funzione costa meno perché una reference costa meno di una struttura da 20-30 bytes, spesso copiata usando una funzione della runtime. Questo rende molte volte il codice di calcolo scritto in C# più veloce di quello equivalente scritto in C++. Certo è chiaro che se uno si mette ad ottimizzare, con il C/C++ si ottengono risultati egregi ma la verità è che con i tempi di sviluppo che ci sono oggi di fatto quasi nessuno ha più il tempo di fare un lavoro così spinto. Mi è capitato molto spesso proprio per questo motivo di avere codice scritto in C# che fosse più veloce dell’equivalente in C++. Ottenere gli stessi risultati in C++ costa tempo di sviluppo. Ovviamente il C# va molto male sui cicli stretti e sugli if: se uno ha un ciclo for stretto e non può usare un iteratore come un foreach, lì ci perde parecchio in termini di prestazioni. Questo perché se uno guarda il disassemblato del codice in C# (cosa che continuo a fare) si rende conto che gli array bound check vengono implementati in una maniera che comunque interrompe spesso la coda di prefetch del processore.
S. Alla fine mettendo tutto sulla bilancia, oggi scegli il C#?”
K. Alla fine, si. Di fatto, uso il C++ solo per pezzi di codice molto specifici dove però compete coll’assembler. Molto spesso c’è una funzione C++ che dentro ha un pezzo in Assembler. Per cui, il C++ è usato solo come un comodo assemblatore. Per il resto, uso il C#. Per quanto mi riguarda, il C++ è un linguaggio in obsolescenza. Anche se debbo ad esso molto della mia carriera di programmatore, però di fatto non ci sono molti vantaggi nell’utilizzarlo. Ad esempio, per la scrittura di interfacce grafiche, se uno mira alla portabilità su altre piattaforme, l’ambiente .NET costituisce il mezzo privilegiato. Lo stesso codice prodotto sotto Windows, senza ricompilazione, gira alla perfezione sotto Linux solo con interfacce grafica leggermente diversa (la forma delle finestre,etc). L’applicazione funziona e si vede bene: questo è un grandissimo vantaggio. Diversamente, o si scrive l’interfaccia grafica due volte, o ci si affida ad emulatori che spesso però danno problemi. Oltretutto, .NET consente di utilizzare un modello di multi-threading unificato, anche cambiando sistema operativo, e questo è un altro vantaggio non di poco conto perché sia chi scrive un’interfaccia grafica, sia chi scrive un’applicazione di acquisizione dati real-time o addirittura di calcolo distribuito ha bisogno di un sistema multi-threading efficiente. Se lo si fa in C++, cambiando sistema operativo, si è costretti a riscrivere tutte le librerie. Questo costa troppo, costa bug e, per quanto mi riguarda, nell’ambiente in cui opero, la portabilità è una richiesta fondamentale. Anche se qui preferiamo lavorare sotto piattaforma Windows, di fatto il codice che noi sviluppiamo è sempre scritto per essere utilizzato sotto altre piattaforme.
Col .NET risparmiamo molto tempo. E poi oggi, col costo dei processori che è molto basso, non è difficile avere macchine con 40 core o più. Con un migliaio di euro in più si riesce a raddoppiare la potenza di calcolo mentre investendo un migliaio di euro in sviluppo (cosa che vuol dire diversi giorni di lavoro) non si raggiunge lo stesso risultato. Per sfruttare le possibilità offerte sia da cluster di calcolo che sono sempre piu facilmente disponibili che in prospettiva il cloud computing è molto più importante riuscire a scrivere codice che giri sotto queste piattaforme piuttosto che fare ottimizzazione spinta come ho fatto io stesso. Parlavamo prima del codice di acquisizione dati. Quel codice è stato scritto col manuale del processore davanti contando i cicli di clock per ogni istruzione. Quando si presentavano alternative, si eseguiva per ognuna di esse il calcolo dei cicli di clock, e alla fine si sceglieva la migliore. Oggi, se vai su un cluster di calcolo, non sai a priori su che macchina gira il tuo codice. Sarà un Intel, un AMD, o altro? Le code di prefetch Sono implementate diversamente. Ho visto sui miei benchmark delle cose anche divertenti. Gli stessi pezzi di codice che perdevano un 50% di tempo in più cambiando tipo di processore perché la logica di ottimizzazione del prefetch era diversa. Quindi una ottimizzazione di codice diventa inutile o non dà grossi vantaggi. E’ molto più importante riuscire ad utilizzare tutta la potenza di calcolo di un cluster.
S. Torniamo un attimo al C++ e ai suoi compilatori. Tu sei partito, se non sbaglio, col Borland.
K. Si. Ad un certo punto ho utilizzato un Borland 3,51..Potrei però confondermi con la numerazione del sistema operativo. Sicuramente era un 3 e qualcosa….Qualcosa come 11 floppy disk di installazione. All’epoca il compilatore Microsoft faceva cose un po’ bizzarre: ricordo qualcosa di strano su un metodo di codifica dei double. Era, se non sbaglio, il VS4, che per fortuna non ho mai usato. Dal 5 in poi ho utilizzato il Visual Studio. Abbandonai Borland perché, di fatto, si dedicarono ad altri linguaggi come il Delphi. Conservo un buon ricordo del compilatore Borland. Era piuttosto bacato ma rispetto alla media degli altri prodotti in giro era spettacolare. Aveva una sua libreria OWL (Object Windows Library) che era antesignana delle MFC Microsoft (in realtà però non sono sicuro che cronologicamente sia andata così) però di fatto la OWL era all’epoca più completa e più facile da usare della MFC. Comunque mi son divertito molto, e scrissi anche una patch. Il compilatore Borland aveva la possibilità di farti sostituire nel Librarian le librerie di run-time, per cui avevo sostituito la fscopy perché mi ero accorto di un bug sotto Windows a 16 bit. Quando avevi un array che eccedeva i 64 K , ti veniva allocata la memoria ma se la scrittura non era allineata ai 64 k, c’era un fenomeno di sovrascrittura per cui l’ultimo pezzo della scrittura veniva messo addosso ai primi byte del segmento che cominciava con lo stesso numero di selettore. Scrissi quindi in Assembler una patch dell’fscopy in maniera tale da curare questo problema.
Sempre sotto questo compilatore, scrissi un programma di grafica per funzioni matematiche che utilizzava un parser simbolico di espressioni matematiche. Questo mi è tornato utile in seguito: si tratta di un codice che ritorna spesso nella mia storia e adesso me lo tengo ben stretto. L’ho tradotto infatti in C# . In tutti i programmi di analisi dati, invece di mettere degli elementi grafici di selezione ( selezione di posizione di una certa coordinata, selezione di angoli, etc. ) offro sempre la possibilità di inserire anche un’espressione matematica in modo da avere criteri di selezione molto più flessibili. La prima realizzazione di questo parser fu in una gara di C++ con un mio amico che ne scrisse uno che batté il mio in velocità. Allora, punto sul vivo, decisi di creare un parser che compilasse a run-time; in pratica inserivi l’espressione matematica nell’interfaccia grafica e lui ti allocava un blocco di memoria al cui interno inseriva del codice in assembly che eseguiva quel calcolo utilizzando il coprocessore matematico. Sulla media dei risultati era solo il 2% più lento del compilato Borland! Diciamo che nella gara giocai sporco ma fu un’esperienza istruttiva.
S. Vorrei tornare un attimo al Visual Studio che tu hai cominciato a utilizzare dalla versione 5 in poi. Una cosa che mi ha sempre allontanato dall’utilizzo del C++ sotto Visual Studio è stato il forte impatto iniziale e la difficoltà di ambientamento alle MFC. Tu che ne pensi?
K: In realtà dipende molto dalla guida online. Ultimamente è molto migliorata, ma in passato dovevi già sapere di che cosa avevi bisogno... c’era poco tutorial.
S. Sai che adesso ci sono le versioni Express gratuite del Visual Studio e sorprendentemente la più scaricata è proprio il C++.
K. Non mi sorprende. Credo che si tratti per lo più di studenti universitari che vogliono apprendere il liinguaggio. Ovviamente uno può provare il gcc o il djgpp che è una variante del gcc ma di fatto chi riesce a fare una manutenzione della libreria di run-time come la Microsoft? Ci sono anche prodotti industriali che però ovviamente non hanno motivo di esistere per un utente che voglia apprendere il linguaggio. Il C++ è ancora molto insegnato e questo crea un effetto traino. Però sono un po’ quelle mode che poi spariscono. Se al CERN 15 anni fa dicevi di usare il C++ ti “crocifiggevano in sala mensa”: era tutto FORTRAN. Lo stesso accade oggi se dici di usare il C#. Magari tra altri 10 anni sarà invece normale.
S. Perché gcc non ti piace?
K. Anzitutto ho trovato molti casi di non uniformità allo standard. Devo anche essere stato sfortunato perché in quel periodo era molto instabile (eravamo attorno alla versione 2.93, o 2.96... ), perché ho trovato bug. Casi in cui non era possibile compilare il codice avendo l’allineamento a 1 byte ma per forza bisognava farlo a 2 byte. Tutto ciò che ti girava con allineamento a 1 byte dovevi ricompilarlo o scriverti altro codice. Il problema sorgeva perché molte volte utilizzavo miei formati di file per cui molte volte mi era comodo fare immagini di memoria direttamente da struttura a file. Invece, col gcc, ho dovuto riscrivere tutta la parte di lettura/scrittura da file che sul Visual C++ era ovvia. Non è neanche un compilatore particolarmente veloce: sia Microsoft che Intel lo battono del 30/40% in termini di velocità. Alla fine comunque è sempre una battaglia di portabilità persa: il C++ non è portabile. Non è questione di compilatore. Puoi con molta fatica attaccare una libreria compilata in gcc a una compilata in Borland ma fai molto prima a ricompilare tutto da capo su un unico compilatore.
S. Ok, direi che per oggi può bastare. Cosa ci vuoi raccontare e /o mostrare la prossima volta.
K. Attualmente ho sviluppato una certa esperienza coi database relazionali, nell’ambito dell’esperimento OPERA. Gestiamo database attualmente nell’ordine dei 10 Tera e puntiamo ai 50 - 100 Tera. Sto lavorando molto con Oracle e con i software di interfaccia al database. Magari lo vedremo nelle prossime interviste. Direi che però possiamo proprio vedere il parser simbolico. Ne ho una versione abbastanza recente in C++ che credo sia debuggata. In realtà se poi guardiamo l’implementazione .NET è molto piu elegante. Non c’è assolutamente paragone. In .NET è possibile aggiungere dinamicamente le funzioni che debbono essere “comprese” mentre in C++ è tutto più statico; e poi con .NET alla peggio puoi sempre inventarti un “delegato”; certo in C++ c’è il puntatore a funzione, ma come la mettiamo con l’allineamento delle strutture e le convenzioni di passaggio dei parametri?
S. Poi mi piacerebbe che ci raccontassi un po alla volta come gestisci i processi di acquisizione dei dati, l’interazione col database e l’analisi dei dati.
K. Va bene!
S. Ok, allora chiudiamo qui. Alla prossima!
K. Ciao!