我的unix/windows C++应用程序已经使用MPI进行了并行化:作业被分割为N cpus,并且每个块都是并行执行,非常高效,非常好的速度缩放,工作正确完成.
但是在每个过程中都会重复一些数据,并且由于技术原因,这些数据不能轻易地通过MPI(...)进行分割.例如:
在4 CPU工作中,这意味着至少有20Gb的RAM负载,大部分内存"浪费",这很糟糕.
我正在考虑使用共享内存来减少总体负载,每台计算机只会加载一次"静态"块.
所以,主要问题是:
是否有任何标准的MPI方式在节点上共享内存? 某种现成的+免费图书馆?
boost.interprocess和使用MPI调用来分发本地共享内存标识符.任何性能损失或特别问题要警惕?
该作业将在PBS(或SGE)排队系统中执行,如果进程不干净退出,我想知道这些是否会清理特定于节点的共享内存.
我对使用内存映射IO的前景感兴趣,最好利用boost :: interprocess中的工具来实现跨平台支持,将文件中不连续的系统页大小块映射到内存中的连续地址空间.
简化的具体方案:
我有许多"普通旧数据"结构,每个都有一个固定的长度(小于系统页面大小.)这些结构被连接成一个(非常长的)流,其结构的类型和位置由在流中进行它们的那些结构的值.我的目标是在要求苛刻的并发环境中最小化延迟并最大化吞吐量.
我可以非常有效地读取这些数据,通过内存映射它至少是系统页面大小的两倍...并建立一个新的映射,立即读取超出倒数第二个系统页面边界的结构.这使得与普通老式的数据结构交互的代码是一无所知,这些结构是存储器映射...,例如,可以比较使用memcmp()直接在两个不同的结构,而不必关心页边界.
事情变得有趣的是关于更新这些数据流......当它们被(同时)读取时.我想要使用的策略受到系统页面大小粒度的"写入时复制"的启发......基本上是写"覆盖页面" - 允许一个进程读取旧数据而另一个进程读取更新数据.
管理哪些叠加页面以及何时使用不一定是微不足道的......这不是我主要关注的问题.我主要担心的是我可能有一个跨越第4页和第5页的结构,然后更新完全包含在第5页的结构...在第6位写入新页面...当第5页时,将第5页保留为"垃圾收集"决定不再可达.这意味着,如果我将第4页映射到位置M,我需要将第6页映射到内存位置M + page_size ...,以便能够使用现有的(非内存映射)可靠地处理跨页边界的结构意识到)功能.
我正在努力建立最好的策略,而且我受到文件的阻碍,我认为这是不完整的.本质上,我需要将地址空间的分配与内存映射分离到该地址空间.使用mmap(),我知道我可以使用MAP_FIXED - 如果我希望显式控制映射位置......但我不清楚我应该如何保留地址空间以便安全地执行此操作.我可以在没有MAP_FIXED的情况下映射/ dev/zero两个页面,然后使用MAP_FIXED两次将两个页面映射到显式VM地址的分配空间吗?如果是这样,我应该三次打电话给munmap()吗?它会泄漏资源和/或有任何其他不利的开销吗?为了使问题更加复杂,我想在Windows上采用类似的行为......有什么办法可以做到这一点吗?如果我要牺牲我的跨平台野心,是否有完整的解决方案?
-
感谢您的回答,Mahmoud ......我已经读过了,并且认为我已经理解了代码......我已经在Linux下编译了它,它的行为与您的建议一致.
我主要关心的是第62行 - 使用MAP_FIXED.它对mmap做了一些假设,当我阅读我能找到的文档时,我无法确认.您将"更新"页面映射到与最初返回的mmap()相同的地址空间 - 我认为这是'正确' - 即不是恰好在Linux上运行的东西?我还需要假设它适用于文件映射和匿名映射的跨平台.
这个样本肯定让我前进......记录我最终需要的东西可能是在Linux上用mmap()实现的 - 至少.我真正喜欢的是指向文档的指针,该文档显示MAP_FIXED行将在示例演示中运行...并且,理想情况下,从Linux/Unix特定mmap()到独立平台的转换(Boost :: interprocess) )方法.
我在php中的客户端和服务器通过共享内存进行通信,现在我想使用Boost.Interprocess访问这个shred内存对象我该如何访问它?server.php:
function create_image($str){
// Create a blank image and add some text
$im = imagecreatetruecolor(300, 20);
$text_color = imagecolorallocate($im, 233, 14, 91);
$stringBanner=exec("date").$str;
imagestring($im, 1, 5, 5, $stringBanner , $text_color);
ob_start();
imagejpeg($im);
$i = ob_get_contents();
ob_get_clean();
imagedestroy($im);
return $i;
}
echo "\n".__FILE__."\n";
$shm_key = ftok(__FILE__, 't');
echo $shm_key."\n";
$shm_id = shmop_open($shm_key, "a", 0, 0);
if ($shm_id) {
//it is already created
shmop_delete($shm_id);
shmop_close($shm_id);
}
//you need to create it with shmop_open using "c" only
echo "try to create\n";
if(!$shm_id = …Run Code Online (Sandbox Code Playgroud) 我想在内存中创建一个映射的二进制文件; 但是我不确定如何创建要映射到系统的文件.我多次阅读文档并意识到有2个映射文件实现,一个在iostream中,另一个在进程间.
你们对如何在共享内存中创建映射文件有任何想法吗?我试图允许多线程程序读取以二进制文件格式写入的大型double数组.iostream中的映射文件和进程间的区别是什么?
我正在开发一个由内存映射文件支持的线程安全队列,它大大利用了boost进程.我提交了它用于代码审查,并且拥有比我在这个星球上更多年经验的开发人员说他不觉得boost :: interprocess是"准备好黄金时间"并且我应该直接使用pthreads.
我认为这主要是FUD.我个人认为重新实现升级的名称如升级名为_dutex或boost :: interprocess :: deque是荒谬的,但我很想知道其他人的想法.我找不到任何数据来支持他的说法,但也许我只是不知情或天真.Stackoverflow赐教!
我们打开一个由另一个进程创建的boost共享内存
boost::interprocess::managed_shared_memory segment(boost::interprocess::open_only, "SharedMem");
Run Code Online (Sandbox Code Playgroud)
但是,如果创建共享内存的进程是root用户,则读取它的进程(如果是普通用户)将失败,原因如下:
terminate called after throwing an instance of 'boost::interprocess::interprocess_exception'
what(): Permission denied
Run Code Online (Sandbox Code Playgroud)
我该怎么做才能避免这种情况?那是为所有人提供共享内存的权限?
我有一个应用程序,它被编写为boost::asio专门用作输入数据源,因为我们的大多数对象都是基于网络通信的.由于某些特定要求,我们现在还要求使用共享内存作为输入方法.我已经编写了共享内存组件,它的工作相对较好.
问题是如何处理从共享内存进程到消费应用程序的通知,数据可供读取 - 我们需要处理现有输入线程中的数据(使用boost::asio),我们还需要不阻止该输入线程等待数据.
我通过引入一个中间线程来实现这一点,该线程等待从共享内存提供程序进程发出信号的事件,然后将完成处理程序发布到输入线程以处理数据中的读取.
现在这也正常工作,但是中间线程的引入意味着在大量的情况下我们有一个额外的上下文切换,然后我们才能读取对延迟有负面影响的数据,并且附加线程的开销也是相对昂贵.
这是应用程序正在做的简单示例:
#include <iostream>
using namespace std;
#include <boost/asio.hpp>
#include <boost/thread.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/bind.hpp>
class simple_thread
{
public:
simple_thread(const std::string& name)
: name_(name)
{}
void start()
{
thread_.reset(new boost::thread(
boost::bind(&simple_thread::run, this)));
}
private:
virtual void do_run() = 0;
void run()
{
cout << "Started " << name_ << " thread as: " << thread_->get_id() << "\n";
do_run();
}
protected:
boost::scoped_ptr<boost::thread> thread_;
std::string name_;
};
class input_thread
: public simple_thread
{ …Run Code Online (Sandbox Code Playgroud) 我在使用Open-MPI 1.3.3的集群上使用CentOS 5.4 x86_64和Boost 1.42.0.我正在编写一个共享库,它使用共享内存来存储大量数据,供多个进程使用.还有一个加载器应用程序,它将读取文件中的数据并将它们加载到共享内存中.
当我运行加载器应用程序时,它确定了准确存储数据所需的内存量,然后增加了25%的开销.对于几乎每个文件,它将超过2演出数据.当我使用Boost的Interprocess库发出内存请求时,它表示它已成功保留了所请求的内存量.但是当我使用start开始使用它时,我得到一个"总线错误".据我所知,总线错误是访问内存段可用范围之外的内存的结果.
所以我开始研究如何在Linux上共享内存以及检查什么以确保我的系统配置正确以允许大量共享内存.
/proc/sys/kernel/shm*:
shmall - 4294967296(4 Gb)shmmax - 68719476736(68 Gb)shmmni - 4096ipcs -lm命令:
------ Shared Memory Limits -------- max number of segments = 4096 max seg size (kbytes) = 67108864 max total shared memory (kbytes) = 17179869184 min seg size (bytes) = 1
据我所知,这些设置表明我应该能够为我的目的分配足够的共享内存.所以我创建了一个在共享内存中创建大量数据的精简程序:
#include <iostream>
#include <boost/interprocess/managed_shared_memory.hpp>
#include <boost/interprocess/allocators/allocator.hpp>
#include <boost/interprocess/containers/vector.hpp>
namespace bip = boost::interprocess;
typedef bip::managed_shared_memory::segment_manager segment_manager_t;
typedef bip::allocator<long, segment_manager_t> long_allocator;
typedef bip::vector<long, long_allocator> long_vector;
int …Run Code Online (Sandbox Code Playgroud) 我有以下数据结构:
typedef struct
{
short id;
string name;
short age;
} person_struct;
Run Code Online (Sandbox Code Playgroud)
使用boost消息队列,我试图在另一个进程中将此数据结构发送到消息队列接收器.然而,收到后,我在访问上述结构中的'name'变量时出现了分段错误.
以下是我的发件人功能:
person_struct MyRec;
MyRec.id = 1;
MyRec.name = "ABC123";
MyRec.age = 20;
message_queue mqSender(create_only, "MSG_Q", 100, sizeof(person_struct));
mqSender.send(&MyRec, sizeof(person_struct), MQ_PRIORITY);
Run Code Online (Sandbox Code Playgroud)
以下是我的接收功能:
message_queue myReceiver(open_only, "MSG_Q");
person_struct *recvMsg = new person_struct();
size_t msg_size;
unsigned int priority;
myReceiver.receive(recvMsg, sizeof(person_struct), msg_size, priority);
cout << "ID: " << (*recvMsg).id << endl;
cout << "Name: " << (*recvMsg).name << endl;
cout << "Age: " << (*recvMsg).age << endl;
Run Code Online (Sandbox Code Playgroud)
(*recvMsg).id的cout没问题,但cout为(*recvMsg).name发生了分段错误.阅读我需要为结构进行序列化的地方,但无法弄清楚如何去做.谁有人建议?
c++ ×8
boost ×5
ipc ×2
boost-asio ×1
interprocess ×1
linux ×1
mmap ×1
mpi ×1
pbs ×1
performance ×1
permissions ×1
php ×1