如何在 OpenMP 中使用缩减向量变量?
How to use reduction vector variable in OpenMP?
我想在 openmp
中使用 reduction
指令,但它不起作用。编译器错误说:
"reduction: OpenMP 'parallel for' empty factor in directive"
(Visual studio 2015 community)
或
"reduction:^ needed scalar variable"
这是我的代码(字节是unsigned char
)
void RotXOR (const Byte *s, int n, Byte *t)
{
int i = 0, q;
q = n / 8; n %= 8;
#pragma omp parallel for private(i) reduction()
for (i = 0; i < 16; i++) {
t[(q + i) % 16] ^= (s[i] >> n);
if (n != 0) {
t[(q + i + 1) % 16] ^= (s[i] << (8 - n));
}
}
}
来自 C/C++ 的 OpenMP 4.0 标准 p171:
Arrays may not appear in a reduction clause.
所以这样做的唯一方法是创建一个初始化为 0 的本地每线程 "tt" 数组,在其上计算并用 [=13= 更新 t
] 在并行部分退出时自动执行。
但无论如何,由于您的循环次数仅为 16,并行化开销将远远大于任何潜在收益,因此从我的角度来看,这只是一个死胡同。
编辑:这就是我的想法:
void RotXOR( const Byte *s, int n, Byte *t ) {
int q = n / 8;
n %= 8;
#pragma omp parallel
{
int tt[] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0 };
#pragma omp for
for ( int i = 0; i < 16; i++ ) {
tt[( q + i ) % 16] ^= ( s[i] >> n );
if ( n != 0 ) {
tt[( q + i + 1 ) % 16] ^= ( s[i] << ( 8 - n ) );
}
}
#pragma omp critical
for ( int i = 0; i < 16; i++ ) {
t[i] ^= tt[i];
}
}
}
而且我说我不期望性能有太大提升(如果有的话),因为行程计数非常小,不能在线程之间分配太多工作来隐藏线程管理的开销,以及顺序最终减少.
在写这个解决方案的时候,我想到了另一个,但我不知道这两个中哪个表现最好...我怀疑由于大量同步,第二个版本会比第一个版本更差t
的开销和虚假共享,但我不确定...
void RotXOR( const Byte *s, int n, Byte *t ) {
int q = n / 8;
n %= 8;
#pragma omp parallel for
{
for ( int i = 0; i < 16; i++ ) {
int idx = ( q + i ) % 16;
int val = s[i] >> n;
#pragma omp atomic
t[idx] ^= val;
if ( n != 0 ) {
idx = ( q + i + 1 ) % 16;
val = s[i] << ( 8 - n );
#pragma omp atomic
t[idx] ^= val;
}
}
}
}
最后,由于 n
的值在输入时已知,我想从循环中删除 if
语句是个好主意,即使这意味着要多写一点代码。
我想在 openmp
中使用 reduction
指令,但它不起作用。编译器错误说:
"reduction: OpenMP 'parallel for' empty factor in directive" (Visual studio 2015 community)
或
"reduction:^ needed scalar variable"
这是我的代码(字节是unsigned char
)
void RotXOR (const Byte *s, int n, Byte *t)
{
int i = 0, q;
q = n / 8; n %= 8;
#pragma omp parallel for private(i) reduction()
for (i = 0; i < 16; i++) {
t[(q + i) % 16] ^= (s[i] >> n);
if (n != 0) {
t[(q + i + 1) % 16] ^= (s[i] << (8 - n));
}
}
}
来自 C/C++ 的 OpenMP 4.0 标准 p171:
Arrays may not appear in a reduction clause.
所以这样做的唯一方法是创建一个初始化为 0 的本地每线程 "tt" 数组,在其上计算并用 [=13= 更新 t
] 在并行部分退出时自动执行。
但无论如何,由于您的循环次数仅为 16,并行化开销将远远大于任何潜在收益,因此从我的角度来看,这只是一个死胡同。
编辑:这就是我的想法:
void RotXOR( const Byte *s, int n, Byte *t ) {
int q = n / 8;
n %= 8;
#pragma omp parallel
{
int tt[] = { 0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0,
0, 0, 0, 0 };
#pragma omp for
for ( int i = 0; i < 16; i++ ) {
tt[( q + i ) % 16] ^= ( s[i] >> n );
if ( n != 0 ) {
tt[( q + i + 1 ) % 16] ^= ( s[i] << ( 8 - n ) );
}
}
#pragma omp critical
for ( int i = 0; i < 16; i++ ) {
t[i] ^= tt[i];
}
}
}
而且我说我不期望性能有太大提升(如果有的话),因为行程计数非常小,不能在线程之间分配太多工作来隐藏线程管理的开销,以及顺序最终减少.
在写这个解决方案的时候,我想到了另一个,但我不知道这两个中哪个表现最好...我怀疑由于大量同步,第二个版本会比第一个版本更差t
的开销和虚假共享,但我不确定...
void RotXOR( const Byte *s, int n, Byte *t ) {
int q = n / 8;
n %= 8;
#pragma omp parallel for
{
for ( int i = 0; i < 16; i++ ) {
int idx = ( q + i ) % 16;
int val = s[i] >> n;
#pragma omp atomic
t[idx] ^= val;
if ( n != 0 ) {
idx = ( q + i + 1 ) % 16;
val = s[i] << ( 8 - n );
#pragma omp atomic
t[idx] ^= val;
}
}
}
}
最后,由于 n
的值在输入时已知,我想从循环中删除 if
语句是个好主意,即使这意味着要多写一点代码。