我有兴趣使用 OpenMP 将工作卸载到 GPU。
下面的代码在 CPU 上给出了 sum 的正确值
//g++ -O3 -Wall foo.cpp -fopenmp
#pragma omp parallel for reduction(+:sum)
for(int i = 0 ; i < 2000000000; i++) sum += i%11;
它也像这样在带有 OpenACC 的 GPU 上工作
//g++ -O3 -Wall foo.cpp -fopenacc
#pragma acc parallel loop reduction(+:sum)
for(int i = 0 ; i < 2000000000; i++) sum += i%11;
nvprof 表明它在 GPU 上运行,并且在 CPU 上也比 OpenMP 更快。
但是当我尝试像这样使用 OpenMP 卸载到 GPU 时
//g++ -O3 -Wall foo.cpp -fopenmp -fno-stack-protector
#pragma omp target teams distribute parallel for reduction(+:sum)
for(int i = 0 ; i < 2000000000; i++) sum += i%11;
sum 得到错误的结果(它只返回零)。 nvprof 似乎表明它在 GPU 上运行,但它比 CPU 上的 OpenMP 慢得多。
为什么在 GPU 上使用 OpenMP 时缩减失败?
这是我用来测试的完整代码
#include <stdio.h>
//g++ -O3 -Wall acc2.cpp -fopenmp -fno-stack-protector
//sudo nvprof ./a.out
int main (void) {
int sum = 0;
//#pragma omp parallel for reduction(+:sum)
//#pragma acc parallel loop reduction(+:sum)
#pragma omp target teams distribute parallel for reduction(+:sum)
for(int i = 0 ; i < 2000000000; i++) {
sum += i%11;
}
printf("sum = %d\n",sum);
return 0;
}
使用 GCC 7.2.0、Ubuntu 17.10 以及 gcc-offload-nvptx
最佳答案
解决方案是像这样添加子句 map(tofrom:sum):
//g++ -O3 -Wall foo.cpp -fopenmp -fno-stack-protector
#pragma omp target teams distribute parallel for reduction(+:sum) map(tofrom:sum)
for(int i = 0 ; i < 2000000000; i++) sum += i%11;
这得到了 sum 的正确结果,但是代码仍然比没有 target 的 OpenACC 或 OpenMP 慢得多。
更新:速度的解决方案是添加 simd 子句。有关详细信息,请参阅此答案的末尾。
上面的解决方案在一行中有很多子句。它可以像这样分解:
#pragma omp target data map(tofrom: sum)
#pragma omp target teams distribute parallel for reduction(+:sum)
for(int i = 0 ; i < 2000000000; i++) sum += i%11;
另一种选择是使用defaultmap(tofrom:scalar)
#pragma omp target teams distribute parallel for reduction(+:sum) defaultmap(tofrom:scalar)
显然,OpenMP 4.5 中的标量变量默认为 firstprivate。
https://developers.redhat.com/blog/2016/03/22/what-is-new-in-openmp-4-5-3/
defaultmap(tofrom:scalar) 会很方便。
我还手动实现了缩减以查看是否可以加快速度。我没有设法加快它的速度,但无论如何这是代码(我尝试了其他优化,但没有一个有帮助)。
#include <omp.h>
#include <stdio.h>
//g++ -O3 -Wall acc2.cpp -fopenmp -fno-stack-protector
//sudo nvprof ./a.out
static inline int foo(int a, int b, int c) {
return a > b ? (a/c)*b + (a%c)*b/c : (b/c)*a + (b%c)*a/c;
}
int main (void) {
int nteams = 0, nthreads = 0;
#pragma omp target teams map(tofrom: nteams) map(tofrom:nthreads)
{
nteams = omp_get_num_teams();
#pragma omp parallel
#pragma omp single
nthreads = omp_get_num_threads();
}
int N = 2000000000;
int sum = 0;
#pragma omp declare target(foo)
#pragma omp target teams map(tofrom: sum)
{
int nteams = omp_get_num_teams();
int iteam = omp_get_team_num();
int start = foo(iteam+0, N, nteams);
int finish = foo(iteam+1, N, nteams);
int n2 = finish - start;
#pragma omp parallel
{
int sum_team = 0;
int ithread = omp_get_thread_num();
int nthreads = omp_get_num_threads();
int start2 = foo(ithread+0, n2, nthreads) + start;
int finish2 = foo(ithread+1, n2, nthreads) + start;
for(int i=start2; i<finish2; i++) sum_team += i%11;
#pragma omp atomic
sum += sum_team;
}
}
printf("devices %d\n", omp_get_num_devices());
printf("default device %d\n", omp_get_default_device());
printf("device id %d\n", omp_get_initial_device());
printf("nteams %d\n", nteams);
printf("nthreads per team %d\n", nthreads);
printf("total threads %d\n", nteams*nthreads);
printf("sum %d\n", sum);
return 0;
}
nvprof 显示大部分时间花在 cuCtxSynchronize 上。使用 OpenACC,它大约是一半。
我终于设法大大加快了减少速度。解决方案是添加 simd 子句
#pragma omp target teams distribute parallel for simd reduction(+:sum) map(tofrom:sum).
这是一行九个子句。一个稍微短一点的解决方案是
#pragma omp target map(tofrom:sum)
#pragma omp teams distribute parallel for simd reduction(+:sum)
时间是
OMP_GPU 0.25 s
ACC 0.47 s
OMP_CPU 0.64 s
GPU 上的 OpenMP 现在比 CPU 上的 OpenACC 和 OpenMP 快得多。我不知道是否可以通过一些附加条款加快 OpenACC 的速度。
希望 Ubuntu 18.04 修复了 gcc-offload-nvptx,这样它就不需要 -fno-stack-protector。
关于c++ - OpenMP 卸载到 Nvidia 错误减少,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/49111443/
大约一年前,我决定确保每个包含非唯一文本的Flash通知都将从模块中的方法中获取文本。我这样做的最初原因是为了避免一遍又一遍地输入相同的字符串。如果我想更改措辞,我可以在一个地方轻松完成,而且一遍又一遍地重复同一件事而出现拼写错误的可能性也会降低。我最终得到的是这样的:moduleMessagesdefformat_error_messages(errors)errors.map{|attribute,message|"Error:#{attribute.to_s.titleize}#{message}."}enddeferror_message_could_not_find(obje
我的瘦服务器配置了nginx,我的ROR应用程序正在它们上运行。在我发布代码更新时运行thinrestart会给我的应用程序带来一些停机时间。我试图弄清楚如何优雅地重启正在运行的Thin实例,但找不到好的解决方案。有没有人能做到这一点? 最佳答案 #Restartjustthethinserverdescribedbythatconfigsudothin-C/etc/thin/mysite.ymlrestartNginx将继续运行并代理请求。如果您将Nginx设置为使用多个上游服务器,例如server{listen80;server
我遵循MichaelHartl的“RubyonRails教程:学习Web开发”,并创建了检查用户名和电子邮件长度有效性的测试(名称最多50个字符,电子邮件最多255个字符)。test/helpers/application_helper_test.rb的内容是:require'test_helper'classApplicationHelperTest在运行bundleexecraketest时,所有测试都通过了,但我看到以下消息在最后被标记为错误:ERROR["test_full_title_helper",ApplicationHelperTest,1.820016791]test
我是rails的新手,想在form字段上应用验证。myviewsnew.html.erb.....模拟.rbclassSimulation{:in=>1..25,:message=>'Therowmustbebetween1and25'}end模拟Controller.rbclassSimulationsController我想检查模型类中row字段的整数范围,如果不在范围内则返回错误信息。我可以检查上面代码的范围,但无法返回错误消息提前致谢 最佳答案 关键是您使用的是模型表单,一种显示ActiveRecord模型实例属性的表单。c
我正在尝试编写一个将文件上传到AWS并公开该文件的Ruby脚本。我做了以下事情:s3=Aws::S3::Resource.new(credentials:Aws::Credentials.new(KEY,SECRET),region:'us-west-2')obj=s3.bucket('stg-db').object('key')obj.upload_file(filename)这似乎工作正常,除了该文件不是公开可用的,而且我无法获得它的公共(public)URL。但是当我登录到S3时,我可以正常查看我的文件。为了使其公开可用,我将最后一行更改为obj.upload_file(file
我克隆了一个rails仓库,我现在正尝试捆绑安装背景:OSXElCapitanruby2.2.3p173(2015-08-18修订版51636)[x86_64-darwin15]rails-v在您的Gemfile中列出的或native可用的任何gem源中找不到gem'pg(>=0)ruby'。运行bundleinstall以安装缺少的gem。bundleinstallFetchinggemmetadatafromhttps://rubygems.org/............Fetchingversionmetadatafromhttps://rubygems.org/...Fe
在Cooper的书BeginningRuby中,第166页有一个我无法重现的示例。classSongincludeComparableattr_accessor:lengthdef(other)@lengthother.lengthenddefinitialize(song_name,length)@song_name=song_name@length=lengthendenda=Song.new('Rockaroundtheclock',143)b=Song.new('BohemianRhapsody',544)c=Song.new('MinuteWaltz',60)a.betwee
我是Google云的新手,我正在尝试对其进行首次部署。我的第一个部署是RubyonRails项目。我基本上是在关注thisguideinthegoogleclouddocumentation.唯一的区别是我使用的是我自己的项目,而不是他们提供的“helloworld”项目。这是我的app.yaml文件runtime:customvm:trueentrypoint:bundleexecrackup-p8080-Eproductionconfig.ruresources:cpu:0.5memory_gb:1.3disk_size_gb:10当我转到我的项目目录并运行gcloudprevie
我有两个Rails模型,即Invoice和Invoice_details。一个Invoice_details属于Invoice,一个Invoice有多个Invoice_details。我无法使用accepts_nested_attributes_forinInvoice通过Invoice模型保存Invoice_details。我收到以下错误:(0.2ms)BEGIN(0.2ms)ROLLBACKCompleted422UnprocessableEntityin25ms(ActiveRecord:4.0ms)ActiveRecord::RecordInvalid(Validationfa
这个问题在这里已经有了答案:Arraysmisbehaving(1个回答)关闭6年前。是否应该这样,即我误解了,还是错误?a=Array.new(3,Array.new(3))a[1].fill('g')=>[["g","g","g"],["g","g","g"],["g","g","g"]]它不应该导致:=>[[nil,nil,nil],["g","g","g"],[nil,nil,nil]]