- c - 在位数组中找到第一个零
- linux - Unix 显示有关匹配两种模式之一的文件的信息
- 正则表达式替换多个文件
- linux - 隐藏来自 xtrace 的命令
我是 OpenMP 的新手,但我正在尝试使用它来加速对具有大量行和少量列的二维数组条目的某些操作。同时,我正在使用缩减来计算每列中所有数组值的总和。代码看起来像这样(我稍后会解释奇怪的部分):
template <unsigned int NColumns>
void Function(int n_rows, double** X, double* Y)
{
#pragma omp parallel for reduction(+:Y[:NColumns])
for (int r = 0; r < n_rows; ++r)
{
for (int c = 0; c < NColumns; ++c)
{
X[r][c] = some_complicated_stuff(X[r], X[r][c]);
Y[c] += X[r][c];
}
}
}
澄清一下,X 是分配在堆上的 n_rows
x NColumns
大小的二维数组,Y 是 NColumns
大小的一维数组大批。 some_complicated_stuff
实际上并没有作为一个单独的函数实现,但是我在该行中对 X[r][c]
所做的操作仅取决于 X[r] [c]
和一维数组 X[r]
中的其他值。
NColumns
作为模板参数而不是作为常规参数(如 n_rows
)传入的原因是当 NColumns
是在编译时已知,编译器可以更积极地优化上述函数中的内部循环。我知道当程序运行时 NColumns
将成为少数值之一,所以稍后我有类似这样的代码:
cin >> n_cols;
double** X;
double Y[n_cols];
// initialise X and Y, etc. . .
for (int i = 0; i < n_iterations; ++i)
{
switch (n_cols)
{
case 2: Function< 2>(X, Y); break;
case 10: Function<10>(X, Y); break;
case 60: Function<60>(X, Y); break;
default: throw "Unsupported n_cols."; break;
}
// . . .
Report(i, Y); // see GDB output below
}
通过测试,我发现将此 NColumns
“参数”作为模板参数而不是普通函数参数实际上可以显着提高性能。然而,我还发现,一旦出现极难发生的情况(比如,大约每 10^7 次调用 Function
),程序就会挂起——更糟糕的是,它的行为有时会因一次运行而改变下一个程序。这种情况很少发生,以至于我在隔离错误时遇到了很多麻烦,但我现在想知道这是否是因为我在我的 OpenMP 缩减中使用了这个 NColumns
模板参数。
我注意到 similar StackOverflow question询问在缩减中使用模板类型,这显然会导致未指定的行为 - OpenMP 3.0 spec说
If a variable referenced in a data-sharing attribute clause has a type derived from a template, and there are no other references to that variable in the program, then any behavior related to that variable is unspecified.
在这种情况下,使用的不是模板类型本身,但我的情况大致相同。我是不是在这里搞砸了,还是错误更有可能出现在代码的其他部分?
我正在使用 GCC 6.3.0。
如果它更有帮助,这里是 Function
中的真实代码。 X
实际上是一个扁平化的二维数组; ww
和 min_x
在别处定义:
#pragma omp parallel for reduction(+:Y[:NColumns])
for (int i = 0; i < NColumns * n_rows; i += NColumns)
{
double total = 0;
for (int c = 0; c < NColumns; ++c)
if (X[i + c] > 0)
total += X[i + c] *= ww[c];
if (total > 0)
for (int c = 0; c < NColumns; ++c)
if (X[i + c] > 0)
Y[c] += X[i + c] = (X[i + c] < min_x * total ? 0 : X[i + c] / total);
}
只是为了让情节更复杂一点,我将 gdb 附加到挂起的程序的运行进程,这是回溯显示的内容:
#0 0x00007fff8f62a136 in __psynch_cvwait () from /usr/lib/system/libsystem_kernel.dylib
#1 0x00007fff8e65b560 in _pthread_cond_wait () from /usr/lib/system/libsystem_pthread.dylib
#2 0x000000010a4caafb in omp_get_num_procs () from /opt/local/lib/libgcc/libgomp.1.dylib
#3 0x000000010a4cad05 in omp_get_num_procs () from /opt/local/lib/libgcc/libgomp.1.dylib
#4 0x000000010a4ca2a7 in omp_in_final () from /opt/local/lib/libgcc/libgomp.1.dylib
#5 0x000000010a31b4e9 in Report(int, double*) ()
#6 0x3030303030323100 in ?? ()
[snipped traces 7-129, which are all ?? ()]
#130 0x0000000000000000 in ?? ()
Report()
是一个在程序主循环内调用但不在 Function()
内调用的函数(我已将其添加到上面的中间代码片段中) ,并且 Report()
不包含任何 OpenMP 编译指示。这是否说明了正在发生的事情?
请注意,可执行文件在进程开始运行和我将 GDB 附加到它之间发生了变化,这需要引用新的(已更改的)可执行文件。所以这可能意味着符号表被搞乱了。
最佳答案
我已经设法部分解决了这个问题。
其中一个问题是程序的行为具有不确定性。这是因为 (1) OpenMP 执行线程完成顺序的缩减,这是不确定的,并且 (2) 浮点加法是非关联的。我假设减少将按线程编号顺序执行,但事实并非如此。因此,任何使用浮点运算减少的 OpenMP for
构造都可能是不确定的,即使从一次运行到下一次运行的线程数相同,只要线程数更大比 2。关于此事的一些相关 StackOverflow 问题是 here和 here .
另一个问题是程序偶尔会挂起。我一直无法解决这个问题。在挂起的进程上运行 gdb
总是会在堆栈跟踪的顶部产生 __psynch_cvwait ()
。每执行 10^8 次并行化 for 循环,它就会挂起。
希望对您有所帮助。
关于c++ - OpenMP 缩减为 C++ 模板指定大小的数组会导致未定义的行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49986327/
我正在尝试使用 Spark 从 Cassandra 读取数据。 DataFrame rdf = sqlContext.read().option("keyspace", "readypulse
这是代码: void i_log_ (int error, const char * file, int line, const char * fmt, ...) { /* Get erro
我必须调试一个严重依赖 Gtk 的程序。问题是由于某些原因,在使用 GtkWindow 对象时开始出现许多运行时警告。问题是,即使 Gtk 提示严重错误,它也不会因这些错误而中止。我没有代码库的更改历
我正在尝试从已有效编译和链接的程序中检索二进制文件。我已经通过 GL_PROGRAM_BINARY_LENGTH 收到了它的长度。该文档说有两个实例可能会发生 GL_INVALID_OPERATION
我有一个托管在 Azure 环境中的服务。我正在使用控制台应用程序使用该服务。这样做时,我得到了异常: "The requested service, 'http://xxxx-d.yyyy.be/S
我有以下代码,它被 SEGV 信号杀死。使用调试器表明它被 main() 中的第一个 sem_init() 杀死。如果我注释掉第一个 sem_init() ,第二个会导致同样的问题。我试图弄清楚是什么
目前我正在编写一个应用程序(目标 iOS 6,启用 ARC),它使用 JSON 进行数据传输,使用核心数据进行持久存储。 JSON 数据由 PHP 脚本通过 json_encode 从 MySQL 数
我对 Xamarin.Forms 还是很陌生。我在出现的主页上有一个非常简单的功能 async public Task BaseAppearing() { if (UserID
这是我的代码的简化版本。 public class MainActivity extends ActionBarActivity { private ArrayList entry = new Arr
我想弄明白为什么我的两个 Java 库很难很好地协同工作。这是场景: 库 1 有一个类 A,其构造函数如下: public A(Object obj) { /* boilerplate */ } 在以
如果网站不需要身份验证,我的代码可以正常工作,如果需要,则在打印“已创建凭据”后会立即出现 EXC_BAD_ACCESS 错误。我不会发布任何内容,并且此代码是直接从文档中复制的 - 知道出了什么问题
我在使用 NSArray 填充 UITableView 时遇到问题。我确信我正在做一些愚蠢的事情,但我无法弄清楚。当我尝试进行简单的计数时,我得到了 EXC_BAD_ACCESS,我知道这是因为我试图
我在 UITableViewCell 上有一个 UITextField,在另一个单元格上有一个按钮。 我单击 UITextField(出现键盘)。 UITextField 调用了以下方法: - (BO
我有一个应用程序出现间歇性崩溃。崩溃日志显示了一个堆栈跟踪,这对我来说很难破译,因此希望其他人看到了这一点并能为我指出正确的方向。 基本上,应用程序在启动时执行反向地理编码请求,以在标签中显示用户的位
我开发了一个 CGImage,当程序使用以下命令将其显示在屏幕上时它工作正常: [output_view.layer performSelectorOnMainThread:@selector(set
我正在使用新的 EncryptedSharedPreferences以谷歌推荐的方式上课: private fun securePrefs(context: Context): SharedPrefe
我有一个中继器,里面有一些控件,其中一个是文本框。我正在尝试使用 jquery 获取文本框,我的代码如下所示: $("#").click(function (event) {}); 但我总是得到 nu
在以下场景中观察到 TTS 初始化错误,太随机了。 已安装 TTS 引擎,存在语音集,并且可以从辅助功能选项中播放示例 tts。 TTS 初始化在之前初始化和播放的同一设备上随机失败。 在不同的设备(
maven pom.xml org.openjdk.jol jol-core 0.10 Java 类: public class MyObjectData { pr
在不担心冲突的情况下,可以使用 MD5 作为哈希值,字符串长度最多为多少? 这可能是通过为特定字符集中的每个可能的字符串生成 MD5 哈希来计算的,长度不断增加,直到哈希第二次出现(冲突)。没有冲突的
我是一名优秀的程序员,十分优秀!