再帰的に分割可能な 2 次元の半開区間を表すテンプレート・クラス。
#include "tbb/blocked_range2d.h"
template<typename RowValue, typename ColValue> class blocked_range2d;
blocked_range2d<RowValue ,ColValue > は、2 次元の半開区間 [i0,j0)×[i1,j1) を表します。範囲の各軸には独自の分割しきい値があります。RowValue および ColValue は、「blocked_range テンプレート・クラス」セクションの表の要件を満たしていなければなりません。いずれかの軸が分割可能な場合、blocked_range2d は分割可能です。blocked_range2d は、Range コンセプトをモデル化します。
namespace tbb {
template<typename RowValue, typename ColValue=RowValue>
class blocked_range2d {
public:
// 型
typedef blocked_range<RowValue> row_range_type;
typedef blocked_range<ColValue> col_range_type;
// コンストラクター
blocked_range2d(
RowValue row_begin, RowValue row_end,
typename row_range_type::size_type row_grainsize,
ColValue col_begin, ColValue col_end,
typename col_range_type::size_type col_grainsize);
blocked_range2d( RowValue row_begin, RowValue row_end,
ColValue col_begin, ColValue col_end);
// 分割コンストラクター
blocked_range2d( blocked_range2d& r, split );
blocked_range2d( blocked_range2d& r, proportional_split proportion );
// 比例分割が可能
static const bool is_splittable_in_proportion = true;
// キャパシティー
bool empty() const;
// アクセス
bool is_divisible() const;
const row_range_type& rows() const;
const col_range_type& cols() const;
};
}
次のコードは、シリアル行列乗算と、blocked_range2d を使用して反復空間を指定する、対応する並列行列乗算を示しています。
const size_t L = 150;
const size_t M = 225;
const size_t N = 300;
void SerialMatrixMultiply( float c[M][N], float a[M][L], float b[L][N] ) {
for( size_t i=0; i<M; ++i ) {
for( size_t j=0; j<N; ++j ) {
float sum = 0;
for( size_t k=0; k<L; ++k )
sum += a[i][k]*b[k][j];
c[i][j] = sum;
}
}
}
#include "tbb/parallel_for.h"
#include "tbb/blocked_range2d.h"
using namespace tbb;
const size_t L = 150;
const size_t M = 225;
const size_t N = 300;
class MatrixMultiplyBody2D {
float (*my_a)[L];
float (*my_b)[N];
float (*my_c)[N];
public:
void operator()( const blocked_range2d<size_t>& r ) const {
float (*a)[L] = my_a;
float (*b)[N] = my_b;
float (*c)[N] = my_c;
for( size_t i=r.rows().begin(); i!=r.rows().end(); ++i ){
for( size_t j=r.cols().begin(); j!=r.cols().end(); ++j ) {
float sum = 0;
for( size_t k=0; k<L; ++k )
sum += a[i][k]*b[k][j];
c[i][j] = sum;
}
}
}
MatrixMultiplyBody2D( float c[M][N], float a[M][L], float b[L][N] ) :
my_a(a), my_b(b), my_c(c)
{}
};
void ParallelMatrixMultiply(float c[M][N], float a[M][L], float b[L][N]){
parallel_for( blocked_range2d<size_t>(0, M, 16, 0, N, 32),
MatrixMultiplyBody2D(c,a,b) );
}
blocked_range2d は、シリアルバージョンの 2 つの最外ループを並列ループにします。parallel_for は、断片が 16x32 になるまで blocked_range2d を再帰的に分割して、各断片で MatrixMultiplyBody2D::operator() を呼び出します。
| メンバー | 説明 |
|---|---|
| row_range_type |
blocked_range<RowValue>。つまり、行の値の型です。 |
| col_range_type |
blocked_range<ColValue>。つまり、列の値の型です。 |
| blocked_range2d<RowValue,ColValue>( RowValue row_begin, RowValue row_end, typename row_range_type::size_type row_grainsize, ColValue col_begin, ColValue col_end, typename col_range_type::size_type col_grainsize ) |
効果: 値の 2 次元空間を表す blocked_range2d を構築します。空間は、行と列が指定された粒度の、半開直積 [row_begin, row_end) x [col_begin, col_end) です。 例: "blocked_range2d<char,int> r(’a’, ’z’+1, 3, 0, 10, 2);" 文は、形式 (i, j) のすべての値ペアを含む 2 次元の空間を構築します。ここで、i の範囲は 'a' から 'z' で粒度 3、j の範囲は 0 から 9 で粒度 2 です。 |
| blocked_range2d<RowValue,ColValue>( RowValue row_begin, RowValue row_end, ColValue col_begin, ColValue col_end ) | blocked_range2d(row_begin,row_end,1,col_begin,col_end,1) と同じ。 |
| blocked_range2d<RowValue,ColValue> ( blocked_range2d& range, split ) |
基本分割コンストラクター。 要件: is_divisible() が true であること。 効果: range を 2 つのサブ範囲に分割します。新しく構築される blocked_range2d は、ほぼオリジナルの range の半分で、range は残りになるように更新されます。各サブ範囲の粒度はオリジナルの range の粒度と同じです。分割は行または列単位で行われます。範囲は選択した軸で分割され、分割が繰り返された後、サブ範囲の行と列はそれぞれの粒度の比率になります。例えば、row_grainsize が col_grainsize の 2 倍の場合、サブ範囲は列の 2 倍の行を持つようになります。 |
| blocked_range2d<RowValue,ColValue> ( blocked_range2d& range, proportional_split proportion ) |
比例分割コンストラクター。 要件: is_divisible() が true であること。 効果: range を軸の 1 つで指定された proportion の 2 つのサブ範囲に分割します。分割する軸の選択は、基本分割コンストラクターと同じ方法で行われ、選択した軸に比例分割が行われます。2 番目の軸と各サブ範囲の粒度はオリジナルの range と同じです。 |
| bool empty() const |
効果: 範囲が空かどうかを決定します。 戻り値: rows().empty()||cols().empty() |
| bool is_divisible() const |
効果: 範囲がサブ範囲に分割できるかどうかを決定します。 戻り値: rows().is_divisible()||cols().is_divisible() |
| const row_range_type& rows() const |
戻り値: 値の空間の行を含む範囲。 |
| const col_range_type& cols() const |
戻り値: 値の空間の列を含む範囲。 |