PDA

View Full Version : [C] calcolare il tempo di esecuzione di un programma


Lelex82
04-06-2008, 13:39
come da titolo.
correggetemi se sbaglio: includo la libreria time.h poi

int main(int argc,char **argv)
{clock_t t1,t2;
t1=clock();
{
corpo del programma

t2=clock();
printf("\ntempo di esecuzione=%.10f sec\n",(t2-t1)/(double)CLOCKS_PER_SEC);
return (0);
}

il problema è che il tempo visualizzato non è realmente quello trascorso. sbaglio qualcosa nella formula del printf?

ramarromarrone
04-06-2008, 19:43
per misurare il tempo di esecuzione :


#include <time.h>
.....
int main() {
time_t m;
time_t now = time(NULL);
.....
.....
m = difftime(time(NULL), now);
printf("tempo totale in secondi: %ld\n",m);
return 0;
}

tæo
04-06-2008, 20:47
se hai bisogno di conoscere il tempo di esecuzione del tuo programma per scopi che esulano dal programma stesso potresti usare il comando time del terminale

$ time ./a.out
...
/* output del tuo programma */

real 0m0.041s
user 0m0.002s
sys 0m0.013s

Lelex82
05-06-2008, 11:18
grazie ragazzi,vanno bene entrambe i modi!
@ramarromarrone: qual è la sintassi nel printf per visualizzare anche i centesimi di secondo?

ramarromarrone
05-06-2008, 11:41
grazie ragazzi,vanno bene entrambe i modi!
@ramarromarrone: qual è la sintassi nel printf per visualizzare anche i centesimi di secondo?

così su due piedi non lo so...dovrei cercare..

ora non ho tempo appena riesco cerco e ti faccio sapere

mjordan
05-06-2008, 19:58
In realtà misurare il tempo di esecuzione di un programma è un task assai piu' complesso che usare due semplici funzioni per le date. Usare la funzione time() a questo scopo è sbagliato e fuorviante. Essa infatti è una funzione per le date, non da piu' precisione del secondo come unità temporale. E nel misurare il tempo di esecuzione una precisione nell'ordine del secondo è inutile.

E' invece corretto utilizzare la funzione clock() come descritto nel problema originale, che ritorna il tick count dall'ultima chiamata. Non ci sono funzioni nello standard che possano ritornare valori con precisione dell'ordine del ms o del us, ma si può usare un'espediente: si contano quanti tick count ci sono in un secondo (e questo è definito dalla costante CLK_PER_SEC) e si calcola propriamente usando variabili double il tempo esatto sapendo a che valore corrisponde un tick di CPU ... ;)

Quindi le funzioni corrette per assolvere allo scopo non sono la funzione time(), la struttura time_t e la costante CLOCKS_PER_SEC (la cui utilità dovrebbe essere relegata alle date) ma bensi la funzione clock(), la struttura clock_t e la costante CLK_PER_SEC (che invece sono piu' utili per le misurazioni), con un'opportuna routine per convertire i tick in unità temporali relative al secondo.

Questo se vogliamo fare le cose fatte bene, altrimenti per l'esercizietto per rispondere alla domanda da compito in classe ci possiamo pure accontentare.

mjordan
05-06-2008, 20:07
grazie ragazzi,vanno bene entrambe i modi!
@ramarromarrone: qual è la sintassi nel printf per visualizzare anche i centesimi di secondo?

I centesimi di secondo vanno calcolati, non ci sono parametri printf() che restituiscano centesimi da funzioni che restituiscono secondi... :D
Non sei mica sotto Java, li hai il metodo statico currentTimeMillis() della classe System. :D

Albi89
05-06-2008, 20:30
In realtà misurare il tempo di esecuzione di un programma è un task assai piu' complesso che usare due semplici funzioni per le date. Usare la funzione time() a questo scopo è sbagliato e fuorviante. Essa infatti è una funzione per le date, non da piu' precisione del secondo come unità temporale. E nel misurare il tempo di esecuzione una precisione nell'ordine del secondo è inutile.

E' invece corretto utilizzare la funzione clock() come descritto nel problema originale, che ritorna il tick count dall'ultima chiamata. Non ci sono funzioni nello standard che possano ritornare valori con precisione dell'ordine del ms o del us, ma si può usare un'espediente: si contano quanti tick count ci sono in un secondo (e questo è definito dalla costante CLK_PER_SEC) e si calcola propriamente usando variabili double il tempo esatto sapendo a che valore corrisponde un tick di CPU ... ;)

Quindi le funzioni corrette per assolvere allo scopo non sono la funzione time(), la struttura time_t e la costante CLOCKS_PER_SEC (la cui utilità dovrebbe essere relegata alle date) ma bensi la funzione clock(), la struttura clock_t e la costante CLK_PER_SEC (che invece sono piu' utili per le misurazioni), con un'opportuna routine per convertire i tick in unità temporali relative al secondo.

Questo se vogliamo fare le cose fatte bene, altrimenti per l'esercizietto per rispondere alla domanda da compito in classe ci possiamo pure accontentare.

Sono in linea con te... uso la stessa tecnica per alcuni programmi di esempio in cui evidenzio le differenze in tempi di esecuzione tra algoritmi ricorsivi e iterativi.
Anyway, CLK_PER_SEC col mio compilatore non funziona, su internet ho trovato che dovrebbe essere equivalente a CLOCKS_PER_SEC, e alcune implementazioni della libreria usano un nome o l'altro.
Confermate? :fagiano:

mjordan
05-06-2008, 20:41
Sono in linea con te... uso la stessa tecnica per alcuni programmi di esempio in cui evidenzio le differenze in tempi di esecuzione tra algoritmi ricorsivi e iterativi.
Anyway, CLK_PER_SEC col mio compilatore non funziona, su internet ho trovato che dovrebbe essere equivalente a CLOCKS_PER_SEC, e alcune implementazioni della libreria usano un nome o l'altro.
Confermate? :fagiano:

No, quella equivalente (e obsoleta) è CLK_TCK che tra l'altro è una macro, non una costante. CLK_PER_SEC è proprio la costante usata da clock() ed è definita in time.h
Che compilatore usi?

Albi89
06-06-2008, 00:18
No, quella equivalente (e obsoleta) è CLK_TCK che tra l'altro è una macro, non una costante. CLK_PER_SEC è proprio la costante usata da clock() ed è definita in time.h
Che compilatore usi?

Uso gcc 4.2.3, ma anche con mingw 3.4.5 che ho sotto windows ho lo stesso comportamento: CLK_PER_SEC non viene riconosciuta.

Su cplusplus (http://www.cplusplus.com/reference/clibrary/ctime/) non si parla proprio di CLK_PER_SEC, mentre su Wikipedia (http://en.wikipedia.org/wiki/Time.h#Constants) la questione è descritta come ti avevo detto prima (CLOCKS_PER_SEC e CLK_PER_SEC nomi alternativi).

sottovento
06-06-2008, 02:24
In realtà misurare il tempo di esecuzione di un programma è un task assai piu' complesso che usare due semplici funzioni per le date. Usare la funzione time() a questo scopo è sbagliato e fuorviante. Essa infatti è una funzione per le date, non da piu' precisione del secondo come unità temporale. E nel misurare il tempo di esecuzione una precisione nell'ordine del secondo è inutile.
No, dai. Non e' sbagliato ne' fuorviante.
Dipende dal problema che stai affrontando, e da cosa stai usando per risolverlo.
La time() ti puo' dare la precisione che vuoi, ovviamente rispetto al problema.
Se per esempio voglio sapere quanti microsecondi mi servono per eseguire una funzione, posso chiamarla un miliardo di volte ed avro' la precisione dei nanosecondi. Ammesso, ovviamente, che possa chiamarla un miliardo di volte.

Comunque anche questa potrebbe non essere una misura valida. Cosa ne diresti, per esempio, se il sistema operativo sul quale esegui detta misura e' un "run-to-completion", basato essenzialmente su priorita' di tipo statico?



E' invece corretto utilizzare la funzione clock() come descritto nel problema originale, che ritorna il tick count dall'ultima chiamata. Non ci sono funzioni nello standard che possano ritornare valori con precisione dell'ordine del ms o del us, ma si può usare un'espediente: si contano quanti tick count ci sono in un secondo (e questo è definito dalla costante CLK_PER_SEC) e si calcola propriamente usando variabili double il tempo esatto sapendo a che valore corrisponde un tick di CPU ... ;)

Non cambia il problema. Hai qualche decimo di secondo di precisione in piu', anche meno su certi sistemi operativi. In compenso devi fare un bel po' di lavoro in piu' - non portabile ed a grosso rischio di errori.
Insomma, rischi di perderci un pomeriggio per poi accorgerti di non avere dati significativamente piu' precisi.



Quindi le funzioni corrette per assolvere allo scopo non sono la funzione time(), la struttura time_t e la costante CLOCKS_PER_SEC (la cui utilità dovrebbe essere relegata alle date) ma bensi la funzione clock(), la struttura clock_t e la costante CLK_PER_SEC (che invece sono piu' utili per le misurazioni), con un'opportuna routine per convertire i tick in unità temporali relative al secondo.

Questo se vogliamo fare le cose fatte bene, altrimenti per l'esercizietto per rispondere alla domanda da compito in classe ci possiamo pure accontentare.
Come dicevo, ci si puo' accontentare anche della time(), anche per problemi che vanno ben oltre il compito in classe (e anche la tesina).

Piuttosto, sembra opportuno riflettere sulla misura che si va a prendere, e sulla sua significativita'. Cosa stiamo misurando, esattamente? A quali perturbazioni e' soggetta, questa misura?

Ovviamente non so il problema per cui non posso rispondere. Comunque sembra ragionevole, specialmente su sistemi time-sharing, utilizzare primitive messe a disposizione dal sistema. E' pacifico che le misure prese in questo modo, su detti sistemi, dipenderanno da tante cose, fra cui anche il carico della macchina.

In questo senso, la risposta piu' precisa e' sicuramente quella data da tæo: utilizzare il comando time da shell, su UNIX, e' la soluzione migliore nella maggior parte dei casi.

Lelex82
06-06-2008, 10:01
devo fare il confronto tra due strutture dati, cioè eseguire lo stesso test sulla stessa macchina, con SO Linux, e analizzare i risultati temporali.
cmq grazie ragazzi

mjordan
06-06-2008, 21:26
Uso gcc 4.2.3, ma anche con mingw 3.4.5 che ho sotto windows ho lo stesso comportamento: CLK_PER_SEC non viene riconosciuta.

Su cplusplus (http://www.cplusplus.com/reference/clibrary/ctime/) non si parla proprio di CLK_PER_SEC, mentre su Wikipedia (http://en.wikipedia.org/wiki/Time.h#Constants) la questione è descritta come ti avevo detto prima (CLOCKS_PER_SEC e CLK_PER_SEC nomi alternativi).

Interessante. Mi fai sapere invece se hai definita la costante CLOCK_PROCESS_CPUTIME_ID? :D

mjordan
06-06-2008, 21:38
Comunque anche questa potrebbe non essere una misura valida. Cosa ne diresti, per esempio, se il sistema operativo sul quale esegui detta misura e' un "run-to-completion", basato essenzialmente su priorita' di tipo statico?


Penso che non ha senso parlarne, perchè stiamo misurando codice applicativo e non di sistema che confronta tempi di esecuzione su strutture dati. Avere quindi un punto di riferimento per le misurazioni (il numero di tick trascorso in un secondo) è piu' che sufficiente per lo scopo. In genere misurare algoritmi differenti sullo stesso SO e sulla stessa istanza del medesimo SO è piu' che sufficiente e ci consente di trascurare questi dettagli. Dettagli che alla fin fine è alquanto lecito trascurare (considerando che stiamo parlando non piu' che di strutture dati ed algoritmi su di esse).


Non cambia il problema. Hai qualche decimo di secondo di precisione in piu', anche meno su certi sistemi operativi. In compenso devi fare un bel po' di lavoro in piu' - non portabile ed a grosso rischio di errori.
Insomma, rischi di perderci un pomeriggio per poi accorgerti di non avere dati significativamente piu' precisi.


No, hai proprio dei dati precisi. I decimi di secondo sono determinanti per valutare la vittoria di una gara automobilistica, figurati se non servono per misurare algoritmi. Il metodo che ho descritto va oltre i decimi di secondo: stiamo parlando di precisione al millisecondo. Avere dei tempi di accesso piu' veloci di "qualche decimo di secondo" su algoritmi che hanno tempi magari super polinomiali fa una bella differenza. I profiler tengono traccia anche dei ms, figuriamoci se i decimi non sono rilevanti.
Per intenderci, se una ricerca su una lista da 100 elementi impiega 1s, allora una ricerca su una lista da 10.000.000 di elementi impiega 100000 di secondi. E questo perchè la ricerca su una lista è lineare in tempo. Cosa succederebbe se invece consideriamo algoritmi super polinomiali? Che i tempi di esecuzione si propagano in modo esponenziale. In queste circostanza capisci che il decimo di secondo di differenza non solo non è irrilevante come dici ma addirittura una misura ancora troppo grande per essere precisa. La differenza fra una buona funzione hash ed una pessima funzione hash ha differenze di parecchi millisecondi, tempi ancora di molto inferiori al decimo di secondo che invece vuoi trascurare. Fra le altre cose, non ci vuole un pomeriggio nel dividere il numero di tick trascorsi per 60 e normalizzare il tutto nell'ordine dei ms.


Piuttosto, sembra opportuno riflettere sulla misura che si va a prendere, e sulla sua significativita'. Cosa stiamo misurando, esattamente? A quali perturbazioni e' soggetta, questa misura?


E' soggetta a tutte quelle casistiche non prevedibili dall'utente, non controllabili dall'utente in fase di runtime, come segnali, eventuali fenomeni di starvation o di deadlock del sistema operativo, preemption del processo da parte dello scheduler dovuto ad un'evento inaspettato di sistema, caricamento del loader della tabella dei simboli, eventuale presenza di simboli di debug extra non eliminabili nel binario, scarsa ottimizzazione in alcuni casi da parte del compilatore e chi piu' ne ha piu' ne metta. Chiaramente una misurazione che sia attendibile prende in considerazione un certo numero di esecuzioni e ne calcola una varianza statistica. Ancora non preciso, ma non stiamo lavorando con orologi atomici, in fondo. Questi eventi fanno parte del ciclo di esecuzione, del resto. Ecco perchè calcolare una varianza aiuta nella precisione ma non ci suicidiamo se comunque ci sono queste "interferenze".



In questo senso, la risposta piu' precisa e' sicuramente quella data da tæo: utilizzare il comando time da shell, su UNIX, e' la soluzione migliore nella maggior parte dei casi.

Non nell'ambito della complessità computazionale. In questo modo usiamo sempre un processo in piu' che si aggiudica a intervalli pre-stabiliti qualche ciclo di cpu-burst. Misurare algoritmi è un processo delicato, ecco perchè in genere è meglio affidarsi a dei profiler, che cercano di "creare" le condizioni di esecuzione ottimali per un determinato programma. Generano "rumore" che comunque sono in grado di auto trascurare. Ma qui siamo in ambito di un'esercizio. Se devo usare un comando shell per misurare algoritmi allora preferisco usare Valgrind, quanto meno sto utilizzando uno strumento decisamente sofisticato. :)

sottovento
07-06-2008, 01:38
Penso che non ha senso parlarne, perchè stiamo misurando codice applicativo e non di sistema che confronta tempi di esecuzione su strutture dati.

Per questo ho fatto l'esempio di un sistema run-to-completion.
In generale, quando fai una misura di questo genere, misuri anche il carico della macchina. Se esegui un solo processo, avrai una certa misura. Se girano 1000 processi in piu' probabilmente le prestazioni degradano.
Ovviamente non in un sistema run-to-completion, appunto: in tal caso, indipendentemente da quanti processi il tuo sistema sta facendo girare, il tuo programma girera' sempre alla stessa velocita'. Negli altri casi, no.



No, hai proprio dei dati precisi. I decimi di secondo sono determinanti per valutare la vittoria di una gara automobilistica, figurati se non servono per misurare algoritmi. Il metodo che ho descritto va oltre i decimi di secondo: stiamo parlando di precisione al millisecondo.

A dirla tutta non ho mai visto tick di sistema cosi' precisi. Un conto e' quanto dichiarato. Cmq ribadisco: dipende sempre dal problema.


Avere dei tempi di accesso piu' veloci di "qualche decimo di secondo" su algoritmi che hanno tempi magari super polinomiali fa una bella differenza. I profiler tengono traccia anche dei ms, figuriamoci se i decimi non sono rilevanti.

Accedendo a risorse di sistema. Se sei su una macchina, per esempio, time sharing, non hai alternative. Solo il sistema sa esattamente quanto tempo stai impiegando.


Per intenderci, se una ricerca su una lista da 100 elementi impiega 1s, allora una ricerca su una lista da 10.000.000 di elementi impiega 100000 di secondi. E questo perchè la ricerca su una lista è lineare in tempo. Cosa succederebbe se invece consideriamo algoritmi super polinomiali?

Nulla, poiche' ripeterai l'algoritmo "super polinomiale". Ripetendolo, il tempo sara' proporzionale al numero di ripetizioni, indipendentemente dall'algoritmo, no?


Che i tempi di esecuzione si propagano in modo esponenziale.

Ho un algoritmo di qualsiasi complessita'. Lo ripeto 10 volte, mi aspetto che il tempo sia 10 volte maggiore. Questo indipendentemente dalla complessita'.



E' soggetta a tutte quelle casistiche non prevedibili dall'utente, non controllabili dall'utente in fase di runtime, come segnali,

Beh, dipende dalla macchina.


eventuali fenomeni di starvation

starvation = aumento del carico. Torniamo al punto di prima


o di deadlock del sistema operativo,

deadlock = diminuzione del carico. Torniamo al punto di prima


preemption del processo da parte dello scheduler

Dipende dalla macchina, ovviamente. Torna l'esempio del run-to-completion


Misurare algoritmi è un processo delicato, ecco perchè in genere è meglio affidarsi a dei profiler, che cercano di "creare" le condizioni di esecuzione ottimali per un determinato programma. Generano "rumore" che comunque sono in grado di auto trascurare. Ma qui siamo in ambito di un'esercizio. Se devo usare un comando shell per misurare algoritmi allora preferisco usare Valgrind, quanto meno sto utilizzando uno strumento decisamente sofisticato. :)
D'accordissimo. L'unica cosa che mi permettevo di far osservare, nel post precedente, era che usare la time() non era certamente inutile e fuorviante.
Anzi, puo' dare risultati precisi quanto la clock() e con un po' di accortezza, anche migliori. Basta guardare il problema ed agire di conseguenza

mjordan
07-06-2008, 02:57
Per questo ho fatto l'esempio di un sistema run-to-completion.
In generale, quando fai una misura di questo genere, misuri anche il carico della macchina. Se esegui un solo processo, avrai una certa misura. Se girano 1000 processi in piu' probabilmente le prestazioni degradano.
Ovviamente non in un sistema run-to-completion, appunto: in tal caso, indipendentemente da quanti processi il tuo sistema sta facendo girare, il tuo programma girera' sempre alla stessa velocita'. Negli altri casi, no.


Io non so se hai mai studiato ingegneria del software, ma a quanto sembra pare di no: la metrica di McCabe considera esclusivamente la complessità relativa allo "sforzo" complessivo a completare un task. Punto. Tutto il resto è inventato da te per creare enigmi su un'argomento che invece è ben definito. Quella roba serve per prendere 18 ad un'esame di sistemi operativi, non per misurare i tempi di esecuzione su un'algoritmo. Nessuno si interroga su queste cose per misurare i tempi di un'algoritmo. Semplicemente non serve. Un'algoritmo gira sotto un sistema operativo e il sistema operativo va preso come assunto. Semplice e chiaro. Tu praticamente stai dicendo che per misurare la velocità delle automobili bisogna farlo in assenza di attrito di aria, gomme e forza di gravità... :asd:


A dirla tutta non ho mai visto tick di sistema cosi' precisi. Un conto e' quanto dichiarato. Cmq ribadisco: dipende sempre dal problema.


Qui allora mi dimostri che non capisci nemmeno di cosa stiamo parlando :rolleyes: Cosa vuol dire "tick di sistema cosi precisi" quando il clock tick è l'unità temporale piu' piccola esprimibile in un sistema hardware? :rolleyes:


Accedendo a risorse di sistema. Se sei su una macchina, per esempio, time sharing, non hai alternative. Solo il sistema sa esattamente quanto tempo stai impiegando.


E non lo sa forse grazie ai tick "che non hai mai visto essere cosi precisi"? :rolleyes:
Ma cosa diavolo c'entra tutto ciò con la misurazione di un'algoritmo? Tutto ciò di cui ti devi preoccupare è tirare fuori i dannati ms di esecuzione. Tutto il resto è indipendente da quello che puoi fare, lo capisci o no?


Nulla, poiche' ripeterai l'algoritmo "super polinomiale". Ripetendolo, il tempo sara' proporzionale al numero di ripetizioni, indipendentemente dall'algoritmo, no?


Forse non ci siamo capiti. Se tu ripeti sempre lo stesso programma, bene o male ottieni sempre gli stessi risultati. Non è questo lo scopo di misurare i tempi di un'algoritmo. I tempi di un'algoritmo si misurano perchè se tolgo 2ms da una routine critica in un renderer, un rendering impegnativo ci mette 4 ore di meno. Se tolgo 3 ms da una routine di commit di un database, quando applico quella routine su un database da 8 petabyte ci metto 40 secondi di meno a fare commit. Se tolgo 1 ms di meno da una routine che applica un post processing per ogni fotogramma di un videogioco, il videogioco mi va a 40fps anziche a 8 fps.
:muro: E questo significa che "qualche decimo di secondo" è trascurabile come hai detto? :muro:
Scusami tanto, gli algoritmi di seek degli hard disk lottano all'ultimo millisecondo per migliorare i tempi di accesso e anche un singolo millisecondo di differenza dà prestazioni evidenziabili durante il funzionamento di un hard disk e tu mi dici che qualche decimo di secondo è trascurabile? :muro:
Non c'è cognizione di causa.


Ho un algoritmo di qualsiasi complessita'. Lo ripeto 10 volte, mi aspetto che il tempo sia 10 volte maggiore. Questo indipendentemente dalla complessita'.


Io non ho mai parlato di ripetere "10 volte", quello non è misurare un'algoritmo, quello non significa niente. Io parlo di ripetere l'algoritmo su input piu grandi e variegati. E questo di certo non è indipendente dalla complessità.
Se la complessità è O(log(n)), ripetere l'argoritmo su un input 10 volte maggiore da un tempo dieci volte maggiore? :rolleyes:
Indipendentemente dalla complessità? :rolleyes:
Se la complessità è O(n* k^n), ripetere l'algoritmo su input dieci volte maggiore ci da un tempo di esecuzione 10 volte maggiore?
A questo serve misurare gli algoritmi, mica ad altro. Eppure mi sembra un concetto talmente banale anche per chi abbia imparato ad usare solo un ciclo for() ...


D'accordissimo. L'unica cosa che mi permettevo di far osservare, nel post precedente, era che usare la time() non era certamente inutile e fuorviante.
Anzi, puo' dare risultati precisi quanto la clock() e con un po' di accortezza, anche migliori. Basta guardare il problema ed agire di conseguenza

Perchè non mi dici come? Sono curioso di capire come tiri fuori millisecondi con la time().

Lelex82
25-06-2008, 23:04
I centesimi di secondo vanno calcolati, non ci sono parametri printf() che restituiscano centesimi da funzioni che restituiscono secondi... :D


potete dirmi come? l'accuratezza in secondi non m è utile...

mjordan
26-06-2008, 02:03
potete dirmi come? l'accuratezza in secondi non m è utile...

Nella pratica ti conviene andare con il millisecondo. Il millisecondo (ovviamente) corrisponde a 0.001s.
Di conseguenza avrai questa situazione:

#include <stdio.h>
#include <time.h>

int main(int argc, char ** argv)
{
clock_t t_start, t_end;
double t_passed;

t_start = clock();
/* Qui inserisci la computazione da misurare. */
t_end = clock();

t_passed = ((double)(t_end - t_start)) / CLOCKS_PER_SEC;
printf("Elapsed time: %f seconds.\n", t_passed);

return 0;
}


Nota che qui il tempo è espresso comunque in secondi, ma il valore è talmente piccolo (numero di cpu ticks) che è comunque un floating point molto piccolo (0.000x s). Se vuoi esprimere il valore comunque in ms, puoi usare uno stratagemma algoritmico per convertirlo: moltiplichi in un ciclo questo numero per 10, controllando ogni volta che sia minore di 1. Se è minore di 1, moltiplichi di nuovo per 10 e cosi via, tenendo conto in una variabile di quante iterazioni hai fatto. Quando il numero è maggiore o uguale di 1, stoppi l'iterazione del ciclo. Il numero di iterazioni che hai fatto, supponiamo 4, corrisponde al secondo. Le n - 1 iterazioni successive corrispondono a unità di misura piu' piccole e conseguenti, quindi 3 sarà il decimo, 2 sarà il centesimo e cosi via...

Nota che tutte le cazzate che si dicevano prima, non sono valide perchè clock() non tiene conto di eventuale tempo perso nell'I/O o da altri fattori esterni all'algoritmo.
Potresti avere una situazione del genere:

void convert_time(const double time)
{
int iterations = 0;
double mul = time;

while (mul <= 0) {
mul =* 10;
iterations++;
}

/* Considerando come secondi il numero di iterazioni, esprimere in ms significa calcolare il tempo a meno di 4 iterazioni */
for (int i = 0; i <= 3; i++)
mul =/ 10;

printf("Elapsed time: %f ms.\n");
}


Sicuramente ci sono degli errori, non ho compilato nè provato, ho scritto di getto il codice, ma per darti un'idea dell'algoritmo di conversione dovrebbe essere comunque utile.

Lelex82
26-06-2008, 11:52
il fatto che stia sotto linux e non sotto windows può influire? xkè nn riesco a prendere questi maledetti tempi di esecuzione!
EDIT: sto provando a usare la gettimeofday può servire?

mjordan
26-06-2008, 12:22
il fatto che stia sotto linux e non sotto windows può influire? xkè nn riesco a prendere questi maledetti tempi di esecuzione!

No. Ma qual è il problema?

Lelex82
26-06-2008, 12:24
la soluzione che mi hai illustrato non m ritorna i valori desiderati, anzi mi da tutti zeri.

Lelex82
26-06-2008, 12:26
la soluzione che mi hai illustrato non ritorna i valori desiderati, anzi mi da tutti zeri.

recoil
26-06-2008, 12:28
E' invece corretto utilizzare la funzione clock() come descritto nel problema originale, che ritorna il tick count dall'ultima chiamata. Non ci sono funzioni nello standard che possano ritornare valori con precisione dell'ordine del ms o del us, ma si può usare un'espediente: si contano quanti tick count ci sono in un secondo (e questo è definito dalla costante CLK_PER_SEC) e si calcola propriamente usando variabili double il tempo esatto sapendo a che valore corrisponde un tick di CPU ... ;)

tra l'altro clock ti da il tempo di processo, che è una cosa diversa
se misuri il tempo di sistema sei influenzato dagli altri processi del sistema che potrebbero rallentarti

sono due misurazioni diverse, a seconda dello scopo può andare bene clock oppure una funzione che ti dia la data (con la precisione che vuoi) :)

Lelex82
26-06-2008, 16:04
nn capisco perchè gettime mi da un valore in ms mentre clock mi da sempre 0

gettimeofday(&now, NULL);
t1=clock();

node= TREE_SEARCH (root, ctrl_head_ptr->flow_id); //funzione da misurare
t2=clock();

gettimeofday(&after, NULL);
printf("gettime %d\n",after.tv_usec-now.tv_usec);

//t_pass=((double)(t2-t1)) / CLOCKS_PER_SEC;
printf("Elapsed time: %f seconds.\n", ((t2-t1)) /(double) CLOCKS_PER_SEC);


dove t1 e t2 sono clock_t
e now e after sono struct timeval

mjordan
26-06-2008, 16:48
Il problema potrebbe essere nei cast, io adesso non posso provare perchè sono sotto Windows e non ho niente installato per provare. Con GDB però puoi provare a vedere quanto vale la differenza che calcoli di start e end mettendo un breakpoint prima della printf() e stampando i valori, compilando con i simboli di debug attivi:


gcc -Wall -ggdb -o programma programma.c



gdb --readnow programma


Una volta dentro GDB, stoppi l'esecuzione nella main:


break main


e lanci il programma con il comando:

run


Una volta raggiunta la main() il programma si stoppa e puoi eseguirlo riga per riga con il comando:

n


Una volta eseguita la differenza, stampi il valore finale con il comando:

p nome_var


In questo modo dovresti essere in grado di dire se il problema sta proprio in clock() (dubito) o nei cast utilizzati.
Con la GNU C Library, una variabile di tipo clock_t equivale ad un "long int" mentre CLOCKS_PER_SEC è un int.

Lelex82
27-06-2008, 11:17
quello che sto cercando di implementare è un progetto costituito da 3 moduli ognuno dei quali parte in una shell diversa e ad ogni avvio questi tre moduli si mandano un segnale di handshaking.
se seguo la tua procedura non riesco a far partire il progetto.

di seguito riporto un pezzo dell'output a video dei tempi prelevati con clock e con gettimeofday

now= 657998
t1= 0.2000000000
t2= 0.2000000000
after= 658006
gettime 8
now= 658016
t1= 0.2000000000
t2= 0.2000000000
after= 658024
gettime 8

project terminated
gettime è la differenza tra after e now.
Praticamente i valori catturati da clock, t1 e t2 sono identici...???

DanieleC88
27-06-2008, 19:09
Guarda, io ho appena provato con questo codice:
double difference;
clock_t t1;
clock_t t2;

t1 = clock();
for (int x = 0; x < 100; ++x)
{
/* codice */
}
t2 = clock();

difference = (double)(t2 - t1);
printf("Elapsed time: %f.\n", (difference / (double)CLOCKS_PER_SEC));

E ottengo in output:
Elapsed time: 0.030000.

:boh:

Lelex82
27-06-2008, 20:21
ho copiato il tuo programmino e...elapsed time 0.000000
a meno che nn usi un codice...usi un codice? o è commentato così come lo hai postato?
io nn riesco proprio a capire...

mjordan
27-06-2008, 20:22
Guarda, io ho appena provato con questo codice:
double difference;
clock_t t1;
clock_t t2;

t1 = clock();
for (int x = 0; x < 100; ++x)
{
/* codice */
}
t2 = clock();

difference = (double)(t2 - t1);
printf("Elapsed time: %f.\n", (difference / (double)CLOCKS_PER_SEC));

E ottengo in output:
Elapsed time: 0.030000.

:boh:

Bhè allora il codice che ho scritto alla ceca senza compilare è giusto. Ci dev'essere qualche altro problema allora. :mbe:
3 centesimi di secondo... Interessante per un ciclo da 100 iterazioni. :)
Che procio è? :D

DanieleC88
27-06-2008, 20:27
LOL, ho un vecchissimo AMD Athlon Thunderbird da 1 Ghz, non pensate chissà che, è semplicemente che quel "codice" non trascritto non faceva niente di che (stampava un "ciao" sullo schermo)... era tanto per provare clock()... :D

gugoXX
27-06-2008, 22:30
Vuoi spaccare il capello in 4, come si suol dire (ma per questo esempio direi in 1000)
Puoi appendere codice assembly in linea?

L'assembly non occorre usarlo praticamente mai, per vari motivi.
Ma per certi lavori sporchi e semplici va ancora tanto bene...
Se fai l'assunto di avere un Intel oppure un AMD, cosa vera direi praticamente al 99% dei casi, allora puoi beneficiare della RDTSC

con il seguente (per VC++, ma se puoi appendere assembly un modo per tradurlo lo trovi)

DllExport unsigned long GetCPUTick()
{
unsigned int res[2];
__asm
{
rdtsc
mov res[1],edx
mov res[0],eax
}
return (unsigned long)(*res);
}



Otterrai come risultato della funzione il numero di tick eseguiti dal microprocessore a partire dall'accensione della macchina.
Dove ciascun tick ha la risoluzione della frequenza del microprocessore stesso. Sono proprio i colpi di clock.

Per me per esempio che vado a 3 GHz, la risoluzione di ciascun tick e' esattamente 1/3 miliardesimo di secondo. Direi sufficiente :fagiano:
Giusto per dire, un ciclo for secco fatto in C#
di 10 chiamate e successive stampe mi ha dato:

34976560116231
34976570277708
34976570348538
34976570413563
34976570478498
34976570542461
34976570606604
34976570670810
34976570735133
34976570799321

Dove 34976 / 3 = 11658 secondi. E' infatti 3 ore e un quarto circa che ho il computer acceso.

mjordan
27-06-2008, 23:33
Vuoi spaccare il capello in 4, come si suol dire (ma per questo esempio direi in 1000)
Puoi appendere codice assembly in linea?

L'assembly non occorre usarlo praticamente mai, per vari motivi.
Ma per certi lavori sporchi e semplici va ancora tanto bene...
Se fai l'assunto di avere un Intel oppure un AMD, cosa vera direi praticamente al 99% dei casi, allora puoi beneficiare della RDTSC

con il seguente (per VC++, ma se puoi appendere assembly un modo per tradurlo lo trovi)

DllExport unsigned long GetCPUTick()
{
unsigned int res[2];
__asm
{
rdtsc
mov res[1],edx
mov res[0],eax
}
return (unsigned long)(*res);
}



Otterrai come risultato della funzione il numero di tick eseguiti dal microprocessore a partire dall'accensione della macchina.
Dove ciascun tick ha la risoluzione della frequenza del microprocessore stesso. Sono proprio i colpi di clock.

Per me per esempio che vado a 3 GHz, la risoluzione di ciascun tick e' esattamente 1/3 miliardesimo di secondo. Direi sufficiente :fagiano:
Giusto per dire, un ciclo for secco fatto in C#
di 10 chiamate e successive stampe mi ha dato:

34976560116231
34976570277708
34976570348538
34976570413563
34976570478498
34976570542461
34976570606604
34976570670810
34976570735133
34976570799321

Dove 34976 / 3 = 11658 secondi. E' infatti 3 ore e un quarto circa che ho il computer acceso.

Da quello che leggo su questa istruzione invece, sembra ben al di sotto dello spaccare il capello in 4.


With the advent of multi-core/hyperthreaded CPUs, systems with multiple CPUs, and "hibernating" operating systems, RDTSC often no longer provides reliable results. The issue has two components: rate of tick and whether all cores (processors) have identical values in their time-keeping registers. There is no longer any promise that the timestamp counters of multiple CPUs on a single motherboard will be synchronized. So, you can no longer get reliable timestamp values unless you lock your program to using a single CPU.


E un comportamento seriale non lo puoi garantire comunque, nonostante non si faccia magari programmazione parallela, perchè attualmente anche le librerie standard dei linguaggi che prima erano seriali ora stanno ricevendo aggiornamenti per essere eseguite in modo parallelo in modo del tutto trasparente all'utente (per esempio, su g++ nel trunk della corrente versione di sviluppo la stdc++ presenta un'implementazione basata su gomp).

Inoltre:


Starting with the Pentium Pro, Intel processors have supported out-of-order execution, where instructions are not necessarily performed in the order they appear in the executable. This can cause RDTSC to be executed later than expected, producing a misleading cycle count.


Richiederebbe di eseguire prima un'istruzione rigorosamente serializzata per evitare questo problema che, ovviamente, ha un costo.
Le implementazioni standard dei tradizionali metodi invece sicuramente tengono conto di questi fattori. Insomma è piu' un'esercizio di stile che una soluzione pratica, per lo meno non in questo contesto. E comunque anche in altri contesti sembra si prediliga HPET :D

gugoXX
27-06-2008, 23:54
Gli esercizi di stile per me sono altri. Questa e' sicuramente una soluzione sporco.
Ma facendo attenzione scommetterei che nonostante tutto si possa avere una precisione maggiore della clock, magari riducendo di un qualche ordine di grandezza (in base 2), pur restando con parecchie virgole in piu' della clock().
E infatti la userei proprio solo in casi estremi, in cui il timer non ha precisione sufficiente.

Il discorso del ciclo di clock perso mi fa un po' ridere... davanti ad una system call (come e' la clock) che quando va bene te ne fara' perdere supergiu' una trentina tra salvataggi, stack, syscall e sysret.
Se poi il dato lo si va a leggere da una porta (non lo so, ma penso), occorre anche una call gate per prendere il privilegio. E li' sono dolori.

Lelex82
30-06-2008, 13:52
Guarda, io ho appena provato con questo codice:
double difference;
clock_t t1;
clock_t t2;

t1 = clock();
for (int x = 0; x < 100; ++x)
{
/* codice */
}
t2 = clock();

difference = (double)(t2 - t1);
printf("Elapsed time: %f.\n", (difference / (double)CLOCKS_PER_SEC));

E ottengo in output:
Elapsed time: 0.030000.

:boh:

ho riprovato questo codice aumentando le iterazioni da 100 a 10000 per ottenere come risultato un 0.010000.
evidentemente la funzione clock ha una risoluzione troppo alta. seguirò a usare la gettimeofday...

mjordan
30-06-2008, 13:54
ho riprovato questo codice aumentando le iterazioni da 100 a 10000 per ottenere come risultato un 0.010000.
evidentemente la funzione clock ha una risoluzione troppo alta. seguirò a usare la gettimeofday...

Non è la clock che ha una risoluzione troppo alta. E il compilatore che ottimizza cicli vuoti. Provaci a mettere qualcosa di piu' complesso dentro a un ciclo e vedi. E comunque 0.01 secondi sarebbe un centesimo di secondo, se ti aspettavi un minuto per 10.000 iterazioni vuote devi passare almeno ad un 8088 :asd: