루프에 들어가기 전에 중첩 루프 내부에서 호출되는 함수를 선택하는 방법은 무엇입니까?

Ali4ph

다음 코드에 표시된 것처럼 여러 원자 루틴 중 하나가 함수에서 호출됩니다 messagePassing. 어떤 것을 사용할 것인지는 중첩 루프에 들어가기 전에 결정됩니다. 현재 구현에서는 while런타임 성능을 위해 여러 루프가 사용됩니다. 가독성과 유지 관리를 위해 자신을 반복 (중첩 된 루프에서 공유 작업을 반복)하는 것을 피하고 messagePassingCleanButSlower.

런타임 성능을 희생하지 않는 접근 방식이 있습니까?

두 가지 시나리오를 처리해야합니다.

  1. 첫 번째에서 원자 루틴은 작고 3 개의 플러스 / 마이너스 연산 만 포함하므로 인라인 될 것입니다.
  2. 두 번째에서는 원자 루틴이 크고 (약 200 줄) 인라인 될 가능성이 낮습니다.
#include <vector>

template<typename Uint, typename Real>
class Graph {
public:
  void messagePassing(Uint nit, Uint type);
  void messagePassingCleanButSlower(Uint nit, Uint type);

private:
  struct Vertex {}; // Details are hidden since they are distracting.
  std::vector< Vertex > vertices;

  void atomicMessagePassingType1(Vertex &v);
  void atomicMessagePassingType2(Vertex &v);
  void atomicMessagePassingType3(Vertex &v);
  // ...
  // may have other types
};

template<typename Uint, typename Real>
void
Graph<Uint, Real>::
messagePassing(Uint nit, Uint type)
{
  Uint count = 0;   // round counter
  if (type == 1) {
    while (count < nit) {
      ++count;
      // many operations
      for (auto &v : vertices) {
        // many other operations
        atomicMessagePassingType1(v);
      }
    }
  }
  else if (type == 2) {
    while (count < nit) {
      ++count;
      // many operations
      for (auto &v : vertices) {
        // many other operations
        atomicMessagePassingType2(v);
      }
    }
  }
  else {
    while (count < nit) {
      ++count;
      // many operations
      for (auto &v : vertices) {
        // many other operations
        atomicMessagePassingType3(v);
      }
    }
  }
}

template<typename Uint, typename Real>
void
Graph<Uint, Real>::
messagePassingCleanButSlower(Uint nit, Uint type)
{
  Uint count = 0;   // round counter
  while (count < nit) {
    ++count;
    // many operations
    for (auto &v : vertices) {
      // many other operations
      if (type == 1) {
        atomicMessagePassingType1(v);
      }
      else if (type == 2) {
        atomicMessagePassingType2(v);
      }
      else {
        atomicMessagePassingType3(v);
      }
    }
  }
}
호두

여기에서 벤치 마크를 참조하십시오.

  1. http://quick-bench.com/rMsSb0Fg4I0WNFX8QbKugCe3hkc

1. 작업 atomicMessagePassingTypeX이 정말 짧은 테스트 시나리오를 설정했습니다 (최적화 장벽 만 있음). 나는 대략 100요소 vertices100외부의 반복을 선택했습니다 while. 이러한 조건은 실제 코드에 따라 다를 수 있으므로 내 벤치 마크 결과가 귀하의 사례에 적용되는지 여부는 자신의 코드를 벤치마킹하여 확인해야합니다.

네 가지 테스트 사례는 다음과 같습니다. 두 가지 변형, 다른 답변에서 언급 된 함수 포인터가있는 변형과 다음과 같이 디스패치 람다를 통해 함수 포인터가 호출되는 변형 :

template<typename Uint, typename Real>
void
Graph<Uint, Real>::
messagePassingLambda(Uint nit, Uint type)
{
  using ftype = decltype(&Graph::atomicMessagePassingType1);
  auto lambda = [&](ftype what_to_call) {
    Uint count = 0;   // round counter
    while (count < nit) {
      ++count;
      // many operations
      for (auto &v : vertices) {
        // many other operations
        (this->*what_to_call)(v);
      }
    }
  };
  if(type == 1) lambda(&Graph::atomicMessagePassingType1);
  else if(type == 2) lambda(&Graph::atomicMessagePassingType2);
  else lambda(&Graph::atomicMessagePassingType3);
}

GCC 9.1 / Clang 8.0 및 O2 / O3의 모든 조합을 사용해보십시오. O3에서 두 컴파일러 모두 "느린"변형에 대해 거의 동일한 성능을 제공한다는 것을 알 수 있습니다. GCC의 경우 실제로 최고입니다. 컴파일러는 적어도 내부 루프에서 if/ else문을 끌어 올린 다음 나에게 완전히 명확하지 않은 어떤 이유로 GCC는 첫 번째 변형과 다르게 내부 루프의 명령을 재정렬하므로 결과적으로 조금 더 빠릅니다.

함수 포인터 변형은 지속적으로 가장 느립니다.

람다 변형은 성능면에서 첫 번째 변형과 사실상 동일합니다. 람다가 인라인되면 본질적으로 동일한 이유가 분명하다고 생각합니다.

인라인되지 않은 경우 간접 호출로 인해 상당한 성능 저하가 발생할 수 있습니다 what_to_call. 다음의 각 호출 사이트에서 적절한 직접 호출을 사용하여 다른 유형을 강제하면이를 방지 할 수 있습니다 lambda.

C ++ 14 이상에서는 일반적인 람다를 만들 수 있습니다.

 auto lambda = [&](auto what_to_call) {

호출 양식 (this->*what_to_call)(v);조정하고 what_to_call();다른 람다로 호출하십시오.

lambda([&](){ atomicMessagePassingType1(v); });

컴파일러가 디스패치 당 하나의 함수를 인스턴스화하도록 강제하고 잠재적 인 간접 호출을 제거해야합니다.

C ++ 11에서는 일반 람다 또는 변수 템플릿을 만들 수 없으므로 보조 람다를 인수로 사용하는 실제 함수 템플릿을 작성해야합니다.

이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.

침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제

에서 수정
0

몇 마디 만하겠습니다

0리뷰
로그인참여 후 검토

관련 기사

분류에서Dev

루프 내에서 비동기 함수 완료 후 함수를 호출하는 방법은 무엇입니까?

분류에서Dev

Python에서 다중 중첩 for 루프를 작성하는 가장 좋은 방법은 무엇입니까?

분류에서Dev

Python : For 루프에 plt.imshow ()를 중첩하는 방법은 무엇입니까?

분류에서Dev

CoffeeScript의 내부 시작 평가에서 외부 인덱스를 사용하여 루프를 중첩하는 방법은 무엇입니까?

분류에서Dev

해당 함수 내부의 루프 변수가있는 루프에서 가져온 함수를 사용하는 방법은 무엇입니까?

분류에서Dev

중첩 루프를 만들고 결과를 3 개 열에 표시하는 방법은 무엇입니까?

분류에서Dev

루프를 통해 사전과 목록을 사전에 중첩하는 방법은 무엇입니까?

분류에서Dev

루프 내에서 조건이 충족되는 경우 while 루프에서 병렬로 함수를 호출하는 방법은 무엇입니까?

분류에서Dev

동적 중첩 for 루프를 생성하기 위해 R에서 재귀 함수를 작성하는 방법은 무엇입니까?

분류에서Dev

중첩 된 foreach 루프 내에서 ProgressBar를 사용하는 방법은 무엇입니까?

분류에서Dev

R에서 중첩 된 for 루프없이 함수 집합을 반복하는 방법은 무엇입니까?

분류에서Dev

루비에서 내부 루프와 다음 for 외부 루프를 끊는 방법은 무엇입니까?

분류에서Dev

함수에서 do..while 루프를 전환하는 가장 좋은 방법은 무엇입니까?

분류에서Dev

중첩 된 ngFor 루프에서 이온 선택에서 값을 얻는 방법은 무엇입니까?

분류에서Dev

Lisp의 for 루프 내에서 함수를 호출하는 방법은 무엇입니까?

분류에서Dev

for 루프 내에서 재귀 함수를 올바르게 호출하는 방법은 무엇입니까?

분류에서Dev

다중 중첩 대신 C ++에서 if else 루프를 만드는 방법은 무엇입니까?

분류에서Dev

Ruby에서 중첩 while 루프를 사용하여 배열을 반복하는 방법은 무엇입니까?

분류에서Dev

VANILLA JS에서 for 루프 내부에서 이벤트를 기다리는 방법은 무엇입니까?

분류에서Dev

루프 내의 중첩 if 문에서 while 루프를 종료하는 방법은 무엇입니까? (아마 쉽게)

분류에서Dev

Java에서 중첩 루프를 효과적으로 사용하는 방법은 무엇입니까?

분류에서Dev

중첩 된 for 루프에서 위치를 제거하는 방법은 무엇입니까?

분류에서Dev

Julia의 if 문 내부에서 for 루프를 끊는 방법은 무엇입니까?

분류에서Dev

Ruby 함수가 중첩 루프에서 'true'로 중단되지 않는 이유는 무엇입니까?

분류에서Dev

PHP MySQL에서 while 루프 내에서 중첩 문을 실행하는 방법은 무엇입니까?

분류에서Dev

Python의 루프에서 for 루프 반복기 변수를 변경하는 방법은 무엇입니까?

분류에서Dev

무한 루프를 만들지 않고 for 루프에서 insert ()를 사용하는 방법은 무엇입니까?

분류에서Dev

for 루프에서 handler.postDelayed를 중지하는 방법은 무엇입니까?

분류에서Dev

루프 내부의 중첩 경로 경로에 연결하는 방법은 무엇입니까?

Related 관련 기사

  1. 1

    루프 내에서 비동기 함수 완료 후 함수를 호출하는 방법은 무엇입니까?

  2. 2

    Python에서 다중 중첩 for 루프를 작성하는 가장 좋은 방법은 무엇입니까?

  3. 3

    Python : For 루프에 plt.imshow ()를 중첩하는 방법은 무엇입니까?

  4. 4

    CoffeeScript의 내부 시작 평가에서 외부 인덱스를 사용하여 루프를 중첩하는 방법은 무엇입니까?

  5. 5

    해당 함수 내부의 루프 변수가있는 루프에서 가져온 함수를 사용하는 방법은 무엇입니까?

  6. 6

    중첩 루프를 만들고 결과를 3 개 열에 표시하는 방법은 무엇입니까?

  7. 7

    루프를 통해 사전과 목록을 사전에 중첩하는 방법은 무엇입니까?

  8. 8

    루프 내에서 조건이 충족되는 경우 while 루프에서 병렬로 함수를 호출하는 방법은 무엇입니까?

  9. 9

    동적 중첩 for 루프를 생성하기 위해 R에서 재귀 함수를 작성하는 방법은 무엇입니까?

  10. 10

    중첩 된 foreach 루프 내에서 ProgressBar를 사용하는 방법은 무엇입니까?

  11. 11

    R에서 중첩 된 for 루프없이 함수 집합을 반복하는 방법은 무엇입니까?

  12. 12

    루비에서 내부 루프와 다음 for 외부 루프를 끊는 방법은 무엇입니까?

  13. 13

    함수에서 do..while 루프를 전환하는 가장 좋은 방법은 무엇입니까?

  14. 14

    중첩 된 ngFor 루프에서 이온 선택에서 값을 얻는 방법은 무엇입니까?

  15. 15

    Lisp의 for 루프 내에서 함수를 호출하는 방법은 무엇입니까?

  16. 16

    for 루프 내에서 재귀 함수를 올바르게 호출하는 방법은 무엇입니까?

  17. 17

    다중 중첩 대신 C ++에서 if else 루프를 만드는 방법은 무엇입니까?

  18. 18

    Ruby에서 중첩 while 루프를 사용하여 배열을 반복하는 방법은 무엇입니까?

  19. 19

    VANILLA JS에서 for 루프 내부에서 이벤트를 기다리는 방법은 무엇입니까?

  20. 20

    루프 내의 중첩 if 문에서 while 루프를 종료하는 방법은 무엇입니까? (아마 쉽게)

  21. 21

    Java에서 중첩 루프를 효과적으로 사용하는 방법은 무엇입니까?

  22. 22

    중첩 된 for 루프에서 위치를 제거하는 방법은 무엇입니까?

  23. 23

    Julia의 if 문 내부에서 for 루프를 끊는 방법은 무엇입니까?

  24. 24

    Ruby 함수가 중첩 루프에서 'true'로 중단되지 않는 이유는 무엇입니까?

  25. 25

    PHP MySQL에서 while 루프 내에서 중첩 문을 실행하는 방법은 무엇입니까?

  26. 26

    Python의 루프에서 for 루프 반복기 변수를 변경하는 방법은 무엇입니까?

  27. 27

    무한 루프를 만들지 않고 for 루프에서 insert ()를 사용하는 방법은 무엇입니까?

  28. 28

    for 루프에서 handler.postDelayed를 중지하는 방법은 무엇입니까?

  29. 29

    루프 내부의 중첩 경로 경로에 연결하는 방법은 무엇입니까?

뜨겁다태그

보관