2012-12-05 2 views
4

이것은 긴 이야기가 될 것입니다. 그러나 아마도 여러분 중 일부는이 사례를 연구하기를 원할 것입니다.병렬 반복을위한 매크로의 대안은 무엇입니까?

저는 병렬 그래프 알고리즘 개발을하고 있습니다. 나는 STINGER이라는 최첨단의 HPC 병렬 그래프 데이터 구조를 선택했다. STINGER의 사명을 읽습니다.

"는 큰 그래프 커뮤니티는 신속하게 서로의 연구 개발을 활용할 수 있도록 공통의 추상 데이터 구조를 제공한다 STINGER [...] STINGER 용으로 작성 알고리즘은 쉽게 될 수 있습니다 여러 언어와 프레임 워크간에 변환/포팅 됨 [...] 알고리즘은 모든 그래프 알고리즘에 가장 적합한 단일 데이터 구조가 없음을 인식합니다. STINGER의 목표는 대부분의 알고리즘을 효과적으로 실행할 수있는 적절한 데이터 구조를 구성하는 것입니다.와 비교할 때 STINGER 사용시 성능이 크게 저하되지 않아야합니다 ( ).일반적인 그래프 알고리즘의 광범위한 세트에 걸쳐 다른 일반적인 데이터 구조. "

STINGER는 아마도 공유 메모리 병렬 처리에 다소 효율적이고 적합합니다. 반면에, 그것은 추상적이지는 않으며 범용 적이거나 간결합니다. STINGER가 제공하는 인터페이스는 여러 가지 이유로 나에게 만족스럽지 않다. 너무 장황하다 (함수는 필자의 경우 중요하지 않은 매개 변수를 필요로한다). 그것은 방향이 잡힌 그래프 만 모델링하는 반면 방향이없는 그래프는 모델링합니다. 및 기타 이유.

그러나 필자는 독자적으로 새로운 병렬 그래프 데이터 구조를 구현하지 않았습니다.

그래서 이미 내 자신의 Graph 클래스로 STINGER 인스턴스를 캡슐화하기 시작했습니다. 예를 들어, 무향 에지가 존재하는지 여부를 확인하기 위해, 지금 대신 내 알고리즘으로 작성하는 Graph::hasEdge(node u, node v)를 호출 할 수

int to = stinger_has_typed_successor(stinger, etype, u, v); 
int back = stinger_has_typed_successor(stinger, etype, v, u); 
bool answer = to && back; 

지금까지이 잘 근무하고있다. 이제 반복의 주제로.

STINGER는 매크로를 통해 순회 (노드, 에지, 노드의 인시던트 에지를 통한 반복)를 실현합니다. 예를 들어, 매크로 외관상 완전히 효율적 (병렬) 반복에 대해 노출 될 필요가있는 데이터 구조의 장내 숨겨

do {         \ 
          \ 
          \ 
    for(uint64_t p__ = 0; p__ < (G.asSTINGER())->ETA[(etype)].high; p__++) { \ 
     struct stinger_eb * current_eb__ = ebpool + (G.asSTINGER())->ETA[(etype)].blocks[p__]; \ 
     int64_t source__ = current_eb__->vertexID;   \ 
     int64_t type__ = current_eb__->etype;    \ 
     for(uint64_t i__ = 0; i__ < stinger_eb_high(current_eb__); i__++) { \ 
    if(!stinger_eb_is_blank(current_eb__, i__)) {     \ 
     struct stinger_edge * current_edge__ = current_eb__->edges + i__; 

STINGER_PARALLEL_FORALL_EDGES_BEGIN가 확장 여기

STINGER_PARALLEL_FORALL_EDGES_BEGIN(G.asSTINGER(), etype) { 
    node u = STINGER_EDGE_SOURCE; 
    node v = STINGER_EDGE_DEST; 
    std::printf("found edge (%d, %d)", u, v); 
} STINGER_PARALLEL_FORALL_EDGES_END(); 

물품. 이 STINGER_FORALL_EDGES_BEGIN, STINGER_READ_ONLY_FORALL_EDGES_BEGIN, STINGER_READ_ONLY_PARALLEL_FORALL_EDGES_BEGIN ...

네,이 매크로를 사용할 수있는 등 다양한 조합에 대한 매크로가 있지만, 반복을 구현하는 더 우아한 방법이 있는지 궁금하다. 내가 인터페이스 할 수 있다면 {...} 단순히 기능, 폐쇄 또는 다음 적절하게 실행될 것 "코드 블록"이고, 그것은

G.forallEdges(readonly=true, parallel=true, {..}) 

GraphIterTools.forallEdges(G, readonly=true, parallel=true, {...}) 

에 유사 것이다. 그러나, 나는 이것을 구현하는 C++ 경험이 부족하다. 이 문제에 대해 어떤 조언을 해줄 수 있는지 궁금합니다. 어쩌면 또한 "당신은 매크로를 가지고 가야만하기 때문에 ...".기존의 매크로를 활용

+0

매크로를 사용하는 이유는 무엇입니까? 'G' 클래스를 정의하고'forallEdges' 메소드를 정적 메소드로 사용할 수 있습니다. 그러나 예제 에서처럼 인수를 넣을 수 없으므로'G.forallEdges (true, true, ...) '가됩니다. – Zane

+0

매크로는 이미 존재합니다. 나는 매크로에 대한 대안을 직접 만들어야 할 것이다. 정적 메소드'forallEdges'는 매크로가 사용되는 곳에서 어떻게 사용될 수 있을까요? – clstaudt

+0

나는 맥주 주인이 이것에 좋은 대답을했다고 생각합니다. – Zane

답변

2

,이 같은 그래프 클래스에 멤버 함수를 구현할 수 :

template<typename Callback> 
void forallEdges(int etype, Callback callback) 
{ 
    STINGER_PARALLEL_FORALL_EDGES_BEGIN(this->asSTINGER(), etype) { 
     node u = STINGER_EDGE_SOURCE; 
     node v = STINGER_EDGE_DEST; 

     // call the supplied callback 
     callback(u, v); 

    } STINGER_PARALLEL_FORALL_EDGES_END(); 
} 

그런 다음 콜백 함수를 정의하고 새로운 방법에 전달 :

void my_callback(node u, node v) { ... } 
... 
G.forallEdges(etype, my_callback); 

또는 C++ 11에서는 람다 함수를 사용할 수 있습니다 :

G.forallEdges(etype, [](node u, node v) { ... });