Wiem, że nie zapytałeś (i prawdopodobnie nie potrzebujesz kazania o właściwym traktowaniu pamięci podręcznych, ale pomyślałem, że i tak wesprze moje dwa centy.) Należy zauważyć, że wszystko to dotyczy tylko gorącego kodu. Pamiętaj, że przedwczesna optymalizacja jest źródłem wszelkiego zła:
Jak podkreślono w komentarzach, najlepszym sposobem jest posiadanie pojemników z rzeczywistymi danymi, mówiąc ogólnie, płaskie struktury danych są znacznie lepsze niż "wskaźnik spaghetti", nawet jeśli musisz skopiować pewne dane i/lub zapłacić cenę za zmianę rozmiaru/przeniesienie/defragmentację struktur danych. tablica danych) opłacają się tylko wtedy, gdy uzyskujesz do nich dostęp liniowo i sekwencyjnie przez większość czasu.
Jednak ta strategia może nie zawsze być użyteczna. Zamiast rzeczywistych danych liniowych można użyć innych strategii, takich jak wykorzystanie alokatorów puli i iteracja nad pulami, zamiast na wektorach zawierających wskaźniki. Ma to oczywiście swoje wady i może być nieco bardziej skomplikowane.
Jestem pewien, że już o tym wiesz, ale warto jeszcze raz wspomnieć, że jedną z najskuteczniejszych technik uzyskiwania jak najwięcej z pamięci podręcznej jest posiadanie mniejszych danych! W powyższym kodzie, jeśli możesz uciec z int16_t
zamiast int32_t
, zdecydowanie powinieneś to zrobić.Powinieneś spakować swoje liczne numery i znaczniki i wyliczyć w polach bitowych, użyć indeksów zamiast wskaźników (szczególnie w systemach 64-bitowych), używać wartości skrótów o stałym rozmiarze w strukturach danych zamiast łańcuchów, itp.
Teraz, na temat głównego pytania, czy procesor może śledzić losowe wskaźniki i przenosić dane do pamięci podręcznej, zanim będą potrzebne. W bardzo ograniczonym zakresie tak się dzieje. Jak zapewne wiecie, nowoczesne procesory wykorzystują wiele sztuczek, aby zwiększyć ich prędkość (tj. Podnoszą wskaźnik wycofywania instrukcji). Sztuczki takie jak bufor sklepu, wykonywanie poza kolejnością, rurociągi superskalarne, wiele jednostek funkcjonalnych każdego rodzaju, oddział przewidywania itp. W większości przypadków te sztuczki pomagają CPU w wykonaniu wykonywania instrukcji, nawet jeśli aktualne instrukcje zostały zatrzymane lub trwają zbyt długo. W przypadku obciążeń pamięci (co jest najwolniejszą czynnością, iff dane nie znajdują się w pamięci podręcznej) oznacza to, że procesor powinien jak najszybciej dostać się do instrukcji, obliczyć adres i zażądać danych z kontrolera pamięci. Jednak kontroler pamięci może mieć tylko bardzo ograniczoną liczbę zaległych żądań (zwykle dwa dni, ale nie jestem pewien.) Oznacza to, że nawet jeśli CPU zrobił bardzo wyrafinowane rzeczy, aby spojrzeć w przyszłość do innych lokalizacji pamięci (np. elementy twojego wektora posPointers
) i wywnioskuj, że są to adresy nowych danych, których twój kod będzie potrzebował, nie mógł się bardzo daleko wyprzedzić, ponieważ kontroler pamięci może mieć tylko tyle zgłoszeń oczekujących.
W każdym razie, AFAIK, nie sądzę, żeby procesory faktycznie to jeszcze robiły. Zauważ, że jest to trudny przypadek, ponieważ adresy twoich losowo rozmieszczonych lokalizacji pamięci są same w pamięci (w przeciwieństwie do bycia w rejestrze lub obliczalne z zawartości rejestru). Jeśli procesory to zrobiły, to nie i tak ma to znaczny wpływ z powodu ograniczeń interfejsu pamięci.
Wydana przeze mnie technika pobierania wstępnego wydaje mi się ważna i widziałem, że była używana, ale daje zauważalny efekt tylko wtedy, gdy procesor ma coś do zrobienia, czekając na przyszłe dane. Inkrementowanie trzech liczb całkowitych zajmuje o wiele mniej czasu niż ładowanie 12 bajtów z pamięci (w rzeczywistości ładowanie jednej linii pamięci podręcznej), a zatem nie będzie to miało większego znaczenia dla czasu wykonywania. Ale gdybyś miał coś wartościowego i cięższego do nałożenia na przedrostki pamięci (na przykład obliczenia złożonej funkcji, która nie wymaga danych z pamięci!), Możesz uzyskać bardzo dobre przyspieszenia. Widzisz, czas przejścia przez powyższą pętlę jest zasadniczo sumą czasu wszystkich chybień w pamięci podręcznej; a otrzymujesz przyrosty współrzędnych i księgowanie w pętli za darmo. Wygrałbyś więcej, gdyby darmowe rzeczy były bardziej wartościowe!
Kod taki jak ten jest mało prawdopodobny, jest bardzo nieprzystępny i nie powoduje automatycznej wektoryzacji. Prosta poprawka to 'std :: vector', zrób kopię. –
Utworzenie tej kopii byłoby równie niewydajne w pamięci podręcznej. Nadal musisz zbierać obiekty z całej pamięci. A jeśli wyniki muszą być przechowywane z powrotem, wykonanie kopii byłoby jeszcze gorsze. – MSalters