Gdy obliczenia o ograniczonej przepustowości pamięci są wykonywane w środowiskach pamięci współużytkowanej (np. Wątkowych przez OpenMP, Pthreads lub TBB), pojawia się dylemat, jak zapewnić, aby pamięć była prawidłowo rozdzielona na pamięć fizyczną , tak aby każdy wątek w większości uzyskiwał dostęp do pamięci na „lokalna” magistrala pamięci. Chociaż interfejsy nie są przenośne, większość systemów operacyjnych ma sposoby ustawiania powinowactwa wątków (np. W pthread_setaffinity_np()
wielu systemach POSIX, sched_setaffinity()
Linux, SetThreadAffinityMask()
Windows). Istnieją również biblioteki takie jak hwloc do określania hierarchii pamięci, ale niestety większość systemów operacyjnych nie zapewnia jeszcze sposobów ustawiania zasad pamięci NUMA. Linux jest godnym uwagi wyjątkiem, z libnumaumożliwianie aplikacji do manipulowania polityką pamięci i migracją stron przy ich szczegółowości (w głównej wersji od 2004 roku, a więc szeroko dostępne). Inne systemy operacyjne oczekują, że użytkownicy będą przestrzegać domyślnej zasady „pierwszego dotknięcia”.
Praca z zasadą „pierwszego dotknięcia” oznacza, że osoba dzwoniąca powinna tworzyć i rozpowszechniać wątki z dowolnym powinowactwem, którego zamierzają użyć później, kiedy po raz pierwszy pisze do świeżo przydzielonej pamięci. (Bardzo niewiele systemów jest skonfigurowanych w taki sposób, że malloc()
faktycznie wyszukuje strony, po prostu obiecuje je znaleźć, gdy zostaną faktycznie uszkodzone, być może przez różne wątki.) Oznacza to, że przydział calloc()
lub natychmiastowe zainicjowanie pamięci po użyciu przydziału memset()
jest szkodliwe, ponieważ może powodować błędy cała pamięć na szynę pamięci rdzenia, na którym działa wątek alokujący, co prowadzi do najmniejszego pasma przepustowości pamięci, gdy pamięć jest dostępna z wielu wątków. To samo dotyczy new
operatora C ++ , który nalega na zainicjowanie wielu nowych alokacji (npstd::complex
). Kilka uwag na temat tego środowiska:
- Alokacja może być „kolektywna dla wątków”, ale teraz alokacja staje się mieszana w modelu wątków, co jest niepożądane w przypadku bibliotek, które mogą być zmuszone do interakcji z klientami używającymi różnych modeli wątków (być może każda z własnymi pulami wątków).
- RAII jest uważane za ważną część idiomatycznego C ++, ale wydaje się być aktywnie szkodliwe dla wydajności pamięci w środowisku NUMA. Umieszczania
new
można używać z pamięcią przydzieloną przezmalloc()
lub z procedurlibnuma
, ale zmienia to proces przydzielania (który moim zdaniem jest konieczny). - EDYCJA: Moje wcześniejsze stwierdzenie o operatorze
new
było niepoprawne, może obsługiwać wiele argumentów, patrz odpowiedź Chetana. Uważam, że nadal istnieje obawa, aby biblioteki lub kontenery STL używały określonego powinowactwa. Wiele pól może być spakowanych i może być niewygodne upewnienie się, że np.std::vector
Realokacja następuje przy aktywnym poprawnym menedżerze kontekstu. - Każdy wątek może alokować i uszkadzać własną pamięć prywatną, ale indeksowanie do sąsiednich regionów jest bardziej skomplikowane. (Rozważ rzadki iloczyn macierzowo-wektorowy z rzędem partycji macierzy i wektorów; indeksowanie nie posiadanej części x wymaga bardziej skomplikowanej struktury danych, gdy x nie jest ciągły w pamięci wirtualnej.)
Czy jakieś rozwiązania dotyczące alokacji / inicjalizacji NUMA są uważane za idiomatyczne? Czy pominąłem inne krytyczne błędy?
(Nie mam na myśli mojego C ++ przykłady sugerować nacisk na ten język, jednak C ++ język koduje pewne decyzje o zarządzaniu pamięcią, że język jak C nie, więc nie wydaje się być większy opór, kiedy sugeruje, że programistów C ++ zrobić ci rzeczy inaczej.)