2009-07-03 5 views
0

Ich möchte meine Ausführung in einer nicht standardmäßigen Weise profilieren. Mit gprof, Valgrind, Oprofile ... für eine bestimmte Funktion, ich bekomme nur das Mittel seiner Ausführungszeit. Was ich möchte, ist die Standardabweichung dieser Ausführungszeit zu erhalten.Wie profiliere ich jeden Anruf einer Funktion?

Beispiel:

void a() 
    sleep (rand() % 10 + 10) 

void b() 
    sleep (rand() % 14 + 2) 

main 
    for (1 .. 100) 
    a() 
    b() 

mit Standard-Werkzeugen, ein und b Funktionen ähnliches Verhalten haben. Kennst du irgendein Werkzeug, das mir dieses Ergebnis mit einem automatischen Ansatz geben könnte?

Ich habe bereits mit TAU getestet, aber bis jetzt ist es nicht wirklich relevant. Ich denke, dass es eine Lösung auf diese Weise gibt, aber ich bin nicht genug zuversichtlich mit TAU. Wenn jemand Tau-Experte ist, versuche ich, alle Ausführungszeiten der Funktion beizubehalten, und am Ende die Mathematik zu machen. Aber ich weiß nicht, wie ich es in Tau angeben soll.

Ich möchte Profil C/C++ - Code, aber wenn Sie irgendeine andere Programmiersprache führen, bin ich offen.

+0

Muss es automatisch sein? Schreiben Sie einfach ein paar Makros und haben Sie eine Tabelle, in der Sie die Ergebnisse aufschreiben. Dann können Sie berechnen, was Sie wollen. – Makis

+0

würde ich besser sein. Wenn dies nicht der Fall ist, muss ich für jede Funktion eine Tabelle verwalten, die dynamische Zuweisung verwalten (die Anzahl der Funktionsaufrufe kann nicht vorhergesagt werden).Und wenn Sie ein Programm mit Hunderten von Funktionen profilieren möchten, erscheint es unrealistisch, die Makros manuell hinzuzufügen. –

+0

Hm, ich kann dir da nicht helfen, aber wie bei der dynamischen Zuweisung: du brauchst es nicht, nur einen Zähler für die Anzahl der Anrufe und einen Ringpuffer. Natürlich werden Sie nicht die Ergebnisse aller Anrufe erhalten, aber diese beiden sollten Ihnen helfen, die Funktionen einzugrenzen, die die meiste Zeit benötigen. Oh, und wenn Sie Funktionsaufrufe auf irgendeine Weise blockieren können, können Sie dies automatisch machen. – Makis

Antwort

0

Ich denke, Apple Shark Profiling-Tool kann den Mittelwert für jede Funktion generieren. Natürlich hilft dir das nur auf einem Mac.

3

Ein Profilierungswerkzeug ist keine Zauberei, und Sie können für einige Zwecke in wenigen Zeilen eigene Rollen erstellen.

Etwas Ähnliches, vielleicht:

// code profile.cpp : Defines the entry point for the console application. 
// 

#include "stdafx.h" 

class cProfile 
{ 
public: 
    // construct profiler for a particular scope 
    // call at begining of scope to be timed 
    // pass unique name of scope 
    cProfile(const char* name) 
    { 
     myName = string(name); 
     QueryPerformanceCounter((LARGE_INTEGER *)&myTimeStart); 
    } 
    // destructor - automatically called when scope ends 
    ~cProfile(); 

    // constructor - produces report when called without parameters 
    cProfile(); 


private: 
    typedef accumulator_set<__int64, stats<tag::variance(lazy)> > acc_t; 
    static map < string, acc_t > myMap; 
    string myName; 
    __int64 myTimeStart; 
}; 
map < string, accumulator_set<__int64, stats<tag::variance(lazy)> > > cProfile::myMap; 


cProfile::~cProfile() 
{ 
    __int64 t=0; 
    QueryPerformanceCounter((LARGE_INTEGER *)&t); 
    t -= myTimeStart; 


    map < string, acc_t >::iterator p = myMap.find(myName); 
    if(p == myMap.end()) { 
     // this is the first time this scope has run 
     acc_t acc; 
     pair<string,acc_t > pr(myName,acc); 
     p = myMap.insert(pr).first; 
    } 
    // add the time of running to the accumulator for this scope 
    (p->second)(t); 

} 
// Generate profile report 
cProfile::cProfile() 
{ 
    __int64 f; 
    QueryPerformanceFrequency((LARGE_INTEGER *)&f); 

    printf("%20s Calls\tMean (secs)\tStdDev\n","Scope"); 
    for(map < string, accumulator_set<__int64, stats<tag::variance(lazy)> > >::iterator p = myMap.begin(); 
     p != myMap.end(); p++) 
    { 
     float av = mean(p->second)/f; 
     float stdev = sqrt(((double) variance(p->second)) )/f; 
     printf("%20s %d\t%f\t%f\n",p->first.c_str(), 
      boost::accumulators::count(p->second), av, stdev); 
    } 
} 
void a() 
{ 
    cProfile profile("a"); 

    Sleep (rand() % 10 + 10); 
} 
void b() 
{ 
    cProfile profile("b"); 

    Sleep (rand() % 20 + 5); 
} 


int _tmain(int argc, _TCHAR* argv[]) 
{ 
    for (int k=1;k<=100;k++) { 
     a(); 
     b(); 
    } 

    cProfile profile_report; 

    return 0; 
} 

Welche

 Scope Calls  Mean (secs)  StdDev 
      a 100  0.014928  0.002827 
      b 100  0.015254  0.005671 
0

Eigentlich Oprofile können Profilfunktion von einem Aufruf Diagrammansicht, die mit unterschiedlichen Anrufer gleichen Rufenen Routine bedeutet produziert wird in verschiedenen profilieren Statistiken.

Probieren Sie den Befehl opreport für den Bericht aus.

2

Vielleicht nicht zutreffen, da es gcc-spezifisch ist, aber ich habe gefunden, dass das spart mir ein paar mal mindestens. Wenn Sie den Code mit "-Finster-Funktionen" Flag kompilieren, wird jeder Eingangs- und Ausgangspunkt einer Funktion in dem Modul, das mit diesem Flag kompiliert wurde, mit den Aufrufen der Gerätefunktionen stubben. Alles, was Sie tun müssen, ist eine Inline-Zeile, die einen hochpräzisen Zähler (z. B. rdtsc auf x86, siehe this discussion) und eine große Reihe von Datensätzen liest: [func_addr, is_enter, timer_value], in die Sie fortlaufend schreiben würden Gerätefunktionen. Speichern Sie dieses Array nach dem Beenden in eine Datei und analysieren Sie es offline.

Ziemlich weit von "automatisierten" Ansatz, den Sie wahrscheinlich gesucht haben - aber hoffe, das ist von Nutzen. Das folgende Beispiel zeigt das Verhalten von gcc, wenn es mit -Filterfunktionen kompiliert wird. Wenn Sie die Flagge nicht hinzufügen, wird es "wie normal" funktionieren.

#include <stdio.h> 
#include <stdlib.h> 

void __cyg_profile_func_enter(void *fn, void *call) 
    __attribute__ ((no_instrument_function)); 
void __cyg_profile_func_exit(void *fn, void *call) 
    __attribute__ ((no_instrument_function)); 

void __cyg_profile_func_enter(void *fn, void *call) { 
    printf("Enter %x,%x\n",fn,call); 
} 
void __cyg_profile_func_exit(void *fn, void *call) { 
    printf("Exit %x,%x\n",fn,call); 
} 

int foo(int i) { 
    printf("inside foo\n"); 
} 

int main(int argc, char *argv[]) { 
    printf("inside main 1\n"); 
    foo(123); 
    printf("inside main 2\n"); 
    exit(0); 
} 
Verwandte Themen