2014-05-13 4 views
1

더 빠른 것은 요소 선택 연산자를 사용하여 다중 배열 요소에 액세스하거나 반복자를 사용하여 다중 배열을 탐색하는 것입니다.Boost MultiArray에서 요소에 액세스하는 가장 빠른 방법

필자의 경우, 매번 multiarray의 모든 요소를 ​​완전히 통과시켜야합니다.

+3

왜 비교? 결과는 컴파일러, 플랫폼 등에 따라 달라질 수 있습니다. 생성 된 어셈블 코드를 비교할 수 있습니다. – user1641854

+0

좋습니다. 윌 당신이 알려 드리겠습니다. –

+0

멀티 어레이는 속도가 필요할 때 힙에서 할당 할 때 사용하는 것은 좋지 않은 생각입니다. – user1095108

답변

5

boost::multi_array의 모든 요소에 액세스하는 가장 빠른 방법은 data()num_elements()입니다.

data()을 사용하면 기본 원시 스토리지 (배열의 데이터가 포함 된 인접한 블록)에 액세스 할 수 있으므로 여러 인덱스 계산이 필요하지 않습니다. multi_array은 0과 다른 기준의 배열을 인덱싱 할 수 있습니다 이것은 더 복잡한 문제입니다.)

간단한 테스트를 제공합니다 : 기본 부스트 액세스 방법으로

g++ -O3 -fomit-frame-pointer -march=native (GCC v4.8.2) 
Writing (index): 9.70651 
Writing (data): 2.22353 
Reading (index): 4.5973 (found 1) 
Reading (data): 3.53811 (found 1) 

clang++ -O3 -fomit-frame-pointer -march=native (CLANG v3.3) 
Writing (index): 5.49858 
Writing (data): 2.13678 
Reading (index): 5.07324 (found 1) 
Reading (data): 2.55109 (found 1) 

범위 검사를 수행합니다. 제공된 인덱스가 배열에 정의 된 범위를 벗어나면 어설 션이 프로그램을 중단합니다. 범위 검사를 사용하지 않으려면 응용 프로그램에 multi_array.hpp을 포함하기 전에 BOOST_DISABLE_ASSERTS 사전 처리기 매크로를 정의 할 수 있습니다.

이 많게 성능 차이를 줄이는 것이다

g++ -O3 -fomit-frame-pointer -march=native (GCC v4.8.2) 
Writing (index): 3.15244 
Writing (data): 2.23002 
Reading (index): 1.89553 (found 1) 
Reading (data): 1.54427 (found 1) 

clang++ -O3 -fomit-frame-pointer -march=native (CLANG v3.3) 
Writing (index): 2.24831 
Writing (data): 2.12853 
Reading (index): 2.59164 (found 1) 
Reading (data): 2.52141 (found 1) 

성능 차이가 증가 (즉 data()가 빠르다) 치수 높은 번호

  • ;
  • 요소 수가 적을 경우 (많은 수의 요소에 대한 액세스는 요소를 CPU 캐시로로드하기 위해 캐시 압력만큼 중요하지 않습니다. 프리 페처가 거기에 앉아 이러한 요소를로드하려고 시도 할 것입니다 , 시간의 큰 부분을 차지할 것입니다).

어쨌든 이러한 종류의 최적화는 실제 프로그램에서 측정 할 수있는 차이를 만들어 내지 않을 것입니다. 광범위한 테스트를 통해 병목 현상의 근원이라는 결론을 내리지 않는 한 걱정할 필요가 없습니다.

출처 :

#include <chrono> 
#include <iostream> 

// #define BOOST_DISABLE_ASSERTS 
#include <boost/multi_array.hpp> 

int main() 
{ 
    using array3 = boost::multi_array<unsigned, 3>; 
    using index = array3::index; 

    using clock = std::chrono::high_resolution_clock; 
    using duration = std::chrono::duration<double>; 

    constexpr unsigned d1(300), d2(400), d3(200), sup(100); 

    array3 A(boost::extents[d1][d2][d3]); 

    // Writing via index 
    const auto t_begin1(clock::now()); 
    unsigned values1(0); 
    for (unsigned n(0); n < sup; ++n) 
    for (index i(0); i != d1; ++i) 
     for (index j(0); j != d2; ++j) 
     for (index k(0); k != d3; ++k) 
      A[i][j][k] = ++values1; 
    const auto t_end1(clock::now()); 

    // Writing directly 
    const auto t_begin2(clock::now()); 
    unsigned values2(0); 
    for (unsigned n(0); n < sup; ++n) 
    { 
    const auto sup(A.data() + A.num_elements()); 

    for (auto i(A.data()); i != sup; ++i) 
     *i = ++values2; 
    } 
    const auto t_end2(clock::now()); 

    // Reading via index 
    const auto t_begin3(clock::now()); 
    bool found1(false); 
    for (unsigned n(0); n < sup; ++n) 
    for (index i(0); i != d1; ++i) 
     for (index j(0); j != d2; ++j) 
     for (index k(0); k != d3; ++k) 
      if (A[i][j][k] == values1) 
      found1 = true; 
    const auto t_end3(clock::now()); 

    // Reading directly 
    const auto t_begin4(clock::now()); 
    bool found2(false); 
    for (unsigned n(0); n < sup; ++n) 
    { 
    const auto sup(A.data() + A.num_elements()); 

    for (auto i(A.data()); i != sup; ++i) 
     if (*i == values2) 
     found2 = true; 
    } 
    const auto t_end4(clock::now()); 

    std::cout << "Writing (index): " 
      << std::chrono::duration_cast<duration>(t_end1 - t_begin1).count() 
      << std::endl 
      << "Writing (data): " 
      << std::chrono::duration_cast<duration>(t_end2 - t_begin2).count() 
      << std::endl 
      << "Reading (index): " 
      << std::chrono::duration_cast<duration>(t_end3 - t_begin3).count() 
      << " (found " << found1 << ")" << std::endl 
      << "Reading (data): " 
      << std::chrono::duration_cast<duration>(t_end4 - t_begin4).count() 
      << " (found " << found2 << ")" << std::endl; 

    return 0; 
}