Informazioni su quanto tempo trascorso in una funzione, in base all'input di questa funzione [chiuso]

4

Esiste uno strumento (quantitativo) per misurare le prestazioni delle funzioni in base al suo input?

Finora, gli strumenti che ho usato per misurare le prestazioni del mio codice, mi dicono quanto tempo ho trascorso in funzioni (come Jetbrain Dottrace per .Net), ma mi piacerebbe avere più informazioni sui parametri passati al funzione per sapere quali parametri influenzano maggiormente le prestazioni.

Diciamo che ho una funzione del genere:

int myFunction(int myParam1, int myParam 2) {
  // Do and return something based on the value of myParam1 and myParam2. 
  // The code is likely to use if, for, while, switch, etc....
}

Se vuoi uno strumento che mi permetta di dirmi quanto tempo è trascorso in myFunction in base al valore di myParam1 e myParam2 .

Ad esempio, lo strumento mi darebbe un risultato simile a questo:

For "myFunction" :
 value   |  value   | Number of | Average
myParam1 | myParam2 |   call    | time
---------|----------|-----------|--------
   1     |    5     |   500     | 301 ms
   2     |    5     |   250     | 1253 ms
   3     |    7     |   1268    | 538 ms
...

That would mean that myFunction has been call 500 times with myParam1=1 and myParam2=5, and that with those parameters, it took on average 301ms to return a value.

L'idea che sta dietro è quella di fare un po 'di ottimizzazione statistica organizzando il mio codice in modo tale che i blocchi di codici che sono più probabilità di essere eseguiti siano testati prima di quelli che hanno meno probabilità di essere eseguiti.

Per dirla chiaramente, se so quali sono i valori più utilizzati, posso riorganizzare la struttura if / while / for etc .. della funzione (e l'intero programma) per ottimizzarlo.

Mi piacerebbe trovare questi strumenti per C ++, Java o.Net.

Nota : non sto cercando suggerimenti tecnici per ottimizzare il codice (come passare parametri come const, funzioni di inlining, inizializzare la capacità di vettori e simili).

    
posta Mesop 15.05.2012 - 15:07
fonte

6 risposte

3

I tuoi test unitari dovrebbero coprire questo. Termina le chiamate in un cronometro e sei a posto.

Suppongo che tu non ne abbia poi, quindi ecco un modo per essere subito aggiornato e ottenere un po '.

Scrivi un test unitario parametrizzato sulla tua funzione usando Pex e poi eseguilo / quelle prove. Avere ANTS in esecuzione quando lo fai - o semplicemente impostare un cronometro prima / dopo la chiamata alla funzione.

In sostanza, se ricordo bene, Pex usa un dimostratore di teoremi per raggiungere ogni ramo e potenziale eccezione / condizione limite usando i parametri per la funzione. Controlla i parametri che genera, pensa in modo critico a qualcuno di tuo e dovresti avere quello che stai cercando.

    
risposta data 15.05.2012 - 15:39
fonte
1

In C ++, se questo è solo per un particolare metodo con input particolari, è piuttosto facile scrivere una classe helper che impiegherà quanto tempo ci vorrà per eseguire un particolare scope. Prendi il tempo nel costruttore e nel distruttore calcoli l'ora corrente e salvalo in una struttura dati statica.

Questa è una tecnica che ho usato con dispositivi embedded per i quali non avevo profiler.

Attenzione: non ho compilato / testato questo:

typedef std::map<std::pair<int,int>, std::pair<int,int> > timeMap;

class TimeIt {
private:
    static timeMap times;
    clock_t timeCalled;
    int myParm1;
    int myParm2;

public:
    TimeIt(int parm1, int parm2) : timeCalled(clock()), myParm1(parm1), myParm2(parm2) {}

    ~TimeIt() {
        clock_t runtime = clock() - timeCalled;
        if(timeMap::iterator it = times.find(std::pair<int,int>(myParm1,myParm2))) {
            it->second->first++;
            it->second->second+=runtime;
        }
        else {
            times[std::pair<int,int>(myParm1,myParm2)] = std::pair<int,int>(1,runtime);
        }
    }

    static void report() {
        for(timeMap::iterator it=times.begin();it!=times.end();it++) {
             cout << it->first->first << " | ";
             cout << it->first->second << " | ";
             cout << it->second->first << " | ";
             cout << (it->second->second/it->second->first) << endl;
        }
    }
}

Quindi nel tuo metodo, fai:

int myFunction(int myParam1, int myParam 2) {

    TimeIt timeIt;

    // Do and return something based on the value of myParam1 and myParam2. 
    // The code is likely to use if, for, while, switch, etc.... 
}

E quando vuoi i dati:

TimeIt::report();

Sono sicuro che puoi fare qualcosa di simile in .NET o Java. Il punto più importante è prendersi cura quando si prende il tempo () dell'orologio. Non vuoi fare nulla di significativo nel distruttore prima di afferrare l'orologio ().

Ovviamente se vuoi una soluzione più generale, vuoi un vero profiler.

    
risposta data 15.05.2012 - 18:15
fonte
1

Risposta solo per .NET

In base alle mie conoscenze, non è possibile recuperare il valore effettivo dei parametri passati a un metodo.

Certo, puoi ottenere una serie di oggetti ParameterInfo, attraverso i quali puoi conoscere molto sui parametri ... ma purtroppo non puoi accedere ai loro valori. Certo, ci sono alcuni modi per indagare sulla traccia dello stack, ma non è garantito che siano abbastanza robusti in tutte le condizioni.

Quindi, no, sembra che tale strumento non possa nemmeno essere sviluppato per .NET.

Tuttavia non conosco altre piattaforme.

    
risposta data 15.05.2012 - 19:10
fonte
0

Anche se un tale strumento potrebbe essere molto utile, non sono a conoscenza di alcunché offra un'analisi dell'hotspot basata su linea. Dato che i profiler sono difficili da hackerare e facilmente sbagliati, probabilmente sei sicuramente meglio dividere temporaneamente il tuo codice in diverse funzioni solo così un normale profiler può dirti quello che devi sapere.

    
risposta data 15.05.2012 - 15:23
fonte
0

Dubito che troverai questo strumento, quindi molto probabilmente dovrai implementare il tuo.

Tuttavia, ci sono profiler del codice (ad esempio callgrind al profilo c e c ++ del codice), che fornisce un valore che rappresenta un tempo relativo trascorso in una funzione.

    
risposta data 15.05.2012 - 15:11
fonte
0

Se vuoi profilare una sola funzione e conosci il piccolo numero di combinazioni di input che ti interessano, puoi aggiungere una sorta di "meccanismo di commutazione" che renderà le chiamate visibili in qualsiasi tipico profiler:

int myFunction_internal(int myParam1, int myParam 2) {
  // the main body
}

int myFunction_p1_p5() {
    return myFunction_internal(1,5);
}

int myFunction_p2_p5() {
    return myFunction_internal(2,5);
}

int myFunction_other(int myParam1, int myParam2) {
    return myFunction_internal(myParam1,myParam2);
}

int myFunction(int myParam1, int myParam2) {
   if(myParam1==1 && myParam2==5)
        return myFunction_p1_p5();
   if(myParam1==2 && myParam2==5)
        return myFunction_p2_p5();
   return myFunction_other(myParam1,myParam2);
}
    
risposta data 15.05.2012 - 16:40
fonte

Leggi altre domande sui tag