Newsgroup: it.comp.lang.c++
Titolo: Conteggio cicli di clock #2

Non demordo.
Voglio contare i cicli di clock che la mia macchina fa per effettuare una
serie di operazioni.
Esempio: ho una funzione "operazione()" e voglio sapere quanti cicli di
clock la mia macchina compie per eseguire questa funzione.
-----------------------------------------------------------
cicli1 = funzione_che_conta_i_cicli_di_clock();
operazione();
cicli2 = funzione_che_conta_i_cicli_di_clock();
cout << "Ho impiegato " << cicli2-cicli1 << " cicli di clock!\n";
----------------------------------------------------------
Lo posso fare direttamente in c++?
C'è una funzione che lo fa?
In che libreria?
La funzione clock() che cosa fa di preciso?
Spero di essere stato chiaro.
Grazie

 
sei stato chiaro, ma non c'è un modo standard in C++ per fare quello che 
chiedi, devi rivolgerti alle API del tuo S.O. Mi pare comunque che ci 
sia una soluzione se sei in grado di inserire codice assembly nel tuo 
programma.

serie di operazioni.
I processori di classe "pentium" hanno un contatore di cicli di clock
integrato. Per leggerne il valore o scrivi un paio di righe di
assembler o utilizzi (se esiste) qualche api del tuo sistema
operativo. Ad esempio Win32 ha una serie di funzioni.... di cui in
questo momento mi sfugge il nome :-(  (se guardi nella documentazione
non è difficile trovarle)
Premesso ciò, non esiste nessuna funzione C++ standard per fare
questo....
ciao
Andrea
----
http://space.tin.it/io/andrea.fa

> Lo posso fare direttamente in c++?
Lo puoi fare utilizzando funzioni specifiche della tua piattaforma.
Sotto Windows esiste l'API GetTickCount() oppure le più raffinate
QueryPerformanceCounter()/QueryPerformanceFrequency().  La trattazione
dell'uso di queste funzioni, però, esula dal topic di questo gruppo,
meglio spostarsi su it.comp.programmare.win32.
La funzione clock() (il cui header è in time.h) può andare bene, se
non ti servono tempi molto precisi, ti restituisce il tempo CPU.
L'utilizzo tipico è il seguente:
#include <iostream>#include <ctime>#include <cstdlib>void
dummy(){     static int i;     std::cout << "paperino" << ++i <<
std::endl;}int main(){    clock_t start_time, end_time;    start_time
= clock();    for (int i = 0; i < 10000; i++) dummy();    end_time =
clock();    std::cout << "tempo CPU usato (sec): "              <<
(end_time - start_time)/CLOCKS_PER_SEC              << std::endl;
system("pause");    return 0;}

 system("pause");    return 0;}
...ops...
#include <iostream>
#include <ctime>
#include <cstdlib>
void dummy()
{
     static int i;
     std::cout << "paperino" << ++i << std::endl;
}
int main()
{
    clock_t start_time, end_time;
    start_time = clock();
    for (int i = 0; i < 10000; i++) dummy();
    end_time = clock();
    std::cout << "tempo CPU usato: "
              << (end_time - start_time)/CLOCKS_PER_SEC
              << std::endl;
    return 0;
}

               << std::endl;
Senza voler essere critico
(altrimenti di questi tempi chissa' cosa mi arriva :-) )
io aggiungerei forse magari volendo anche un (double)
davanti a (end_time - start_time) cioe' la riga diventerebbe
               << (double)(end_time - start_time)/CLOCKS_PER_SEC
in questo modo si puo' avere una idea della
precisione di clock(), che dipende dall'implementazione
ma spesso e' dell'ordine del centesimo di secondo.
Nel senso che anche se CLOCKS_PER_SEC magari vale 1000000,
ma questo non vuol dire che puoi misurare milionesimi
di secondo, perche' in realta' il valore fornito da
clock() avanza a passi di, per esempio, 10000.
Senza il (double) otteniamo la stampa del tempo approssimato
ai secondi (e quindi in questo caso un bel 0, presumo)
Per rispondere in qualche modo alla creatrice del thread
(Sigourney) direi che per usi "amatoriali" clock() puo' andare
benissimo, se i tempi delle routine che vuoi in qualche
modo cronometrare sono decisamente maggiori del centesimo di
secondo e se non hai problemi derivanti da multithreading
etc.etc. Altrimenti, come ti hanno gia' suggerito, la
strada da percorrere esce dal C++ standard e si deve dirigere
verso soluzioni che dipendono strettamente dalla tua piattaforma.
In ogni caso clock() non va bene per contare "i cicli di clock":
al massimo potresti avere una stima del tempo di CPU usato,
per avere i cicli di clock bisognerebbe anche avere una funzione
che mi dice a che frequenza va la CPU, e questa funzione proprio
non c'e' in C++ standard.
ciao,
g.

 La funzione clock() che cosa fa di preciso?
Misura approssimativamente il tempo di processore trascorso, misurato
in incrementi di 1 / CLOCKS_PER_SEC secondi.
Ciao,
Nicola

 serie di operazioni.
Confermi che l'unità di misura di questi cicli non è il "secondo", 
giusto? E' solo un numero adimensionato, cioè il numero di cicli 
macchina. Poi il tempo in secondi dipende dalla velocità del processore. 
Capito bene ho? 
-- 
Luc

Finalmente un po' di risposte chiare.
Grazie a tutti.

 wrote in message
MPG.1aa7e76c1...@tornado.fastwebnet.it...


Hai capito perfettamente!

 La funzione clock() che cosa fa di preciso?
Fa un po' di porcherie... :-) scherzo...
A titolo "puramente esemplificativo" ti faccio vedere
cosa puoi fare in *NIX utilizzando il TSC della CPU:
-------------------------
#include <sys/types.h>
#include <sys/sysctl.h>
int buff;
size_t len;
typedef union {
   unsigned long long ts;
     struct {
       unsigned long lo;
       unsigned long hi;
     } ts_;
} timestamp_t;
// TSC corrente
#define get_tsc(ts)               \
        {                         \
          asm("rdtsc"             \
          : "=d" ((ts).ts_.hi),   \
            "=a" ((ts).ts_.lo));  \
        }
// Restituisce i clock/secondo della CPU
int get_ticks(){
  len=sizeof(buff);
  if(sysctlbyname("machdep.tsc_freq", &buff, &len, 0, 0) < 0)
  return 0;
  return buff;
}
-------------------------
Ottieni i "ticks" con get_tsc(VARIABILE_timestamp_t)
e porti nel dominio del tempo con get_ticks(); come vedi serve
una chiamata assembly per ottenere il contenuto del TSC.
Ripeto, non è escluso che contando i cicli di clock
tre due istanti di una applicazione "nel mezzo" non
ci si ficchi qualcos'altro e conteresti anche i cicli
di clock di quella parte di codice di un'altro processo
schedulato.
A tal proposito, se sei in ambiente *NIX (ma noto che il tuo
newsreader è àutluc...) potresti dare un'occhiata a times()
il cui uso - personalmente - trovo sia, al fine della precisione,
sostanzialmente inutile.
L'unica cosa che rimane è la conta dei cicli di clock dopo aver
dato massima priorità al processo di interesse (cosa molto pericolosa...)
Ciao!
SiMoStro

 sostanzialmente inutile.
Sto lavorando in Win...
Vado a 'studiare' il tuo esempio. Mi ci vorrà un mesetto... (sinceramente
sei su di un altro livello)
Ma oramai credo di aver perso le speranze.
Credo che farò così: conterò i secondi che impiega l'intero programma,
banalmente con due timestamps all'inizio ed alla fine;
poi dividerò per il numero di dati processati.
Otterrò una stima un po' imprecisa... ma qualcosa verrà fuori.
Grazie sei stato molto chiaro.
Ciao

Sigourney wrote:

Per sapere quanti cicli di closk occupa una determinata funzione (a meno 
di schedulazione del processore) devi:
1) compilare il codice
2) verificare nell'assembly le righe che identificano la funzione
3) con un manuale relativo al tuo processore verificare per ogni 
istruzione assembly cosa genera in termini di binario e contare le righe 
generate dall'assembly
4) calcolare eventuali gli scarti dovuti all'architettura (sempre dal 
manuale del processore)
Ciao.

 manuale del processore)
Potrei sbagliare, ma penso che questa strada sia di fatto impraticabile.
La somma dei costi (in termini di cicli di clock) delle varie
operazioni e' un valore che puo' essere cosi' lontano dal
tempo effettivamente impiegato dal programma da risultare
praticamente inutile. (possono esserci delle eccezioni).
Il fatto e' che le caratteristiche delle moderne cpu, come
pipelining, esecuzione condizionata, prefech e l'uso della cache,
rendono il tempo finale difficilmente prevedibile.
Per esempio posso mostrare un programmino che fa le stesse
operazioni (riempie una matrice 1024x1024 di interi e poi
ci fa delle operazioni sopra) e a seconda dell'ordine
degli indici, pur facendo le stesse operazioni, ho una differenza
in termini di tempo di un fattore 20.
Penso che per quel che vuole fare la Sigourney forse dovrebbe rivolgersi
a dei tool di profiling molto spinto. Oppure scordarsi dei cicli
di clock, e usare clock ma calcolando il tempo complessivo di, diciamo,
1000 invocazioni della sua routine e poi mediare.
ciao,
g.

Giovanni Resta wrote:

Allora, diciamo che se vuoi sapere i cicli teorici devi fare il 
conteggio da binario come ho scritto prima.
Se invece vuoi sapere i tempi di esecuzione allora usi un profiler (io 
uso glowcode che mi da tutte le statistiche)
Naturalmente in entrambe i casi il tempo deve considerarsi puramente 
teorico perchè se sotto ci metti una cpu diversa, uno scheduler dei task 
diverso o un processo che si becca l'80% della cpu.....

 In che libreria?
Nelle librerie standard C/C++, no.
Alcuni O.S. danno funzioni specifiche.
Se non ti interessa la portabilità del codice al di fuori della
piattaforma i586, puoi sicuramente usare la seguente facilissima funzione:
long getClock() {
    asm ( "rdtsc" );
}
...dovrebbe andare.
L'esempio l'ho estratto da un esempio di JNI che ho fatto per avere
accesso a quell'istruzione da Java, lo trovi qua (sul mio CVS):
http://home.lapo.it/cgi-bin/viewcvs.cgi/lapint/it/lapo/util/RDTSC.c?rev=HEAD&content-type=text/vnd.viewcvs-markup
- --
L a p o   L u c h i n i
l a p o @ l a p o . i t
w w w . l a p o . i t /
http://www.megatokyo.it
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.2.4 (Cygwin)
Comment: Using GnuPG with Mozilla - 
http://enigmail.mozdev.org
iEYEARECAAYFAkBAtlUACgkQaJiCLMjyUvvEjgCgpQg0HAZVB8o93DVS1TXKCxC6
PXoAn10bFEaIMkSXdWfWmXYIQ3zN3d0O
=oyPJ
-----END PGP SIGNATURE-----

 ...dovrebbe andare.
Non dovrebbe andare... va!
La portabilità del codice non mi interessa infatti.
Grazie Tante.
Ciao