Open Source, lasci o ci provi [agg.]

In vita mia non ho mai pubblicato nessun lavoro a codice aperto, e sono stato sempre molto perplesso riguardo all’utilizzare quello degli altri, ma questa volta farò uno strappo alla regola e può darsi che questo sia solo il primo di molti altri strappi a venire.

A differenza di Andrea quello che presento in questa prima puntata è un codice destinato agli sviluppatori, ed in particolar modo a quegli sviluppatori che lavorano a progetti grande complessità come l’analisi dei linguaggi, la scrittura di sistemi operativi e compilatori o l’analisi di grandi quantità di dati e/o flussi di dati ad elevata velocità.

Il modulo in oggetto è un “replacement” della libreria ctype.h dei compilatori C, che è una delle parti più critiche quando si affrontano compiti come quelli descritti sopra; una cattiva scrittura di questa libreria, in fin dei conti semplice, può portare ad interi ordini di grandezza di rallentamento nel software che la utilizza, perchè ad essa è deputato il gravoso compito di catalogare ogni singolo elemento del flusso in esame.

Al tempo stesso questa libreria è spesso fonte di errori, perchè nel tentativo di recuperare fino all’ultimo briciolo di performance capita che vengano trascurati controlli sui dati in ingresso.

Questo articolo ci offrirà anche l’occasione di mettere a confronto quattro dei principali compilatori presenti sul mercato (GCC, Clang, Microsoft ed Intel) ed anche di toglierci un dubbio riguardo alle performance del Subsystem WSL di Windows 10.
Questo confronto metterà in luce ai giovani sviluppatori quanto sia importante la scelta degli strumenti, in questo caso dei compilatori, quando ci si trova a dover risolvere problemi complessi per i quali occorrono grandi capacità di calcolo.

Ma veniamo al codice, che potrete trovare su Github assieme al piccolo programma di test che ho scritto sia per controllare la correttezza dei risultati forniti che per confrontare le performance offerte con quelle ottenute impiegamdo la ctype standard dei compilatori.
Non scenderò nei dettagli, che annoierebbero i più e sui quali magari entrerò dietro richiesta nei commenti, accenno solo al fatto che tutto è basato su macro del preprocessore C e su una matrice che viene impiegata sia per la classificazione dei caratteri che per le conversioni.

Il codice è comunque commentato riga per riga e ben scritto, dunque non vi dovrebbero essere difficoltà nel comprenderne il funzionamento.

Alcune caratteristiche degne di nota:

L’implementazione introduce molte funzioni supplementari rispetto allo standard, quasi tutte implementate con operatori a bit (quindi estremamente veloci); in questo caso le estensioni implementate riguardano in particolar modo lo sviluppo dei compilatori ed interpreti di linguaggio, ma si è liberi di ridefinirle come meglio si crede.

La sctype.h non può mai generare errori nella classificazione dell’input, dunque non serve aggiungere controlli prima della sua chiamata.

L’implementazione su un’unica matrice rende facilissima la sua estensione o anche l’implementazione di differenti alfabeti.

Passiamo adesso al confronto con le altre ctype standard, partendo dal compilatore che è andato peggio di tutti: Clang. Per ogni compilatore viene riportato per primo il run del test in modalità non ottimizzata e a seguire quello con le ottimizzazioni (per massima velocità) abilitate.
Le immagini sono clickabili.

Indubbiamente la mia implementazione di ctype fa a pezzi quella di Clang, ma attenzione perchè i risultati ottenuti nel run ottimizzato (quello che realmente conta) lo caratterizzano come un ottimo compilatore con delle librerie schifose. Almeno per il caso in esame.
Però le librerie fanno parte della dotazione del compilatore e quindi il povero ma blasonato Clang, almeno per questo particolare confronto, è il fanalino di coda.

Passiamo al penultimo della lista: Microsoft Visual Studio (2017 v. 15.7.2).

Che dire… mediocre il compilatore (viene battuto da Clang) e mediocri le librerie; in aggiunta va segnalato che la ctype offerta con Visual Studio non è a prova di errore, dunque a queste prestazioni deludenti va aggiunto l’overhead di controlli a monte della chiamata.
Se non fosse che il suo IDE è spettacolare, in particolar modo nelle funzioni di debugging e per la capacità di incorporare plugin, magari varrebbe la pena di lasciarlo chiuso.

E siamo agli ultimi due, quelli che realmente se la giocano nel campo degli impieghi seri… l’avrà spuntata il costosissimo Intel o il gratuito ed “aperto” GCC?
Voi che dite?

Evvabbè, il compilatore Intel costa quanto una moto di media cilindrata… grazie al cavolo che il povero GCC arriva secondo.
Però del GCC va fatta notare una cosa: pur non ottenendo i risultati strabilianti dell’Intel è l’unico a dimostrarsi in grado di battere la mia versione di ctype. I risultati che ottiene dimostrano che è ottimo sia il compilatore che le sue librerie.
Davvero i miei complimenti!

Nota: i tempi qui vanno letti in millisecondi. L’aspetto grafico, dovuto all’ambiente di esecuzione, non influisce minimamente sulle prestazioni.

E ora largo a Sua Altezza Imperiale, Intel Parallel Studio XE… il top del top in fatto di compilatori, sopra di lui non c’è solo la scrittura diretta in linguaggio macchina.

Qui viaggiamo su un altro pianeta, 0.266 secondi per un miliardo di cicli complessi come quelli fanno sorgere il sospetto che dentro questo compilatore vi sia tecnologia proveniente da un altro pianeta.
Strabiliante!
A voler proprio fare le pulci, la sua ctype non va forte quanto la mia, ma fate finta che io non lo abbia scritto 🙂

Ed ora togliamoci lo sfizio: quanto rallenta l’impiego di WSL rispetto alla normale esecuzione su Win32?
Lo vediamo subito perchè casualmente ho anche un Clion installato lì dentro:

Sorpresi eh?

Bene, l’ho fatta lunga.
Magari al prossimo progetto aggiungerò anche le prove su Android.

Nota: i risultati dei test non si intendono come esaustivi e, per quanto eseguiti con cura, sono da ritenersi validi unicamente per questo specifico impiego.

[Aggiornamento]: ho ripetuto il test sotto Aldroid (Linux su chroot)

Visto che la macchina è sempre la stessa delle altre prove, anche i risultati sono sovrapponibili a quelli dell GCC eseguito su Win 32 e su WSL.
Ora che abbiamo anche questi risultati mi sento di poter dire che GCC rappresenta di gran lunga la migliore scelta quanto a performance ottenute per questa classe di problemi. Lasciando da parte il superbo e costosissimo compilatore Intel, ovviamente.
Quanto all’ambiente di esecuzione credo che tutti dovrebbero considerare la mia scelta: ELF-64, ossia il formato di eseguibile supportato da Linux. Nel prossimo articolo spiegherò la ragione.

Federico