2016-06-09 3 views
1

많은 컴퓨팅 코어에서 실행될 수있는 많은 CPU 코어에서 실행되는 대규모 코드가 있습니다. 코드는 C++이며 OpenMPI와 병렬 처리됩니다.복잡한 개체를위한 MPI 공유 메모리

내 코드에는 각 MPI 프로세스에서 읽는 매우 큰 개체 (~ 10GB RAM 사용)가 있습니다. 이 객체는 매우 가끔 업데이트됩니다 (데이터 파일을 읽는 것만으로 단일 프로세스로 수행 할 수 있습니다).

지금까지 내가 해왔 던 것은 각 MPI 프로세스에이 개체의 복사본을 제공하는 것입니다. 하지만 그건 내가 심각하게 RAM 제한적이며 내 노드의 전체 CPU 성능을 사용할 수 없다는 것을 의미합니다. 그래서 저는 MPI 3 사양에서 공유 메모리에 대해 읽었습니다.

제 질문은 : MPI 프로세스에서 복잡한 객체를 공유하는 가장 좋은 방법은 무엇입니까? 모든 예제에서 MPI 공유 메모리 창을 만들어 간단한 데이터 구조 (float, ints 배열 등)를 교환하는 데 사용합니다. 내 전역 개체는 여러 멤버 변수를 포함하는 사용자 지정 클래스 형식이며 일부는 포인터이고 그 중 다수는 다른 복잡한 클래스 형식입니다. 따라서, 나는 단지 MPI_Win_allocate_shared을 호출하고 내 복잡한 객체의 주소를 전달할 수 없기 때문에, 특히 멤버 변수에 대한 모든 정보를 공유하고자하므로 (특히, 기본 값을 공유하고 싶습니다. 포인터 타입 멤버 변수 - 즉, MPI 프로세스에서 "딥 카피 (deep copy)"를 공유하며 각 프로세스에서 모든 가상 메모리 주소가 정확합니다.)

MPI 공유 메모리와 함께 "깊은 공유"를 달성 할 수 있습니까? 그렇다면 그렇게하는 "모범 사례"가 있습니까? 아니면 다른 라이브러리 (예 : 프로세스 간 프로세스 향상)를 사용하면이 방법이 더 실현 가능할 것입니까?

P. 좋은 해결책을 찾을 수 없다면, 하이브리드 MPI + pthreads 접근 방식을 사용하게 될 것입니다. 여기서는 pthread가있는 각 노드에이 전역 객체를 쉽게 가질 수 있습니다. 하지만 정말 우아한 MPI 전용 솔루션을 찾고 싶습니다.

+0

공유 메모리가 정확히 동일한 기본 주소에 매핑되어 있지 않은 한 프로세스의 가상 주소 공간에 대한 포인터는 다른 프로세스에서 의미가 없습니다. 당신이 원하는 것은 불가능한 것이 아닙니다 : 모든 프로세스에서 모든 메모리 구멍의 교차점에 큰 구멍을 발견하고'mmap()'을 선호 주소로 호출하는 것이 중요하지만, 이식성이없고 각각의 때마다. 적절한 해결책은 상대 포인터를 사용하고 역 참조하기 전에 각 포인터의 값에 기본 주소를 추가하는 것입니다. –

+0

기본 통신자의 프로세스 그룹이 둘 이상의 공유 메모리 노드에 걸쳐있을 때'MPI_Win_allocate_shared'를 사용할 수 없음에 유의하십시오. 그런 경우 MPI RMA를 대신 사용해야합니다. –

+0

당신이 말했듯이 RMA를 사용하여 노드 당 하나의 개체 복사본을 얻은 다음 각 노드에서 공유 메모리를 사용하므로 노드 당 하나의 개체 복사본 만 있습니다 (내 메모리 사용을 유지하기에 충분합니다) 최소한 - 1 노드에 n 개의 복사본이 없도록해야합니다.) 또한, 보장되고 이식 가능한 솔루션을 찾고 있습니다.이 코드는 안정적으로 작동해야하며 이상적으로는 Linux와 Windows에서 모두 실행해야합니다. "적절한 해결책은 ..."이라고 말하면 그 기술이 내 문제를 해결하는 방법을 더 설명 할 수 있습니까? 모든 의사/예제 코드도 도움이됩니다. 감사! – davewy

답변

1

기계 경계를 넘고 (많은 기계에서 노드를 사용하는 경우) 목표를 달성하기위한 쉬운 방법이 없습니다. Windows 또는 Linux 컴퓨터 만 사용하는 경우 (혼합하지 않음) 가상 메모리에 일부 공유 리소스를 연결하는 방식으로 해킹 할 수 있습니다 (효율적인 방법으로 시스템 API 사용). 다른 방법은 대형 객체에 대한 사용자 지정 직렬화/직렬화 해제 코드를 만들고 이진 배열로 메모리에 저장하는 것입니다 (같은 시스템의 프로세스간에 공유하기 위해). 문제는 "메모리 덤프"만 저장하려는 경우 큰/작은 엔디안입니다. 전용 MPI API를 사용하는 경우 모든 엔디안 (및 데이터 표시 문제)이 올바르게 지원됩니다. ... 추가

PVM 더 나은 같은 시나리오를 지원하는 경우 나는 순간 모르겠지만, MPI의 경우에 나는 (프로세스 만 사이에 몇 가지 액세스 키를 공유) 동일한 시스템에서 VM의 직접 사용을 시작할 수 있습니다 답변 1 :

한 대의 컴퓨터에서는 간단하게 생각해야합니다 (Windows를 사용하므로이 플랫폼에 집중할 것입니다). 이런 경우에는 엔디안 문제와 데이터 정렬이 중요하지 않습니다. 동일한 옵션으로 모든 내용을 컴파일하고 동일한 하드웨어에서 사용한다고 가정하기 때문입니다. 목표를 달성하는 가장 쉬운 방법은 가상 메모리에 적절히 이름 붙여진 파일을 매핑하는 것입니다 (다른 개체에 대해 많은 매핑을 만들 때까지는 이름이 중요하지 않습니다.이 경우 일관성을 위해 명명 스키마가 필요합니다). Sample is here for instance.

가상 메모리를 만든 후에는 모든 개체 데이터를 거기에 배치하십시오 (이전 학교 memcpy 또는 배치 생성자라고 함). 모든 데이터가 이미 가상 메모리에서 사용 가능할 때, 동일한 기계의 모든 프로세스/노드에 몇 가지 추가 속성이있는 파일 이름을 보내면됩니다.가상 메모리 공간의 시작 부분에 오브젝트에 대한 포인터 (예 : 할당 주소 델타 포함)가있는 배열을 여러 개 배치하여 하나 이상의 오브젝트가있는 경우 모든 관련 오브젝트를 쉽게 연결할 수 있습니다 (이러한 경우에는 vm의 첫 번째 요소 배열에 elems의 수를 포함해야합니다 - 단지 몇 가지 아이디어 일뿐입니다). 가상 메모리를 모든 프로세스의 동일한 가상 주소에 매핑 할 수 있으므로 포인터가 마음에 들지 않으면 포인터를 관리 할 필요가 없습니다. 이런 경우 포인터가있는 배열은 필요하지 않습니다!

가상 메모리를 사용하면 메모리 페이지 사용을 최적화 할 수 있으므로 큰 데이터 객체가있는 경우를 대비하여 10GB의 RAM을 절약 할 수 있습니다.

BTW : Windows는 섹션의 일부 switch과 공유하는 직접 메모리 페이지를 지원합니다. CPP에는 such support이 있습니다.

+0

단순함을 위해 하나의 컴퓨터로 작업하고 있다고 가정 해 보겠습니다. (여러 머신의 경우, 위에서 언급 한 Hristo와 같은 일을 할 것입니다. RMA를 사용하여 노드 당 하나의 객체 사본을 얻은 다음 공유 메모리를 사용하여 해당 노드의 모든 procs 중에서 사본을 공유합니다.) 하나의 노드에서만 바이너리 어레이 솔루션이 어떻게 작동하는지 더 자세히 설명 할 수 있습니까? 전체 주소를 가져 와서 데이터를 저장하려면 어떻게해야합니까? 어떻게하면 원하는 수업 유형으로 캐스팅 할 수 있을까요? – davewy

+0

"추가 답변 1"섹션에서 답변을 추가했습니다. 내 아이디어가 무엇인지 분명히 알기를 바랍니다 ... –