2012-07-15 11 views
7

Próbowałem użyć ograniczonych kwalifikowanych wskaźników i napotkałem problem. Poniższy program jest prosty i przedstawia tylko problem.Ograniczanie wskaźników i wstawianie

Funkcja calc_function używa trzech wskaźników, które są ograniczone, więc "SHALL" nie są aliasami. Podczas kompilowania tego kodu w visual studio funkcja będzie wstawiana, więc bez żadnego powodu program Visual Studio 2010 ignoruje kwalifikatory. Jeśli wyłączę wpisywanie, kod wykonuje więcej niż sześć razy szybciej (od 2200ms do 360ms). Ale nie chcę wyłączać wprowadzania w całym projekcie ani całego pliku (ponieważ wtedy będzie to wywoływać narzut w np. Wszystkich programach pobierających i ustawiających, co byłoby okropne).

(może być jedynym rozwiązaniem jest wyłączenie inline tylko o tej funkcji?)

Próbowałem stworzyć tymczasowy ograniczyć wykwalifikowanych wskaźniki do funkcji, zarówno na górze i na pętli wewnętrznej spróbować powiedzieć kompilator, który obiecuję, że nie ma aliasingu, ale kompilator mi nie uwierzy i nie zadziała. Próbowałem również poprawić ustawienia kompilatora, ale jedynym, który znalazłem działa, jest wyłączenie wstawiania.

Byłbym wdzięczny za pomoc w rozwiązaniu tego problemu optymalizacji.

Aby uruchomić program (w realeasemode), nie zapomnij użyć argumentów 0 1000 2000. Dlaczego użycie argumentów userinput/program ma na celu upewnienie się, że kompilator nie może wiedzieć, czy istnieje czy nie jest? t aliasowanie między wskaźnikami a, b i 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 za dobre praktyki profilowania. Zdecyduję się nie narzekać na specyfikatora formatu. P.S. 'clock' zwraca' clock_t', a nie 'time_t'. – Hurkyl

+1

Spróbuj chronić wywołanie funkcji, sprawdzając, czy przesunięcia są wystarczająco duże. Najprawdopodobniej będziesz musiał użyć prawdziwych zmiennych 'int', ale przechowaj przesunięcia, zamiast hacku, którego użyłeś. – Hurkyl

+0

@Hurkyl Myślałem, że clock_t i time_t były zarówno typedefs do tego samego, ale masz rację. (Btw, jak mogę edytować mój post z pytaniami?) – Boll

Odpowiedz

3

Jeśli zadeklarujesz funkcję z __declspec(noinline), zmusi go, by nie być inlined:

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

Można to wykorzystać, aby ręcznie wyłączyć inline na podstawie za funkcją.


chodzi o restrict, kompilator może swobodnie używać go tylko wtedy, gdy chce. Tak więc błąkanie się z różnymi wersjami tego samego kodu jest nieco nieuniknione przy próbie "oszukiwania" kompilatorów w celu wykonania takich optymalizacji.

+0

To rozwiązanie działa zarówno w kodzie testowym w pytaniu, jak iw mojej prawdziwej aplikacji. Ale pojawią się problemy, jeśli bardzo mała funkcja, która jest nazywana wiele razy, wymaga ograniczonych kwalifikowanych wskaźników, gdzie __declspec (noinline) wymusi dość duży narzut. Dlatego poczekam z akceptacją tego jako najlepszą odpowiedzią. – Boll

+0

Tak, wiem co masz na myśli. Domyślam się, że analiza aliasingu wskaźnika używana w VS2010 jest tylko na poziomie funkcji na poziomie szczegółowości. Nie jest więc w stanie odróżnić wskaźników bez wygładzania, które są "generowane" w środku funkcji. Nie jestem pewien, czy 'restrict' może być użyty na lokalnych deklarowanych wskaźnikach. Jeśli tak, może warto spróbować. – Mysticial

+0

Masz całkowitą rację, a ja próbowałem używać lokalnych deklarowanych wskaźników z ograniczeniem bez powodzenia.Twój "__declspec (noinline)" jest najlepszym rozwiązaniem i działa w moim bieżącym przypadku (moja aplikacja), więc akceptuję go jako odpowiedź. Dzięki. – Boll