나는이 질문을하기에는 불리하다고 생각한다. 그러나 나 자신을 도울 수 없었다. 각 노드에 16 개의 코어가있는 노드가 100 개인 클러스터가 있다고 가정합니다. 통신 패턴이 이미 알려진 mpi 응용 프로그램이 있고 클러스터 토폴로지 (노드 간 홉 거리)도 알고 있습니다. 이제 네트워크상의 경합을 줄이는 노드 매핑 프로세스를 알고 있습니다. 예를 들어 프로세스 대 노드 맵핑은 10-> 20,30-> 90입니다. 순위 10의 프로세스를 노드 -20에 어떻게 매핑합니까? 도와주세요.특정 노드에 MPI 프로세스 매핑하기
1
A
답변
2
어떤 종류의 대기열 시스템에도 제약이 없으면 자신의 machinefile
을 생성하여 순위 대 노드 매핑을 제어 할 수 있습니다. 파일 my_machine_file
이 다음에게 1,600 선
node001
node002
node003
....
node100
node001
node002
node003
....
node100
...
[repeat 13 more times]
...
node001
node002
node003
....
node100
이 매핑에 해당하는 것이있는 경우
는 예를 들어0-> node001, 1 -> node002, ... 99 -> node100, 100 -> node001, ...
당신은
mpirun -machinefile my_machine_file -n 1600 my_app
와 응용 프로그램을 실행해야 할 때를 응용 프로그램에 1600 개가 넘는 프로세스가 필요합니다. machinef를 편집 할 수 있습니다. 이에 따라.
클러스터 관리자는 아마도 상호 연결의 토폴로지를 고려한 노드의 번호를 매겼을 것입니다. 그러나 클러스터 토폴로지를 신중하게 활용하여 성능이 현저히 향상되는 것으로 나타났습니다 (10 % -20 %의 순서). (참고 문헌).
참고 :mpirun
으로 MPI 프로그램을 시작하는 것은 표준화되거나 이식되지 않습니다. 그러나 여기서 질문은 명확하게 특정 컴퓨팅 클러스터 및 특정 구현 (OpenMPI)과 관련이 있으며 휴대용 솔루션을 요청하지 않습니다.
1
이 파티에 조금 늦지 만, 여기에 C + +의 서브 루틴이 있습니다.이 서브 루틴은 노드 통신자와 마스터 커뮤니케이터 (노드의 마스터 만 해당)뿐만 아니라 각각의 크기와 순위를 제공합니다. 서투르지 만 불행히도 더 좋은 방법을 찾지 못했습니다. 운좋게도 벽 시간에 약 0.1 초를 추가합니다. 어쩌면 당신이나 다른 누군가가 그것을 사용하게 될 것입니다.
#define MASTER 0
using namespace std;
/*
* Make a comunicator for each node and another for just
* the masters of the nodes. Upon completion, everyone is
* in a new node communicator, knows its size and their rank,
* and the rank of their master in the master communicator,
* which can be useful to use for indexing.
*/
bool CommByNode(MPI::Intracomm &NodeComm,
MPI::Intracomm &MasterComm,
int &NodeRank, int &MasterRank,
int &NodeSize, int &MasterSize,
string &NodeNameStr)
{
bool IsOk = true;
int Rank = MPI::COMM_WORLD.Get_rank();
int Size = MPI::COMM_WORLD.Get_size();
/*
* ======================================================================
* What follows is my best attempt at creating a communicator
* for each node in a job such that only the cores on that
* node are in the node's communicator, and each core groups
* itself and the node communicator is made using the Split() function.
* The end of this (lengthly) process is indicated by another comment.
* ======================================================================
*/
char *NodeName, *NodeNameList;
NodeName = new char [1000];
int NodeNameLen,
*NodeNameCountVect,
*NodeNameOffsetVect,
NodeNameTotalLen = 0;
// Get the name and name character count of each core's node
MPI::Get_processor_name(NodeName, NodeNameLen);
// Prepare a vector for character counts of node names
if (Rank == MASTER)
NodeNameCountVect = new int [Size];
// Gather node name lengths to master to prepare c-array
MPI::COMM_WORLD.Gather(&NodeNameLen, 1, MPI::INT, NodeNameCountVect, 1, MPI::INT, MASTER);
if (Rank == MASTER){
// Need character count information for navigating node name c-array
NodeNameOffsetVect = new int [Size];
NodeNameOffsetVect[0] = 0;
NodeNameTotalLen = NodeNameCountVect[0];
// build offset vector and total char count for all node names
for (int i = 1 ; i < Size ; ++i){
NodeNameOffsetVect[i] = NodeNameCountVect[i-1] + NodeNameOffsetVect[i-1];
NodeNameTotalLen += NodeNameCountVect[i];
}
// char-array for all node names
NodeNameList = new char [NodeNameTotalLen];
}
// Gatherv node names to char-array in master
MPI::COMM_WORLD.Gatherv(NodeName, NodeNameLen, MPI::CHAR, NodeNameList, NodeNameCountVect, NodeNameOffsetVect, MPI::CHAR, MASTER);
string *FullStrList, *NodeStrList;
// Each core keeps its node's name in a str for later comparison
stringstream ss;
ss << NodeName;
ss >> NodeNameStr;
delete NodeName; // node name in str, so delete c-array
int *NodeListLenVect, NumUniqueNodes = 0, NodeListCharLen = 0;
string NodeListStr;
if (Rank == MASTER){
/*
* Need to prepare a list of all unique node names, so first
* need all node names (incl duplicates) as strings, then
* can make a list of all unique node names.
*/
FullStrList = new string [Size]; // full list of node names, each will be checked
NodeStrList = new string [Size]; // list of unique node names, used for checking above list
// i loops over node names, j loops over characters for each node name.
for (int i = 0 ; i < Size ; ++i){
stringstream ss;
for (int j = 0 ; j < NodeNameCountVect[i] ; ++j)
ss << NodeNameList[NodeNameOffsetVect[i] + j]; // each char into the stringstream
ss >> FullStrList[i]; // stringstream into string for each node name
ss.str(""); // This and below clear the contents of the stringstream,
ss.clear(); // since the >> operator doesn't clear as it extracts
//cout << FullStrList[i] << endl; // for testing
}
delete NodeNameList; // master is done with full c-array
bool IsUnique; // flag for breaking from for loop
stringstream ss; // used for a full c-array of unique node names
for (int i = 0 ; i < Size ; ++i){ // Loop over EVERY name
IsUnique = true;
for (int j = 0 ; j < NumUniqueNodes ; ++j)
if (FullStrList[i].compare(NodeStrList[j]) == 0){ // check against list of uniques
IsUnique = false;
break;
}
if (IsUnique){
NodeStrList[NumUniqueNodes] = FullStrList[i]; // add unique names so others can be checked against them
ss << NodeStrList[NumUniqueNodes].c_str(); // build up a string of all unique names back-to-back
++NumUniqueNodes; // keep a tally of number of unique nodes
}
}
ss >> NodeListStr; // make a string of all unique node names
NodeListCharLen = NodeListStr.size(); // char length of all unique node names
NodeListLenVect = new int [NumUniqueNodes]; // list of unique node name lengths
/*
* Because Bcast simply duplicates the buffer of the Bcaster to all cores,
* the buffer needs to be a char* so that the other cores can have a similar
* buffer prepared to receive. This wouldn't work if we passed string.c_str()
* as the buffer, becuase the receiving cores don't have string.c_str() to
* receive into, and even if they did, c_srt() is a method and can't be used
* that way.
*/
NodeNameList = new char [NodeListCharLen]; // even though c_str is used, allocate necessary memory
NodeNameList = const_cast<char*>(NodeListStr.c_str()); // c_str() returns const char*, so need to recast
for (int i = 0 ; i < NumUniqueNodes ; ++i) // fill list of unique node name char lengths
NodeListLenVect[i] = NodeStrList[i].size();
/*for (int i = 0 ; i < NumUnique ; ++i)
cout << UniqueNodeStrList[i] << endl;
MPI::COMM_WORLD.Abort(1);*/
//delete NodeStrList; // Arrays of string don't need to be deallocated,
//delete FullStrList; // I'm guessing becuase of something weird in the string class.
delete NodeNameCountVect;
delete NodeNameOffsetVect;
}
/*
* Now we send the list of node names back to all cores
* so they can group themselves appropriately.
*/
// Bcast the number of nodes in use
MPI::COMM_WORLD.Bcast(&NumUniqueNodes, 1, MPI::INT, MASTER);
// Bcast the full length of all node names
MPI::COMM_WORLD.Bcast(&NodeListCharLen, 1, MPI::INT, MASTER);
// prepare buffers for node name Bcast's
if (Rank > MASTER){
NodeListLenVect = new int [NumUniqueNodes];
NodeNameList = new char [NodeListCharLen];
}
// Lengths of node names for navigating c-string
MPI::COMM_WORLD.Bcast(NodeListLenVect, NumUniqueNodes, MPI::INT, MASTER);
// The actual full list of unique node names
MPI::COMM_WORLD.Bcast(NodeNameList, NodeListCharLen, MPI::CHAR, MASTER);
/*
* Similar to what master did before, each core (incl master)
* needs to build an actual list of node names as strings so they
* can compare the c++ way.
*/
int Offset = 0;
NodeStrList = new string[NumUniqueNodes];
for (int i = 0 ; i < NumUniqueNodes ; ++i){
stringstream ss;
for (int j = 0 ; j < NodeListLenVect[i] ; ++j)
ss << NodeNameList[Offset + j];
ss >> NodeStrList[i];
ss.str("");
ss.clear();
Offset += NodeListLenVect[i];
//cout << FullStrList[i] << endl;
}
// Now since everyone has the same list, just check your node and find your group.
int CommGroup = -1;
for (int i = 0 ; i < NumUniqueNodes ; ++i)
if (NodeNameStr.compare(NodeStrList[i]) == 0){
CommGroup = i;
break;
}
if (Rank > MASTER){
delete NodeListLenVect;
delete NodeNameList;
}
// In case process fails, error prints and job aborts.
if (CommGroup < 0){
cout << "**ERROR** Rank " << Rank << " didn't identify comm group correctly." << endl;
IsOk = false;
}
/*
* ======================================================================
* The above method uses c++ strings wherever possible so that things
* like node name comparisons can be done the c++ way. I'm sure there's
* a better way to do this because that was way too many lines of code...
* ======================================================================
*/
// Create node communicators
NodeComm = MPI::COMM_WORLD.Split(CommGroup, 0);
NodeSize = NodeComm.Get_size();
NodeRank = NodeComm.Get_rank();
// Group for master communicator
int MasterGroup;
if (NodeRank == MASTER)
MasterGroup = 0;
else
MasterGroup = MPI_UNDEFINED;
// Create master communicator
MasterComm = MPI::COMM_WORLD.Split(MasterGroup, 0);
MasterRank = -1;
MasterSize = -1;
if (MasterComm != MPI::COMM_NULL){
MasterRank = MasterComm.Get_rank();
MasterSize = MasterComm.Get_size();
}
MPI::COMM_WORLD.Bcast(&MasterSize, 1, MPI::INT, MASTER);
NodeComm.Bcast(&MasterRank, 1, MPI::INT, MASTER);
return IsOk;
}
관련 문제
- 1. MPI 프로세스를 노드에 할당
- 2. MPI 프로세스 동기화
- 3. MPI 루트 프로세스 만 모으십시오.
- 4. mpi 무작위로 선택된 노드에 메시지 보내기
- 5. MPI 및 클러스터
- 6. MPI : 한번에 stdout - 1 프로세스 잠그기?
- 7. Django 앱에서 MPI 작업자 프로세스 시작
- 8. MPI : 프로세스 수에 따라 프로그램이 작동합니다.
- 9. 간단한 MPI 프로그램이 내 코드입니다 프로세스
- 10. MPI 프로세스 간의 교환 데이터 (후광)
- 11. MPI Internals : 프로세스 간의 통신 구현
- 12. open-mpi/mpi-run에서 공유 라이브러리로드
- 13. 생성 된 프로세스 표준 노드에 쓰시겠습니까?
- 14. 종료 할 모든 프로세스 (MPI)에 대한 브로드 캐스트 메시지
- 15. MPI C
- 16. 각 http 블록을 특정 인증 제공자에 매핑하기
- 17. 일반 URL 경로를 특정 파일에 매핑하기
- 18. 노드의 특정 프로세스 ID 제어?
- 19. 바이너리 트리의 특정 노드에 인쇄
- 20. drupal의 특정 노드에 블록 추가
- 21. 특정 하위 노드에 노드 추가
- 22. DataContractSerializer가 특정 XML 노드에 직렬화합니다.
- 23. 특정 노드에 qlogin하는 방법은 무엇입니까?
- 24. srun을 통해 실행 된 MPI 작업의 프로세스 고정
- 25. MPI 프로세스에서 MPI 프로세스를 호출하는 스크립트 호출하기
- 26. MPI, NFS 파일 쓰기
- 27. CMake를 사용하여 특정 MPI 컴파일러 강제 설정
- 28. MPI - 프로세스의 논리 순환
- 29. 특정 디렉토리에서 프로세스 실행
- 30. 특정 사용자의 프로세스 나열
빠른 응답을 주셔서 감사합니다. – Srini
@ srini 수정. 모든 코어는 동일한 노드에 상주하므로 mpirun과 구분할 수 없습니다. OS 스케줄러는 프로세스를 코어에 매핑합니다. 코어에 대한 프로세스 선호도는 [별도의 문제] (http://blogs.cisco.com/performance/open-mpi-v1-5-processor-affinity-options/)입니다. –
이것은 맥락에서 벗어날 수 있지만 사실 Open MPI를 사용하면 주어진 노드의 특정 코어에 대한 각 개별 순위의 매핑을 지정할 수 있습니다. 이것은'-rf' 옵션과 함께'rankfile '을'mpirun'에 넘김으로써 가능합니다. –