- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我有一些使用 openMP(在 for 循环上)并行化的代码。我现在想多次重复该功能并使用 MPI 提交到机器集群,同时保持节点内的所有内容仍然是 openMP。
当我只使用 openMP 时,我得到了预期的速度(使用两倍的处理器/内核数量,用一半的时间完成)。当我添加 MPI 并仅提交给一个 MPI 进程时,我没有得到这种加速。我创建了一个玩具问题来检查这个并且仍然有同样的问题。这是代码
#include <iostream>
#include <stdio.h>
#include <unistd.h>
#include "mpi.h"
#include <omp.h>
int main(int argc, char *argv[]) {
int iam=0, np = 1;
long i;
int numprocs, rank, namelen;
char processor_name[MPI_MAX_PROCESSOR_NAME];
double t1 = MPI_Wtime();
std::cout << "!!!Hello World!!!" << std::endl; // prints !!!Hello World!!!
MPI_Init(&argc, &argv);
MPI_Comm_size(MPI_COMM_WORLD, &numprocs);
MPI_Comm_rank(MPI_COMM_WORLD, &rank);
MPI_Get_processor_name(processor_name, &namelen);
int nThread = omp_get_num_procs();//omp_get_num_threads here returns 1??
printf("nThread = %d\n", nThread);
int *total = new int[nThread];
for (int j=0;j<nThread;j++) {
total[j]=0;
}
#pragma omp parallel num_threads(nThread) default(shared) private(iam, i)
{
np = omp_get_num_threads();
#pragma omp for schedule(dynamic, 1)
for (i=0; i<10000000; i++) {
iam = omp_get_thread_num();
total[iam]++;
}
printf("Hello from thread %d out of %d from process %d out of %d on %s\n",
iam, np, rank, numprocs,processor_name);
}
int grandTotal=0;
for (int j=0;j<nThread;j++) {
printf("Total=%d\n",total[j]);
grandTotal += total[j];
}
printf("GrandTotal= %d\n", grandTotal);
MPI_Finalize();
double t2 = MPI_Wtime();
printf("time elapsed with MPI clock=%f\n", t2-t1);
return 0;
}
我正在使用 openmpi-1.8/bin/mpic++ 进行编译,使用 -fopenmp 标志。这是我的 PBS 脚本
#PBS -l select=1:ncpus=12
setenv OMP_NUM_THREADS 12
/util/mpi/openmpi-1.8/bin/mpirun -np 1 -hostfile $PBS_NODEFILE --map-by node:pe=$OMP_NUM_THREADS /workspace/HelloWorldMPI/HelloWorldMPI
我也尝试过使用#PBS -l nodes=1:ppn=12,得到相同的结果。
当使用一半的核心时,程序实际上更快(快两倍!)。当我减少内核数量时,我更改了 ncpus 和 OMP_NUM_THREADS。我尝试增加实际工作(添加 10^10 个数字而不是代码中显示的 10^7)。我试过删除 printf 语句,想知道它们是否以某种方式减慢了速度,但仍然有同样的问题。顶部显示我正在使用接近 100% 的所有 CPU(在 ncpus 中设置)。如果我使用 -np=2 提交,它会在两台机器上完美地并行化,所以 MPI 似乎按预期工作,但 openMP 坏了
现在没有想法,我可以尝试任何东西。我做错了什么?
最佳答案
我不想这么说,但有很多错误,你应该熟悉一下自己更多地使用 OpenMP 和 MPI。不过,我会尝试通过你的代码并指出我看到的错误。
double t1 = MPI_Wtime();
开始:在 MPI_Init()
之前调用 MPI_Wtime()
是未定义的。我还要补充一点,如果你想用 MPI 做这种基准测试,一个好主意是在之前放一个 MPI_Barrier()
调用 Wtime
以便所有任务同时进入该部分。
//omp_get_num_threads here returns 1??
omp_get_num_threads()
返回 1 的原因是你不在平行区域。
#pragma omp parallel num_threads(nThread)
您将 num_threads
设置为 nThread
,正如 Hristo Iliev 提到的那样,有效忽略通过 OMP_NUM_THREADS
环境变量的任何输入。你通常可以将 num_threads
排除在外,就可以解决这种简化的问题。
default(shared)
并行区域中变量的行为默认是shared
,所以有没有理由在这里有 default(shared)
。
private(iam, i)
我想这是你的编码风格,但不是让 iam
和 i
私有(private),你可以只需在并行区域内声明它们,这将自动将它们设为私有(private)(考虑到您并没有真正在它之外使用它们,没有太多理由不这样做)。
#pragma omp for schedule(dynamic, 1)
另外正如 Hristo Iliev 提到的,使用 schedule(dynamic, 1)
特别针对这个问题集不是最好的主意,因为循环的每次迭代几乎不需要时间并且总的问题大小是固定的。
int grandTotal=0;
for (int j=0;j<nThread;j++) {
printf("Total=%d\n",total[j]);
grandTotal += total[j];
}
不一定是错误,但是你分配的total
数组和最后的求和使用 OpenMP reduction
指令可以更好地完成。
double t2 = MPI_Wtime();
类似于您对 MPI_Init()
所做的,在您完成后调用 MPI_Wtime()
调用的 MPI_Finalize()
未定义,应尽可能避免。
注意:如果您对 OpenMP 有点熟悉,this是一个很好的引用,基本上我在这里解释的关于 OpenMP 的所有内容都在那里。
顺便说一句,我必须指出您实际上并没有对 MPI 做任何事情,除了输出排名和通信大小。也就是说,所有的 MPI 任务不管任务的数量如何,每次都做固定数量的工作。既然有对于越来越多的 MPI 任务,每个任务的工作量没有减少,您不会期望有任何规模,你会吗? (注意:这实际上就是所谓的 Weak Scaling ,但由于您没有通过 MPI 进行通信,因此没有理由期望它不会完美缩放)。
这是用我提到的一些更改重写的代码:
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <mpi.h>
#include <omp.h>
int main(int argc, char *argv[])
{
MPI_Init(&argc, &argv);
int world_size,
world_rank;
MPI_Comm_size(MPI_COMM_WORLD, &world_size);
MPI_Comm_rank(MPI_COMM_WORLD, &world_rank);
int name_len;
char proc_name[MPI_MAX_PROCESSOR_NAME];
MPI_Get_processor_name(proc_name, &name_len);
MPI_Barrier(MPI_COMM_WORLD);
double t_start = MPI_Wtime();
// we need to scale the work per task by number of mpi threads,
// otherwise we actually do more work with the more tasks we have
const int n_iterations = 1e7 / world_size;
// actually we also need some dummy data to add so the compiler doesn't just
// optimize out the work loop with -O3 on
int data[16];
for (int i = 0; i < 16; ++i)
data[i] = rand() % 16;
// reduction(+:total) means that all threads will make a private
// copy of total at the beginning of this construct and then
// do a reduction operation with the + operator at the end (aka sum them
// all together)
unsigned int total = 0;
#pragma omp parallel reduction(+:total)
{
// both of these calls will execute properly since we
// are in an omp parallel region
int n_threads = omp_get_num_threads(),
thread_id = omp_get_thread_num();
// note: this code will only execute on a single thread (per mpi task)
#pragma omp master
{
printf("nThread = %d\n", n_threads);
}
#pragma omp for
for (int i = 0; i < n_iterations; i++)
total += data[i % 16];
printf("Hello from thread %d out of %d from process %d out of %d on %s\n",
thread_id, n_threads, world_rank, world_size, proc_name);
}
// do a reduction with MPI, otherwise the data we just calculated is useless
unsigned int grand_total;
MPI_Allreduce(&total, &grand_total, 1, MPI_UNSIGNED, MPI_SUM, MPI_COMM_WORLD);
// another barrier to make sure we wait for the slowest task
MPI_Barrier(MPI_COMM_WORLD);
double t_end = MPI_Wtime();
// output individual thread totals
printf("Thread total = %d\n", total);
// output results from a single thread
if (world_rank == 0)
{
printf("Grand Total = %d\n", grand_total);
printf("Time elapsed with MPI clock = %f\n", t_end - t_start);
}
MPI_Finalize();
return 0;
}
另外需要注意的是,添加了 schedule(dynamic, 1)
后,我的代码版本执行速度慢了 22 倍,只是为了向您展示它如何影响性能使用不当。
不幸的是,我对 PBS
不太熟悉,因为我使用的集群与 SLURM
一起运行,但一个示例 sbatch file对于在 3 个节点上运行的作业,在每个节点有两个 6 核处理器的系统上,可能看起来像这样:
#!/bin/bash
#SBATCH --job-name=TestOrSomething
#SBATCH --export=ALL
#SBATCH --partition=debug
#SBATCH --nodes=3
#SBATCH --ntasks-per-socket=1
# set 6 processes per thread here
export OMP_NUM_THREADS=6
# note that this will end up running 3 * (however many cpus
# are on a single node) mpi tasks, not just 3. Additionally
# the below line might use `mpirun` instead depending on the
# cluster
srun ./a.out
为了好玩,我还在集群上运行我的版本以测试 MPI 和 OMP 的缩放,并得到以下结果(注意对数缩放):
如你所见,它基本上是完美的。实际上,1-16 是 1 个 MPI 任务和 1-16 个 OMP 线程,16-256 是 1-16 个 MPI 任务,每个任务有 16 个线程,因此您还可以看到 MPI 缩放和 OMP 缩放之间的行为没有变化.
关于c++ - 将 openMP 与 openMPI 混合时的奇怪行为,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27296261/
SQLite、Content provider 和 Shared Preference 之间的所有已知区别。 但我想知道什么时候需要根据情况使用 SQLite 或 Content Provider 或
警告:我正在使用一个我无法完全控制的后端,所以我正在努力解决 Backbone 中的一些注意事项,这些注意事项可能在其他地方更好地解决......不幸的是,我别无选择,只能在这里处理它们! 所以,我的
我一整天都在挣扎。我的预输入搜索表达式与远程 json 数据完美配合。但是当我尝试使用相同的 json 数据作为预取数据时,建议为空。点击第一个标志后,我收到预定义消息“无法找到任何内容...”,结果
我正在制作一个模拟 NHL 选秀彩票的程序,其中屏幕右侧应该有一个 JTextField,并且在左侧绘制弹跳的选秀球。我创建了一个名为 Ball 的类,它实现了 Runnable,并在我的主 Draf
这个问题已经有答案了: How can I calculate a time span in Java and format the output? (18 个回答) 已关闭 9 年前。 这是我的代码
我有一个 ASP.NET Web API 应用程序在我的本地 IIS 实例上运行。 Web 应用程序配置有 CORS。我调用的 Web API 方法类似于: [POST("/API/{foo}/{ba
我将用户输入的时间和日期作为: DatePicker dp = (DatePicker) findViewById(R.id.datePicker); TimePicker tp = (TimePic
放宽“邻居”的标准是否足够,或者是否有其他标准行动可以采取? 最佳答案 如果所有相邻解决方案都是 Tabu,则听起来您的 Tabu 列表的大小太长或您的释放策略太严格。一个好的 Tabu 列表长度是
我正在阅读来自 cppreference 的代码示例: #include #include #include #include template void print_queue(T& q)
我快疯了,我试图理解工具提示的行为,但没有成功。 1. 第一个问题是当我尝试通过插件(按钮 1)在点击事件中使用它时 -> 如果您转到 Fiddle,您会在“内容”内看到该函数' 每次点击都会调用该属
我在功能组件中有以下代码: const [ folder, setFolder ] = useState([]); const folderData = useContext(FolderContex
我在使用预签名网址和 AFNetworking 3.0 从 S3 获取图像时遇到问题。我可以使用 NSMutableURLRequest 和 NSURLSession 获取图像,但是当我使用 AFHT
我正在使用 Oracle ojdbc 12 和 Java 8 处理 Oracle UCP 管理器的问题。当 UCP 池启动失败时,我希望关闭它创建的连接。 当池初始化期间遇到 ORA-02391:超过
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 9 年前。 Improve
引用这个plunker: https://plnkr.co/edit/GWsbdDWVvBYNMqyxzlLY?p=preview 我在 styles.css 文件和 src/app.ts 文件中指定
为什么我的条形这么细?我尝试将宽度设置为 1,它们变得非常厚。我不知道还能尝试什么。默认厚度为 0.8,这是应该的样子吗? import matplotlib.pyplot as plt import
当我编写时,查询按预期执行: SELECT id, day2.count - day1.count AS diff FROM day1 NATURAL JOIN day2; 但我真正想要的是右连接。当
我有以下时间数据: 0 08/01/16 13:07:46,335437 1 18/02/16 08:40:40,565575 2 14/01/16 22:2
一些背景知识 -我的 NodeJS 服务器在端口 3001 上运行,我的 React 应用程序在端口 3000 上运行。我在 React 应用程序 package.json 中设置了一个代理来代理对端
我面临着一个愚蠢的问题。我试图在我的 Angular 应用程序中延迟加载我的图像,我已经尝试过这个2: 但是他们都设置了 src attr 而不是 data-src,我在这里遗漏了什么吗?保留 d
我是一名优秀的程序员,十分优秀!