ton*_*sdg 2 c multithreading locking openmp
我正在尝试在我的应用程序中检测一些功能,看看它们需要多长时间。我使用链接列表将所有时间记录在内存中。
在此过程中,我引入了一个全局变量来跟踪列表的末尾。当我输入新的计时区域时,我会在列表末尾插入一条新记录。相当简单的东西。
然而,我想要跟踪的一些函数是在 OpenMP 区域中调用的。这意味着它们可能会被并行调用多次。这就是我被难住的地方。
如果这是使用普通的 Pthreads,我只需将对全局变量的访问包装在互斥体中,然后就到此为止了。但是,我不确定:此策略是否仍适用于 OpenMP 区域中调用的函数?比如,他们会尊重锁吗?
例如(不会编译,但我认为明白了这一点):
Record *head;
Record *tail;
void start_timing(char *name) {
Record *r = create_record(name);
tail->next_record = r;
tail = r;
return r;
}
int foo(void) {
Record r = start_timing("foo");
//Do something...
stop_timing(r);
}
int main(void) {
Record r = start_timing("main");
//Do something...
#pragma omp parallel for...
for (int i = 0; i < 42; i++) {
foo();
}
//Do some more...
stop_timing(r);
}
Run Code Online (Sandbox Code Playgroud)
然后我将更新为:
void start_timing(char *name) {
Record *r = create_record(name);
acquire_mutex_on_tail();
tail->next_record = r;
tail = r;
release_mutex_on_tail();
return r;
}
Run Code Online (Sandbox Code Playgroud)
(如果有一个明显的答案,我深表歉意 - 我对 OpenMP 框架和多线程总体来说相对缺乏经验。)
omp_set_lock(&taillock)
tail->next_record = r;
tail = r;
omp_unset_lock(&taillock)
Run Code Online (Sandbox Code Playgroud)
和某处:
omp_lock_t taillock;
omp_init_lock(&taillock);
...
omp_destroy_lock(&taillock);
Run Code Online (Sandbox Code Playgroud)
void start_timing(char *name) {
Record *r = create_record(name);
#pragma omp critical
{
tail->next_record = r;
tail = r;
}
return r;
}
Run Code Online (Sandbox Code Playgroud)
这会创建一个绑定到源代码行的隐式全局锁。有关一些详细讨论,请参阅此问题的答案。
出于实际目的,使用 Pthread 锁也可以,至少对于 OpenMP 基于 Pthread 的场景来说是这样。
在性能测量代码中使用锁是危险的。内存分配也是如此,这通常也意味着使用锁。这意味着,这start_time会产生巨大的成本,并且随着线程数量的增加,性能甚至会变得更差。这甚至没有考虑由于一个线程分配一块内存(记录)然后另一个线程修改它(尾指针)而导致的缓存失效。
现在,如果您测量的部分需要几秒钟,这可能没问题,但当您的部分只有数百个周期时,就会导致巨大的开销和扰动。
要创建可扩展的性能跟踪工具,您必须以更大的块预先分配线程本地内存,并让每个线程仅写入其本地部分。
您还可以选择使用一些现有的测量基础设施,例如Score-P。
首先,区分两者(相关概念)。开销是您花费的额外时间,而扰动是指对您测量的内容的影响(即您现在测量的东西与没有测量时发生的情况不同)。大量的开销是不受欢迎的,但扰动会更糟。
是的,您可以通过在昂贵的测量运行时间期间暂停计时器来避免一些干扰(开销仍然存在)。然而,在多线程上下文中这仍然是一个很大的问题。
| 归档时间: |
|
| 查看次数: |
1555 次 |
| 最近记录: |