Często znane jako likely
i unlikely
makra pomagają kompilatorowi wiedzieć, czy if
zwykle będzie wprowadzane czy pomijane. Używanie go powoduje pewne (raczej niewielkie) ulepszenia wydajności.
Zacząłem ich używać niedawno i nie jestem pewien, jak często należy korzystać z takich wskazówek. Obecnie używam go do sprawdzania błędów if
, które zwykle są oznaczone jako unlikely
. Na przykład:
mem = malloc(size);
if (unlikely(mem == NULL))
goto exit_no_mem;
Wydaje się to w porządku, ale sprawdzanie błędów if
zdarza się dość często iw konsekwencji użycie wspomnianych makr.
Moje pytanie brzmi, czy to zbyt wiele, aby mieć likely
i unlikely
makra na każdym Sprawdzanie błędów if
?
Skoro już tu jesteśmy, jakie inne miejsca są często używane?
W moim obecnym użyciu znajduje się w bibliotece, która dokonuje abstrakcji z podsystemu czasu rzeczywistego, więc programy stałyby się przenośne między RTAI, QNX i innymi. To powiedziawszy, większość funkcji jest raczej niewielka i bezpośrednio wywołuje jedną lub dwie inne funkcje. Wiele z nich to nawet static inline
funkcje.
Przede wszystkim nie jest to aplikacja, którą mógłbym profilować. Identyfikacja „wąskich gardeł” nie ma sensu, ponieważ jest to biblioteka, a nie samodzielna aplikacja.
Po drugie, jest to coś w rodzaju „wiem, że to mało prawdopodobne, równie dobrze mogę to powiedzieć kompilatorowi”. Nie próbuję aktywnie optymalizować if
.
źródło
likely
iunlikely
istnieje i co robią. Nie znalazłem niczego, co faktycznie sugerowałoby, kiedy i gdzie najlepiej ich używać.Odpowiedzi:
Czy potrzebujesz wydajności tak bardzo, że zechcesz w ten sposób skazić kod? To niewielka optymalizacja.
Jeśli nie potrafisz odpowiedzieć
yes
na wszystkie powyższe pytania , nie przejmuj się takimi rzeczami.Edycja: w odpowiedzi na edycję. Nawet jeśli nie możesz profilować, zwykle możesz oszacować punkty aktywne. Funkcja alokacji pamięci, która jest wywoływana przez wszystkich, jest dobrym kandydatem, zwłaszcza że wymaga tylko jednego użycia makra do pracy dla całej biblioteki.
źródło
(un)likely
makro jest rzadko używane i tylko w kodzie krytycznym pod względem wydajności? Czy używanie go często jest „złą praktyką”, czy po prostu „niepotrzebne”?if (likely(x==2 || x==3)) doOneThing(); else switch(x) { ... }
, mógłby ocenić, że użycieif
przez programistę wartości 2 i 3 nie było jedynie konsekwencją tego, że programista nie wiedział, że C może skojarzyć dwiecase
etykiety z jednym programem obsługi.Jeśli piszesz dla x86 / x64 (i nie używasz 20-letnich procesorów), wzrost wydajności przy użyciu __builtin_expect () będzie nieznaczny, jeśli w ogóle. Powodem tego jest fakt, że współczesne procesory x86 / x64 (choć nie w 100% pewna co do Atomu) mają dynamiczne przewidywanie gałęzi, więc w zasadzie procesor „uczy się” o gałęzi, która jest pobierana częściej. Oczywiście te informacje można przechowywać tylko dla ograniczonej liczby oddziałów, jednak możliwe są tylko dwa przypadki. Jeśli (a) jest to gałąź „często używana”, to twój program skorzysta z tej dynamicznej prognozy gałęzi, a jeśli (b) jest to gałąź „rzadka”, naprawdę nie zobaczysz żadnego realistycznego spadku wydajności z powodu nieprzewidzianych takie rzadkie gałęzie (20 cykli procesora błędnego przewidywania gałęzi nie jest ZBYT złe, jeśli zdarzy się to raz na niebieskim księżycu).
Uwaga: NIE oznacza to, że na współczesnym x86 / x64 znaczenie nieprzewidywalności gałęzi spadło: każda gałąź z 50-50 szansą na skok-nojump nadal będzie podlegać karze (IIRC 10-20 cykli CPU), więc w wewnętrznych pętlach gałęzie mogą wciąż trzeba unikać. Jest to tylko ważność __builtin_expect () na x86 / x64, która się zmniejszyła (IIRC, około 10-15 lat temu) - głównie z powodu dynamicznego przewidywania gałęzi.
NB2: dla innych platform innych niż x86 / x64, YMMV.
źródło
unlikely
adnotacji.