Biorąc pod uwagę przewidywania gałęzi, a także efekt optymalizacji kompilatora, który kod oferuje lepszą wydajność?
Zauważ, że bRareExceptionPresent stanowi rzadki warunek. To nie jest normalna ścieżka logiki.
/* MOST COMMON path must branch around IF clause */
bool SomeFunction(bool bRareExceptionPresent)
{
// abort before function
if(bRareExceptionPresent)
{
return false;
}
.. function primary body ..
return true;
}
/* MOST COMMON path does NOT branch */
bool SomeFunction(bool bRareExceptionPresent)
{
if(!bRareExceptionPresent)
{
.. function primary body ..
}
else
{
return false;
}
return true;
}
optimization
theory
dyasta
źródło
źródło
Odpowiedzi:
W dzisiejszym świecie nie ma to większego znaczenia, jeśli w ogóle.
Prognozowanie gałęzi dynamicznych (coś, o czym myślano przez dziesięciolecia (patrz Analiza obciążeń systemu schematów prognozowania dynamicznego opublikowane w 1996 r.)) Jest dość powszechnym miejscem.
Przykład tego można znaleźć w procesorze ARM. Z centrum informacyjnego uzbrojenia w prognozach gałęzi
Powstaje zatem pytanie „czym jest dynamiczne przewidywanie gałęzi w procesorze uzbrojenia?” Ciągły odczyt przewidywania gałęzi dynamicznej pokazuje, że wykorzystuje on 2-bitowy schemat predykcji (opisany w artykule) budujący informacje o tym, czy gałąź jest silnie, czy słabo pobrana, czy nie.
Z biegiem czasu (a czasem mam na myśli kilka przejść przez ten blok) gromadzi to informacje o tym, w którą stronę pójdzie kod.
W przypadku przewidywania statycznego sprawdza, jak wygląda sam kod i w jaki sposób gałąź jest tworzona w teście - do poprzedniej instrukcji lub kolejnej w kodzie:
Jak wspomniał Sparky, opiera się to na zrozumieniu, że pętle częściej niż nie, pętle. Pętla rozgałęzia się do tyłu (ma gałąź na końcu pętli, aby ponownie uruchomić ją u góry) - zwykle robi to.
Niebezpieczeństwo próby odgadnięcia kompilatora polega na tym, że nie wiesz, jak ten kod zostanie skompilowany (i zoptymalizowany). I w większości nie ma to znaczenia. W przypadku przewidywania dynamicznego dwukrotnie funkcja ta przewiduje przeskakiwanie instrukcji wartownika w celu przedwczesnego powrotu. Jeśli wydajność dwóch przepłukanych rurociągów ma krytyczną wydajność, należy martwić się innymi sprawami.
Czas potrzebny do odczytania jednego stylu nad drugim ma większe znaczenie - oczyszczenie kodu, aby człowiek mógł go odczytać, ponieważ kompilator dobrze sobie poradzi, bez względu na to, jak niechlujny lub wyidealizowany zostanie kod.
źródło
Rozumiem, że gdy procesor po raz pierwszy napotka gałąź, będzie przewidywał (jeśli jest obsługiwany), że gałęzie do przodu nie są pobierane, a gałęzie do tyłu są. Uzasadnieniem tego jest założenie, że pętle (które zwykle rozgałęziają się do tyłu) są przyjmowane.
Na niektórych procesorach możesz podpowiedzieć w instrukcji asemblera, która ścieżka jest bardziej prawdopodobna. Szczegóły tego w tej chwili mi uciekają.
Ponadto niektóre kompilatory C obsługują również przewidywanie gałęzi statycznych, dzięki czemu można powiedzieć kompilatorowi, która gałąź jest bardziej prawdopodobna. Z kolei może zreorganizować wygenerowany kod lub użyć zmodyfikowanych instrukcji, aby skorzystać z tych informacji (a nawet po prostu zignorować je).
Mam nadzieję że to pomoże.
źródło
__builtin_expect
?