2012-07-15 12 views
7

Ich habe versucht, beschränken Sie qualifizierte Zeiger, und ich habe ein Problem festgestellt. Das folgende Programm ist nur ein einfaches, um das Problem darzustellen.Pointer und Inlining beschränken Zeiger auf

Die Funktion calc_function verwendet drei Zeiger, die so eingeschränkt sind, dass sie sich nicht gegenseitig aliasieren. Wenn Sie diesen Code in Visual Studio kompilieren, ist die Funktion inline, weshalb Visual Studio 2010 die Qualifizierer aus keinem Grund ignoriert. Wenn ich das Inlining deaktiviere, wird der Code mehr als sechs Mal schneller ausgeführt (von 2200ms bis 360ms). Aber ich möchte nicht das gesamte Projekt oder die ganze Datei inlining (weil dann Anruf Overheads in zum Beispiel alle Getters und Setter, die schrecklich wäre).

ich versucht habe (Könnte die einzige Lösung inlining nur diese Funktion? Abzuschalten sein) auf temporäre qualifizierte Zeiger in der Funktion, die beide an der Spitze und in der inneren Schleife beschränken zu erstellen zu versuchen, das zu sagen, Compiler, den ich verspreche, dass es kein Aliasing gibt, aber der Compiler wird mir nicht glauben, und es wird nicht funktionieren. Ich habe auch versucht, Compiler-Einstellungen zu optimieren, aber die einzige, die ich gefunden habe, die funktioniert, ist das Inlining zu deaktivieren.

Ich würde einige Hilfe schätzen, um dieses Optimierungsproblem zu lösen.

Um das Programm (in Realeasemode) auszuführen, vergessen Sie nicht, die Argumente 0 1000 2000 zu verwenden. Warum die Verwendung von UserInput/Programmargumente ist sicher, dass der Compiler nicht wissen kann, ob es oder Isn ' t Aliasing zwischen den Zeigern a, b und c.

#include <cstdlib> 
#include <cstdio> 
#include <ctime> 

// Data-table where a,b,c will point into, so the compiler cant know if they alias. 
const size_t listSize = 10000; 
int data[listSize]; 

//void calc_function(int * a, int * b, int * c){ 
void calc_function(int *__restrict a, int *__restrict b, int *__restrict c){ 
    for(size_t y=0; y<1000*1000; ++y){ // <- Extra loop to be able to messure the time. 
     for(size_t i=0; i<1000; ++i){ 
      *a += *b; 
      *c += *a; 
     } 
    } 
} 
int main(int argc, char *argv[]){ // argv SHALL be "0 1000 2000" (with no quotes) 
    // init 
    for(size_t i=0; i<listSize; ++i) 
     data[i] = i; 

    // get a, b and c from argv(0,1000,2000) 
    int *a,*b,*c; 
    sscanf(argv[1],"%d",&a); 
    sscanf(argv[2],"%d",&b); 
    sscanf(argv[3],"%d",&c); 
    a = data + int(a); // a, b and c will (after the specified argv) be, 
    b = data + int(b); // a = &data[0], b = &data[1000], c = &data[2000], 
    c = data + int(c); // So they will not alias, and the compiler cant know. 

    // calculate and take time 
    time_t start = clock(); 
     funcResticted(a,b,c); 
    time_t end = clock(); 
    time_t t = (end-start); 
    printf("funcResticted  %u (microSec)\n", t); 

    system("PAUSE"); 
    return EXIT_SUCCESS; 
} 
+1

+1 für gute Profilierungsverfahren. Ich werde mich dafür entscheiden, nicht über den Formatbezeichner zu klagen. P.S. "clock" gibt ein "clock_t", nicht ein "time_t" zurück. – Hurkyl

+1

Versuchen Sie, den Funktionsaufruf zu überwachen, indem Sie prüfen, ob die Offsets ausreichend groß sind. Sie werden wahrscheinlich echte 'int'-Variablen verwenden müssen, um die Offsets zu speichern, anstatt den Hack, den Sie verwendet haben. – Hurkyl

+0

@Hurky Ich dachte, dass clock_t und time_t beide typedefs zur gleichen Sache waren, aber Sie haben Recht. (Btw, wie bearbeite ich meine Frage-Post?) – Boll

Antwort

3

Wenn Sie eine Funktion mit __declspec(noinline) erklären, wird es nicht inlined zwingen:

http://msdn.microsoft.com/en-us/library/kxybs02x%28v=vs.80%29.aspx

Sie können diese verwenden, um manuell inlining auf einer Pro-Funktion Basis zu deaktivieren.


Was restrict, ist der Compiler es kostenlos nur verwenden, wenn es will. Es ist daher unvermeidbar, mit verschiedenen Versionen desselben Codes herumzuhantieren, wenn versucht wird, Compiler zu "tricksen", um solche Optimierungen durchzuführen.

+0

Diese Lösung funktioniert, sowohl im Test-Code in der Frage, als auch in meiner realen Anwendung. Aber es wird einige Probleme geben, wenn eine sehr kleine Funktion, die viele Male aufgerufen wird, eingeschränkte qualifizierte Zeiger benötigt, wobei die __declspec (noinline) einen ziemlich großen Anruf-Overhead erzwingt. Deshalb warte ich darauf, dies als beste Antwort zu akzeptieren. – Boll

+0

Ja, ich weiß was du meinst. Meine Vermutung ist, dass die in VS2010 verwendete Zeiger-Aliasing-Analyse nur auf der Granularität auf Funktionsebene ist. Daher ist es nicht möglich, Nicht-Aliasing-Zeiger zu unterscheiden, die in der Mitte einer Funktion "generiert" werden. Ich bin mir nicht sicher, ob 'restrict' für lokal deklarierte Zeiger verwendet werden kann. Wenn dies der Fall ist, könnte es etwas zu versuchen sein. – Mysticial

+0

Sie haben völlig Recht, und ich habe versucht, lokal deklarierte Zeiger mit Einschränkung ohne Glück zu verwenden.Ihre "__declspec (noinline)" ist die beste Lösung und funktioniert in meinem aktuellen Fall (meine Anwendung), also akzeptiere ich sie als Antwort. Vielen Dank. – Boll