2014-06-11 36 views
15

Aby zmniejszyć czas transferu z hosta do urządzenia dla mojej aplikacji, chcę użyć przypiętej pamięci. NVIDIA's best practices guide proponuje bufory mapowania i zapisywania danych za pomocą następującego kodu:Używanie przypiętej pamięci/zmapowanej pamięci w OpenCL

cDataIn = (unsigned char*)clEnqueueMapBuffer(cqCommandQue, cmPinnedBufIn, CL_TRUE,CL_MAP_WRITE, 0, memSize, 0, NULL, NULL, NULL); 

for(unsigned int i = 0; i < memSize; i++) 
{ 
    cDataIn[i] = (unsigned char)(i & 0xff); 
} 

clEnqueueWriteBuffer(cqCommandQue, cmDevBufIn, CL_FALSE, 0, 
szBuffBytes, cDataIn, 0, NULL, NULL); 

Intel's optimization guide zaleca stosowanie połączeń do clEnqueueMapBuffer i clEnqueueUnmapBuffer zamiast wywołań clEnqueueReadBuffer lub clEnqueueWriteBuffer.

Jaki jest właściwy sposób użycia przypiętej pamięci/zmapowanej pamięci? Czy konieczne jest zapisanie danych przy użyciu enqueueWriteBuffer lub czy program EnqueueMapBuffer jest wystarczający?

Czym różni się CL_MEM_ALLOC_HOST_PTR od CL_MEM_USE_HOST_PTR?

Odpowiedz

10

Jest to interesujący temat, który bardzo niewiele osób szczegółowo. Postaram się dokładnie określić, jak to działa.

Przypięta pamięć oznacza pamięć, która oprócz obecności w urządzeniu istnieje w hoście, więc możliwe jest zapisanie DMA między tymi 2 pamięciami. Zwiększenie wydajności kopiowania. Dlatego potrzebuje CL_MEM_ALLOC_HOST_PTR w parametrach tworzenia bufora.

Z drugiej strony, CL_MEM_USE_HOST_PTR zajmie wskaźnik hosta do tworzenia bufora, jest niejasne przez specyfikację, jeśli może to być lub nie może być przypięta pamięć. Ale ogólnie rzecz biorąc, NIE powinien być to pamięć przypięta, utworzona w ten sposób, ponieważ wskaźnik hosta nie został zarezerwowany przez interfejs OpenCL API i nie jest jasne, gdzie znajduje się w pamięci.


Odnośnie mapy/pytania do przeczytania. Zarówno są w porządku. I dadzą taką samą wydajność. Różnica między obu technik jest to, że:

  • Dla Mapa/unmap: Musisz map przed pisania/czytania i unmap później. W ten sposób zapewnisz spójność danych. Są to wywołania interfejsu API i potrzeba czasu na ich ukończenie, a także na asynchronię. Dobrą rzeczą jest to, że nie musisz trzymać niczego innego niż obiektu bufora.
  • Dla mapy + odczyt/zapis: Przy tworzeniu strefy pamięci należy wykonać Mapę i zapisać wartość wskaźnika. Następnie, po zniszczeniu bufora, musisz najpierw odświeżyć, a następnie zniszczyć. Musisz cały czas trzymać buffer+Mapped_Buffer. Dobrą rzeczą jest to, że możesz teraz tylko clEnqueueRead/Write do tego zmapowanego wskaźnika. Interfejs API zaczeka, aż przypięte dane będą spójne, a następnie rozważ to. Jest łatwiejszy w użyciu, ponieważ wygląda jak zrobienie mapy + odpakowanie w jednym ujęciu.

tryb Read/Write jest łatwiejszy w użyciu, specjalnie dla powtarzalne czyta, ale nie jest tak wszechstronny, jak ręcznego wyboru mapy, ponieważ można nie napisać read only mapę, ani czytać write only mapę. Ale do ogólnego użytku zmienne, które są czytane, nigdy nie zostaną zapisane i viceversa.


Moje zrozumienie jest, że Intel zalecenie odnosi się do "Użyj mapy, a nie zwykły Read/Write", zamiast "Podczas korzystania z Map, nie używaj odczyt/zapis na zmapowany wskazówek" .

Czy sprawdziłeś tę rekomendację nVIDII nad Intel HW? Myślę, że to powinno działać, ale nie wiem, czy rzeczywiście operacja byłaby optymalna (tak jak w AMD czy nVIDIA HW).

+0

To naprawdę dziwne, że musisz użyć clEnqueueWriteBuffer() wraz z Map/Unmap. Odkąd robisz Mapę, a następnie zmieniasz wskaźnik hosta, zmieniasz dane zarówno CPU, jak i GPU. Kiedy zrobisz mapowanie, dane zostaną zsynchronizowane pomiędzy procesorem a stroną GPU. Nie rozumiem potrzeby wykonywania clEnqueueWriteBuffer między MAP + zmiana cDataIn i UNMAP. Bardzo dziwne... –