Newsgroup: it.comp.programmare
Titolo: Ottimizzare il codice

Salve a tutti,
una domanda un po' tecnica: come si ottimizza il codice? o meglio: c'è
qualcosa in giro che mi dica se è più efficiente una sottrazione ed
un'uguaglianza oppure un "maggiore di"?? sto sviluppando un'applicazione che
deve essere il più efficiente possibile (ovviamente nei limiti) e vorrei
sapere se conoscete qualcosa, soprattutto orientato a delphi che già di suo
ottimizza il codice in compilazione.
Grazie a tutti

 un'uguaglianza oppure un "maggiore di"?? 
solitamente non e` necessario preoccuparsi troppo di queste 
micro-ottimizzazioni: e` probabile che il compilatore scelga gia` per 
conto suo il codice piu` efficiente.
ciao Anto
-- 
Antonio Cuni, 19 anni, studente
Brainbench C++ Master: 4.73, higher than 99% of all previous test takers.
C Language: 3.79, higher than 92% of all previous test takers.
Guida C/C++ di Programmazione.it: 
http://cpp.programmazione.it

 solitamente non si ottimizza :-)
Io aggiungerei un "prima si progetta bene il software e si scelgono gli
algoritmi giusti".
E` inutile ottimizzare un algoritmo inefficiente se se ne puo` usare
uno efficiente e non ottimizzato che ci mette meta` del tempo. :)
Bye.

 conto suo il codice piu` efficiente.
beh, non è detto: è per questo che chiedevo se ci fossero dei modi di
approccio a questo argomento

 uno efficiente e non ottimizzato che ci mette meta` del tempo. :)
Perfettamente d'accordo!

Anch'io ho problemi di ottimizzazione del codice in un algoritmo
estremamente ricorsivo.
Non ho ancora capito bene:
Per esempio:
č meglio questo:
if ((a < (dim1-dim2)) && (b < (dim1-dim2)) && (c < (dim1-dim2))) ....;
o questo:
register int dim12 = dim1-dim2;
If ((a < dim12) && (b < dim12) && (c < dim12)) ....;
E poi:
Io cerco di usare sempre le funzioni inline. Qual č lo svantaggio oltre ad
un eseguibile con maggiore occupazione di memoria (che non mi sembra grave)?
E poi, prendiamo questo ciclo:
for(int k=0; k<Arr.GetSize(); k++)
{
    int i;
    ...
}
Il GetSize() viene eseguito ad ogni ciclo del for? Se cosě fosse sarebbe
meglio appoggiarsi ad una variabile dichiarata prima del for
int size = Arr.GetSize();
for(int k=0; k<size; k++)
{
    int i;
    ...
}
L'intero i č megliodichiararlo fuori (prima) del for? (o č uguale?)

 L'intero i è megliodichiararlo fuori (prima) del for? (o è uguale?)
Se lo dichiari prima e` globale alla funzione, se lo dichiari dopo e`
locale al ciclo for e viene persa quando ne esci. Prestazionalmente
dovrebbe essere la stessa cosa.
Bye.

 L'intero i e` megliodichiararlo fuori (prima) del for? (o e` uguale?)
In teoria ad ogni ciclo lo stack pointer dovrebbe essere decrementato di
sizeof(int) e  re-incrementato alla  fine di  ogni ciclo. In  pratica il
gcc,  anche senza  attivare le  ottimizzazioni, tratta  i come  se fosse
stato dichiarato  prima del ciclo  for, senza pasticciare ad  ogni ciclo
con esp.
ciao
Kronos
-- 
Home: 
http://kronoz.cjb.net
Al termine di un pranzo di nozze mi hanno dato un
amaro alle erbe cosi' schifoso che perfino sull'etichetta
c'era un frate che vomitava.

 conto suo il codice piu` efficiente.
Infatti, piu` che probabile.  Comunque, c'e` anche una tecnica alternativa, 
dovuta ad Andrew Koenig, per cercare di misurare queste eventuali 
inefficienze del sistema compilatore/processore.  Koenig, noto soprattutto 
per i suoi grandi contributi al C++ (e in minor misura al C), era 
naturalmente alla recente decima conferenza internazionale di Python (prima 
o poi chi ha abbastanza fiuto e passione per l'informatica a Python ci 
arriva!), e fra le varie cose si chiacchierava anche di questa tecnica e di 
come si potrebbe applicarla al nuovo profiler "hotshot" di Python 2.2.
Alla radice del problema (se problema e`) c'e` anzitutto la grande 
invenzione dell'IBM del 1960, quella di fare una *famiglia* di computer 
tutti compatibili ma con hardware assai diverso.  La prima famiglia fu 
quella IBM/360, al giorno d'oggi e` un concetto quasi scontato.  Come puo` 
un compilatore ottimizzare per TUTTE le CPU della famiglia quando esse 
hanno architetture diverse e quindi rapporti diversi fra le prestazioni di 
diverse istruzioni di macchina?  Non puo`.  Se la differenza si limita a 
puri rapporti costanti, per cui (che so) sul modello A la sequenza
    SUB AX, AX
    JEQ +46
prende tempo 0.9996 rispetto a quella
    TST AX, AX
    JEQ +46
mentre sul modello B la seconda prende 1.00002 rispetto alla prima, un 
compilatore potrebbe in teoria tenere un tabellone con tutti questi 
rapporti e per ogni costrutto da generare scegliere quello piu` adatto per 
un certo modello ovvero un certo mix pesato di modelli.  In realta` le
cose sono molto piu` complesse perche` le cache (dimensioni e 
architetture), la profondita` e granularita` delle pipeline, e cosi` via, 
sono pure tutte diverse, e qui non si tratta di semplici rapporti numerici 
fissi.  In pratica, per famiglie sufficientemente numerose e varie, come 
quella dell'Intel 80386 e dei suoi innumerevoli discendenti ed imitatori, 
gli autori di compilatori ci rinunciano: mettono (al massimo) una mezza 
dozzina di switch per scegliere i modelli per cui stai ottimizzando (piu` 
che altro per sapere se certe specifiche famiglie di istruzioni, come le 
MMX, sono usabili o meno) e li` smettono.
E se tu vuoi ottimizzare per quello SPECIFICO chip, non per "una famiglia", 
perche` quello specifico modello e` sul satellite in orbita ovvero nella 
centrale sottomarina che controlla la commutazione su cavi oceanici, e tu 
devi preparare il codice da spedirgli remotamente?
Naturalmente si tratta di problemi che toccano forse due o trecento 
programmatori sulle decine di milioni che programmano in tutto il mondo,
per cui il tuo "solitamente" e` del tutto corretto.  Nondimeno, anche 
l'insolito e l'assurdo hanno il loro fascino.  Alcuni, come Koenig, 
lavorano in un ambiente di ricerca (un tempo i Bell Labs, oggi il 
laboratorio Shannon della AT&T) e possono almeno qualche volta perseguire 
un problema di nessuna rilevanza pratica per il suo puro fascino 
intellettuale (il management di questi laboratori permette queste 
escursioni sostanzialmente perche`, su 1000 ricerche apparentemente 
inutili, una o due scoprono inaspettatemente qualcosa di grosso e ripagano 
ampiamente anche per tutte le altre).  La tecnica di Koenig non e` 
esattamente fra queste, comunque...
Problema: ho un chip che marcia a 1.4 GHz o giu` di li`.  Vorrei misurare 
le microscopiche differenze fra due costrutti di macchina come sopra, ma 
non ho un clock cosi` accurato: ben che mi vada, il clock (stabilizzato via 
radio da orologio atomico) misura il decimo o (e siamo gia` sul 
costosissimo anche per un laboratorio AT&T) il centesimo di microsecondo.
Visto che la differenza che voglio misurare sara` nell'ordine del 
nanosecondo (sto naturalmente presumendo per assurdo che un nanosecondo in 
piu` o in meno "IMPORTI" a qualcuno), come faccio...?
L'idea di Koenig (i dettagli sono stati pubblicati a suo tempo su di un
qualche journal dell'AT&T prima del breakup, credo il System Journal dei 
laboratori Bell) in pseudo-codice macchina:
    load AX, CLOCK
    load BX, 0
WAIT:
    load ZX, CLOCK
    cmp AX, ZX
    jeq WAIT
# inizia la sequenza da misurare
    ...
# finisce la sequenza da misurare
    load CX, CLOCK
COUNT: 
    add BX, 1
    load ZX, CLOCK
    cmp CX, ZX
    jeq COUNT
Il concetto e` che: la sequenza da misurare inizia "appena possibile"
dopo che il clock ha tickato da un valore al successivo; e viene
seguita da una "coda" che dura sino al *prossimo* tick del clock
e la cui durata e` contata nel registro BX.  La durata della
sequenza stessa e` dunque CX-AX tick del clock meno BX volte la
durata della sequenza di 4 istruzioni che inizia dopo la label
COUNT.  Posso calibrare questa misurazione ponendo come "sequenza
da misurare" il nulla, poi una singola istruzione NOP, due di
esse, ecc (anche per provare l'eventuale effetto degli allineamenti
in linee di cache, che spesso domina effetti quasi irrilevanti come
la differenza fra un SUB e un TST!).  Quanto piu` veloce la macchina
e quanto piu` lento il clock (purche` senza drift!), tanto meglio
questa tecnica di misura calibrata puo` migliorare le mie possibilita`
di misura accurata.  Naturalmente eseguiro` molteplici misure e le
trattero` con tutta l'abituale baraccata di tecniche statistiche,
ma l'accuratezza della misura puo` comunque migliorare di ordini
di grandezza (ad esempio nel caso limite in cui il "clock" ticka una
volta al secondo, con pure tecniche statistiche non riesco a
misurare meglio di circa 1/10 di secondo, con questo metodo posso
arrivare a 1/1000 -- ovviamente a macchina dedicata, nessun sistema
operativo che rompa, e altre evidenti necessita` per chi abbia
bisogno di misurazioni di questo tipo!).
Non particolarmente importante per la programmazione, ma di un
certo interesse puramente astratto/filosofico...:-).
Alex