Autor Wątek: Deklarownia zmiennych a wydajność.  (Przeczytany 4370 razy)

Offline lukasyno

  • Użytkownik

# Luty 23, 2011, 15:07:27
Zastanawia mnie fakt czy

taki sposób deklarowania zmiennych w wewnątrz pętli

void compute() {
for (int i = 0; i < n; ++i)
{
   int a = val1;
   int b = val2;
   int c = val3;
   ..... ok. 30 takich zmiennych

}

}


jest wolniejszy od tego

 int a, b, c;

void compute() {
for (int i = 0; i < n; ++i)
{
   a = val1;
   b = val2;
   c = val3;
   ..... ok. 30 takich zmiennych

}

}

val...n to jakieś obliczone wartości przypisane do zmiennych na których wykonują się inne obliczenia..
oczywiście zapis to tylko pokazówka w rzeczywistości zmienne nie sa typu int itd :)

ma to jakieś znaczenie ? nawet minimalne ?

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Lerhes

  • Użytkownik

# Luty 23, 2011, 15:22:45
Ja bym po prostu zrobił test i tyle -> sprawdź sobie, dając w pętli jakieś 1kk iteracji.

Według mnie - nie będzie różnicy. Przy wywoływaniu funkcji i tak jest obliczane potrzebne miejsce na stosie do pomieszczenia tych wszystkich zmiennych (w pętli i poza nią) (i ta pamięć jest rezerwowana przy tworzeniu zapisu aktywacji funkcji), więc nie będą tworzone i niszczone (w stylu new, delete) przy każdym obiegu pętli.

Dla pewności zrobiłbym test (przetestowanie tego zajęło by mniej czasu, niż pisanie tej odpowiedzi.. I twojego pytania...).

Powyższa odpowiedź ma charakter nie na 100%, tak po prostu ja się tego nauczyłem.
Edit: Czyli w przypadku który przedstawiłeś już przy wywoływaniu funkcji zostanie zarezerwowane miejsce na te 31 intów (i parę dodatkowych rzeczy, jak miejsce na wartość zwracaną z funkcji, adres powrotu itd) więc nie będą one tworzone za każdym obiegiem pętli, a co za tym idzie -> efekt będzie ten sam gdyby umieścić te deklaracje przed pętlą.
Edit down: Oczywiście to dotyczy typów prostych.
Lerhes
« Ostatnia zmiana: Luty 23, 2011, 15:43:21 wysłana przez Lerhes »

Offline s0d

  • Użytkownik

# Luty 23, 2011, 15:33:15
zależy czy zmienna będzie za każdym razem tworzona/ niszczona w każdym obiegu pętli czy tylko raz tak jak w wypadku deklaracji zmiennej przed pętlą.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Luty 23, 2011, 15:34:46
Podstawowe pytanie: zmienne są typów prostych, czy są to klasy?

Jeżeli typy proste, optymalizator powinien być w stanie sobie z tym poradzić.
Jeżeli klasy, za każdym razem będą wywoływane konstruktory/destruktory (chyba że są puste, to też sobie powinien poradzić).

Offline lukasyno

  • Użytkownik

# Luty 23, 2011, 15:46:04
po1. robiłem testy ale wydają się nie wiarygodne bo samo z siebie robienie dużej (wielkiej) pętli dość rożnie zajmuje czasu procesora...

po2.  ten problem dotyczy newralgicznego miejsca w moim projekcie i chciałem je po prostu jak najlepiej się da zoptymalizować... to nie jest pytanie "bo mi się nudzi" tylko raczej "raz na zawsze chce wiedzieć jak to jest"

zmienne są złożonych typów ale działają na zasadzie przypisywania referencji z CollisionPoint, żadne konstruktory czy destruktory się nie wykonują(aż takim szaleńcem nie jestem :P)..

chyba jednak sobie odpuszczę i nie będę śmiecił kodu kosztem kilku nanosekund (a może nawet nie)

Offline ArekBal

  • Użytkownik

# Luty 23, 2011, 16:12:20
Jakbyś dalej szedł tą ścieżką to byś int i, j, k trzymał jako globalne, a to krótka droga do piekła.
Tak w ogóle to czym mniej pamięci wrzucasz na tzw. stos wewnątrz pętli tym lepiej lokalną(typ prosty, malutki) tworzyć tam.

Bo mozliwości są bodajże dwie:
Albo ci trafi na stos, albo do któregoś rejestru. Na to drugie mała szansa (bo zazwyczaj czymś już wewnątrz pętli ten rejestr zapełnisz, ale jak jesteś pewien że się uda, to lepiej wewnątrz dokonywać cudów.

Tak mi się wydaje. To trzeba zwyczajnie sprawdzić.

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Luty 23, 2011, 16:27:32
Cytuj
Jakbyś dalej szedł tą ścieżką to byś int i, j, k trzymał jako globalne, a to krótka droga do piekła.
Globalne będą wolniejsze.

Offline ArekBal

  • Użytkownik

# Luty 23, 2011, 16:30:32
Domyślam się, ale mógłbyś to uzasadnić. Czy wg. ciebie
globalna będzie wolniejsza niż jakaś zmienna klasy.

Offline lukasyno

  • Użytkownik

# Luty 23, 2011, 16:38:56
Jakbyś dalej szedł tą ścieżką to byś int i, j, k trzymał jako globalne, a to krótka droga do piekła.
Tak w ogóle to czym mniej pamięci wrzucasz na tzw. stos wewnątrz pętli tym lepiej lokalną(typ prosty, malutki) tworzyć tam.

Bo mozliwości są bodajże dwie:
Albo ci trafi na stos, albo do któregoś rejestru. Na to drugie mała szansa (bo zazwyczaj czymś już wewnątrz pętli ten rejestr zapełnisz, ale jak jesteś pewien że się uda, to lepiej wewnątrz dokonywać cudów.

Tak mi się wydaje. To trzeba zwyczajnie sprawdzić.

mądrze prawisz(mądrze brzmi), ale w rzeczywistość jest inaczej :) zmienne poza pętla są szybsze właśnie zrobiłem dokładny test i przy obiegu pętli 100 * 100 * 100 * 20 (tak wiem ze to dużo, ale tylko przy duzym liczniku moglem zarysować różnice) i 30 zmiennych różnica to ok ~70ms....
od początku wydawało mi się to logiczne, przecież proces odczytania zmiennej z pamięci (i przypisanie tam wartości) wydaje się logicznie szybszy niż stworzenie zmiennej (wrzucenie gdzieś na stos) i ponowne przypisanie/odczytanie (mimo ze to jakaś "lokalna" pamięć to i tak jest wolniejsze).

co ciekawe stale są o dużo szybsze od zmiennych (wiedziałem ze są ale różnica szybkości była o 100%! w stosunku do zmiennych)

Offline lukasyno

  • Użytkownik

# Luty 23, 2011, 16:40:14
BTW zmienne typu int testowalem :)

Offline Oti

  • Użytkownik

# Luty 23, 2011, 16:41:07
Cytuj
Jakbyś dalej szedł tą ścieżką to byś int i, j, k trzymał jako globalne, a to krótka droga do piekła.
Globalne będą wolniejsze.
No i przy rekurencji(a tak na dobrą sprawę, to przy posrednim zagnieżdżaniu pętel) mogą być niespodzianki.

Ja dla pewnosci w większosci przypadków takie zmienne pomocnicze deklaruję przed pętlą-nie mam czasu ani ochoty zastanawiać się, czy kompilator mi to zoptymalizuje.
« Ostatnia zmiana: Luty 23, 2011, 16:44:05 wysłana przez Oti »

Offline Krzysiek K.

  • Redaktor
    • DevKK.net

# Luty 23, 2011, 16:50:38
Cytuj
Domyślam się, ale mógłbyś to uzasadnić.
Powód prosty: przy wyjściu z funkcji, oraz przed każdym wejściem do innej nie-inlinowanej funkcji wartość zmiennej globalnej trzeba zapisać tam, gdzie być powinna. Lokalnych nie trzeba, bo wiadomo z góry, że tylko ta jedna funkcja ma do nich dostęp.

Cytuj
Czy wg. ciebie globalna będzie wolniejsza niż jakaś zmienna klasy.
Globalne mogą być szybsze od zmiennych klasy. Dostęp do zmiennej klasy to przecież ni mniej ni więcej, co dostęp to this[offset], a koniecznośc zapisywania danych pozostaje ta sama.