- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
由于 MPI 不提供二进制兼容性,仅提供源代码兼容性,因此我们不得不将我们的求解器源代码发送给客户,以便他们将我们的求解器与他们首选的 MPI 版本一起使用。好吧,我们已经到了无法再提供源代码的地步。
因此,我正在寻找围绕 MPI 调用创建包装器的方法。我们的想法是为我们提供 stub 函数的 header ,用户将编写实现,从中创建一个动态库,然后我们的求解器将在运行时加载它。
但是解决方案并不“优雅”并且容易出错。因为有 struct
参数(例如,MPI_Request
),其 struct
定义可能因一个 MPI 实现而异,我们需要接受 (void*)
用于我们的许多 stub 参数。此外,如果一个 MPI 与另一个 MPI 的参数数量不同(我不确定它是否保证永远不会发生),唯一的解决方法是使用 var_args
。
//header (provided by us)
int my_stub_mpi_send(const void buf, int count, void* datatype,
int dest, int tag, void* comm);
//*.c (provided by user)
#include <my_stub_mpi.h>
#include <mpi.h>
int my_stub_mpi_send(const void buf, int count, void* datatype,
int dest, int tag, void* comm)
{
return MPI_Send(buf, count, *((MPI_Datatype) datatype),
dest, tag, ((MPI_Comm) comm));
}
//Notes: (1) Most likely the interface will be C, not C++,
// unless I can make a convincing case for C++;
// (2) The goal here is to avoid *void pointers, if possible;
我的问题是是否有人知道解决这些问题的方法?
最佳答案
如果您只针对支持 PMPI 分析接口(interface)的平台,那么有一个通用解决方案,只需对原始源代码进行最少甚至不需要更改。基本思想是(滥用)使用 PMPI 接口(interface)作为包装器。在某种非 OO 意义上,它可能是桥接模式的实现。
首先,几点观察。 MPI 标准中定义了一种结构类型,即 MPI_Status
。它只有三个公开可见的字段:MPI_SOURCE
、MPI_TAG
和 MPI_ERR
。没有 MPI 函数按值获取 MPI_Status
。该标准定义了以下不透明类型:MPI_Aint
、MPI_Count
、MPI_Offset
和 MPI_Status
(+ 几种 Fortran 互操作性类型为清楚起见,特此删除)。前三个是不可或缺的。然后是10种句柄类型,从MPI_Comm
到MPI_Win
。句柄可以作为特殊整数值或作为指向内部数据结构的指针来实现。 MPICH 和基于它的其他实现采用第一种方法,而 Open MPI 采用第二种方法。作为指针或整数,任何类型的句柄都可以适合单个 C 数据类型,即 intptr_t
。
基本思想是覆盖所有 MPI 函数并将它们的参数重新定义为 intptr_t
类型,然后让用户编译的代码转换为正确的类型并进行实际的 MPI 调用:
在 mytypes.h
中:
typedef intptr_t my_MPI_Datatype;
typedef intptr_t my_MPI_Comm;
在mympi.h
中:
#include "mytypes.h"
// Redefine all MPI handle types
#define MPI_Datatype my_MPI_Datatype
#define MPI_Comm my_MPI_Comm
// Those hold the actual values of some MPI constants
extern MPI_Comm my_MPI_COMM_WORLD;
extern MPI_Datatype my_MPI_INT;
// Redefine the MPI constants to use our symbols
#define MPI_COMM_WORLD my_MPI_COMM_WORLD
#define MPI_INT my_MPI_INT
// Redeclare the MPI interface
extern int MPI_Send(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm);
在mpiwrap.c
中:
#include <mpi.h>
#include "mytypes.h"
my_MPI_Comm my_MPI_COMM_WORLD;
my_MPI_Datatype my_MPI_INT;
int MPI_Init(int *argc, char ***argv)
{
// Initialise the actual MPI implementation
int res = PMPI_Init(argc, argv);
my_MPI_COMM_WORLD = (intptr_t)MPI_COMM_WORLD;
my_MPI_INT = (intptr_t)MPI_INT;
return res;
}
int MPI_Send(void *buf, int count, intptr_t datatype, int dest, int tag, intptr_t comm)
{
return PMPI_Send(buf, count, (MPI_Datatype)datatype, dest, tag, (MPI_Comm)comm);
}
在您的代码中:
#include "mympi.h" // instead of mpi.h
...
MPI_Init(NULL, NULL);
...
MPI_Send(buf, 10, MPI_INT, 1, 10, MPI_COMM_WORLD);
...
MPI 包装器可以静态链接或动态预加载。只要 MPI 实现对 PMPI 接口(interface)使用弱符号,这两种方法都有效。您可以扩展上面的代码示例以涵盖所有使用的 MPI 函数和常量。所有常量都应保存在 MPI_Init
/MPI_Init_thread
的包装器中。
处理 MPI_Status
有点复杂。尽管该标准定义了公共(public)字段,但并未说明它们在结构中的顺序或位置。再一次,MPICH 和 Open MPI 显着不同:
// MPICH (Intel MPI)
typedef struct MPI_Status {
int count_lo;
int count_hi_and_cancelled;
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
} MPI_Status;
// Open MPI
struct ompi_status_public_t {
/* These fields are publicly defined in the MPI specification.
User applications may freely read from these fields. */
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
/* The following two fields are internal to the Open MPI
implementation and should not be accessed by MPI applications.
They are subject to change at any time. These are not the
droids you're looking for. */
int _cancelled;
size_t _ucount;
};
如果您只使用 MPI_Status
从诸如 MPI_Recv
的调用中获取信息,那么将三个公共(public)字段复制到一个用户定义的静态结构中是微不足道的,其中包含只有那些领域。但是,如果您还使用读取非公共(public)函数的 MPI 函数,那是不够的,例如MPI_Get_count
。在这种情况下,一种愚蠢的非 OO 方法是简单地嵌入原始状态结构:
在 mytypes.h
中:
// 64 bytes should cover most MPI implementations
#define MY_MAX_STATUS_SIZE 64
typedef struct my_MPI_Status
{
int MPI_SOURCE;
int MPI_TAG;
int MPI_ERROR;
char _original[MY_MAX_STATUS_SIZE];
} my_MPI_Status;
在mympi.h
中:
#define MPI_Status my_MPI_Status
#define MPI_STATUS_IGNORE ((my_MPI_Status*)NULL)
extern int MPI_Recv(void *buf, int count, MPI_Datatype datatype, int dest, int tag, MPI_Comm comm, MPI_Status *status);
extern int MPI_Get_count(MPI_Status *status, MPI_Datatype datatype, int *count);
在mpiwrap.c
中:
int MPI_Recv(void *buf, int count, my_MPI_Datatype datatype, int dest, int tag, my_MPI_Comm comm, my_MPI_Status *status)
{
MPI_Status *real_status = (status != NULL) ? (MPI_Status*)&status->_original : MPI_STATUS_IGNORE;
int res = PMPI_Recv(buf, count, (MPI_Datatype)datatype, dest, tag, (MPI_Comm)comm, real_status);
if (status != NULL)
{
status->MPI_SOURCE = real_status->MPI_SOURCE;
status->MPI_TAG = real_status->MPI_TAG;
status->MPI_ERROR = real_status->MPI_ERROR;
}
return res;
}
int MPI_Get_count(my_MPI_Status *status, my_MPI_Datatype datatype, int *count)
{
MPI_Status *real_status = (status != NULL) ? (MPI_Status*)&status->_original : MPI_STATUS_IGNORE;
return PMPI_Get_count(real_status, (MPI_Datatype)datatype, count);
}
在您的代码中:
#include "mympi.h"
...
MPI_Status status;
int count;
MPI_Recv(buf, 100, MPI_INT, 0, 10, MPI_COMM_WORLD, &status);
MPI_Get_count(&status, MPI_INT, &count);
...
然后,您的构建系统应检查实际 MPI 实现的 sizeof(MPI_Status)
是否小于或等于 MY_MAX_STATUS_SIZE
。
以上只是一个快速而肮脏的想法——还没有测试它,一些 const
或转换可能在这里或那里丢失。它应该在实践中工作并且非常易于维护。
关于c++ - 如何为动态加载编写 MPI 包装器,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38442254/
我之前让 dll 注入(inject)器变得简单,但我有 Windows 7,我用 C# 和 C++ 做了它,它工作得很好!但是现在当我在 Windows 8 中尝试相同的代码时,它似乎没有以正确的方
我正在尝试制作一个名为 core-splitter 的元素,该元素在 1.0 中已弃用,因为它在我们的项目中起着关键作用。 如果您不知道 core-splitter 的作用,我可以提供一个简短的描述。
我有几个不同的蜘蛛,想一次运行所有它们。基于 this和 this ,我可以在同一个进程中运行多个蜘蛛。但是,我不知道如何设计一个信号系统来在所有蜘蛛都完成后停止 react 器。 我试过了: cra
有没有办法在达到特定条件时停止扭曲 react 器。例如,如果一个变量被设置为某个值,那么 react 器应该停止吗? 最佳答案 理想情况下,您不会将变量设置为一个值并停止 react 器,而是调用
https://code.angularjs.org/1.0.0rc9/angular-1.0.0rc9.js 上面的链接定义了外部js文件,我不知道Angular-1.0.0rc9.js的注入(in
我正在尝试运行一个函数并将服务注入(inject)其中。我认为这可以使用 $injector 轻松完成.所以我尝试了以下(简化示例): angular.injector().invoke( [ "$q
在 google Guice 中,我可以使用函数 createInjector 创建基于多个模块的注入(inject)器。 因为我使用 GWT.create 在 GoogleGin 中实例化注入(in
我在 ASP.NET Core 1.1 解决方案中使用配置绑定(bind)。基本上,我在“ConfigureServices Startup”部分中有一些用于绑定(bind)的简单代码,如下所示: s
我在 Spring MVC 中设置 initBinder 时遇到一些问题。我有一个 ModelAttribute,它有一个有时会显示的字段。 public class Model { privat
我正在尝试通过jquery post发布knockoutjs View 模型 var $form = $('#barcodeTemplate form'); var data = ko.toJS(vm
如何为包含多态对象集合的复杂模型编写自定义模型绑定(bind)程序? 我有下一个模型结构: public class CustomAttributeValueViewModel { publi
您好,我正在尝试实现我在 this article 中找到的扩展方法对于简单的注入(inject)器,因为它不支持开箱即用的特定构造函数的注册。 根据这篇文章,我需要用一个假的委托(delegate)
你好,我想自动注册我的依赖项。 我现在拥有的是: public interface IRepository where T : class public interface IFolderReposi
我正在使用 Jasmine 测试一些 Angular.js 代码。为此,我需要一个 Angular 注入(inject)器: var injector = angular.injector(['ng'
我正在使用 Matlab 代码生成器。不可能包含代码风格指南。这就是为什么我正在寻找一个工具来“ reshape ”、重命名和重新格式化生成的代码,根据我的: 功能横幅约定 文件横幅约定 命名约定 等
这个问题在这里已经有了答案: Where and why do I have to put the "template" and "typename" keywords? (8 个答案) 关闭 8
我开发了一种工具,可以更改某些程序的外观。为此,我需要在某些进程中注入(inject)一个 dll。 现在我基本上使用这个 approach .问题通常是人们无法注入(inject) dll,因为他们
我想使用 swing、spring 和 hibernate 编写一个 java 应用程序。 我想使用数据绑定(bind)器用 bean 的值填充 gui,并且我还希望它反射(reflect) gui
我有这段代码,当两个蜘蛛完成后,程序仍在运行。 #!C:\Python27\python.exe from twisted.internet import reactor from scrapy.cr
要点是 Spring Batch (v2) 测试框架具有带有 @Autowired 注释的 JobLauncherTestUtils.setJob。我们的测试套件有多个 Job 类提供者。因为这个类不
我是一名优秀的程序员,十分优秀!