10

Open-MPI 1.3.3 を使用するクラスターで CentOS 5.4 x86_64 と Boost 1.42.0 を使用しています。共有メモリを使用して、複数のプロセスが使用する大量のデータを格納する共有ライブラリを作成しています。ファイルからデータを読み取り、共有メモリにロードするローダー アプリケーションもあります。

ローダー アプリケーションを実行すると、データを正確に格納するために必要なメモリ量が決定され、オーバーヘッドが 25% 追加されます。ほぼすべてのファイルで、2 ギガ以上のデータになります。Boost の Interprocess ライブラリを使用してメモリ要求を行うと、要求された量のメモリが正常に予約されたと表示されます。しかし、使用開始を使用すると、「バスエラー」が発生します。私が知る限り、バス エラーは、メモリ セグメントで使用可能な範囲外のメモリにアクセスした結果です。

そこで、Linux で共有メモリがどのようになっているのか、システムが大量の共有メモリを許可するように正しく構成されていることを確認するために何をチェックすればよいのかを調べ始めました。

  1. 私は次の「ファイル」を見ました/proc/sys/kernel/shm*
    • shmall- 4294967296 (4GB)
    • shmmax- 68719476736 (68GB)
    • shmmni- 4096

  2. 私はipcs -lmコマンドを呼び出しました:
    ------ 共有メモリの制限 --------
    セグメントの最大数 = 4096
    最大セグメント サイズ (キロバイト) = 67108864
    最大合計共有メモリ (キロバイト) = 17179869184
    最小セグメント サイズ (バイト) = 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 main(int argc, char ** argv) {
    struct shm_remove  { 
        shm_remove()    { bip::shared_memory_object::remove("ShmTest"); } 
        ~shm_remove()   { bip::shared_memory_object::remove("ShmTest"); } 
    } remover; 

    size_t szLength = 280000000;
    size_t szRequired = szLength * sizeof(long);
    size_t szRequested = (size_t) (szRequired * 1.05);
    bip::managed_shared_memory segment(bip::create_only, "ShmTest", szRequested); 

    std::cout << 
        "Length:       " << szLength << "\n" <<
        "sizeof(long): " << sizeof(long) << "\n" <<
        "Required:     " << szRequired << "\n" <<
        "Requested:    " << szRequested << "\n" <<
        "Allocated:    " << segment.get_size() << "\n" <<
        "Overhead:     " << segment.get_size() - segment.get_free_memory() << "\n" <<
        "Free:         " << segment.get_free_memory() << "\n\n";

    long_allocator alloc(segment.get_segment_manager()); 
    long_vector vector(alloc);

    if (argc > 1) {
        std::cout << "Reserving Length of " << szLength << "\n";
        vector.reserve(szLength);
        std::cout << "Vector Capacity: " << vector.capacity() << "\tFree: " << segment.get_free_memory() << "\n\n";
    }

    for (size_t i = 0; i < szLength; i++) {
        if ((i % (szLength / 100)) == 0) {
            std::cout << i << ": " << "\tVector Capacity: " << vector.capacity() << "\tFree: " << segment.get_free_memory() << "\n";
        }
        vector.push_back(i);    
    }
    std::cout << "end: " << "\tVector Capacity: " << vector.capacity() << "\tFree: " << segment.get_free_memory() << "\n";

    return 0;
}

次の行でコンパイルしました:

g++ ShmTest.cpp -lboost_system -lrt

次に、次の出力で実行しました(小さくするために編集しました):

長さ: 280000000
sizeof(長い): 8
必須: 2240000000
要求: 2352000000
割り当て済み: 2352000000
オーバーヘッド: 224
無料: 2351999776

0: ベクトル容量: 0 フリー: 2351999776
2800000: ベクター容量: 3343205 フリー: 2325254128
5600000: ベクトル容量: 8558607 フリー: 2283530912
8400000: ベクトル容量: 8558607 フリー: 2283530912
11200000: ベクター容量: 13693771 フリー: 2242449600
14000000: ベクター容量: 21910035 フリー: 2176719488
...
19600000: ベクター容量: 21910035 フリー: 2176719488
22400000: ベクター容量: 35056057 フリー: 2071551312
...
33600000: ベクトル容量: 35056057 フリー: 2071551312
36400000: ベクター容量: 56089691 フリー: 1903282240
...
56000000: ベクター容量: 56089691 フリー: 1903282240
58800000: ベクター容量: 89743507 フリー: 1634051712
...
89600000: ベクター容量: 89743507 フリー: 1634051712
92400000: ベクター容量: 143589611 フリー: 1203282880
...
142800000: ベクター容量: 143589611 フリー: 1203282880
145600000: ベクター容量: 215384417 フリー: 628924432
...
212800000: ベクター容量: 215384417 フリー: 628924432
215600000: ベクター容量: 293999969 フリー: 16
...
260400000: ベクター容量: 293999969 フリー: 16
バスエラー

a パラメーターを指定してプログラムを実行すると (どれでも機能しますが、 を増やすだけで済みますargc)、ベクターは事前に割り当てられますが、同じ配列インデックスでバス エラーが発生します。

次のコマンドを/dev/shm使用して、「ファイル」のサイズを確認しました。ls -ash /dev/shm

合計 2.0G
   0 . 0 .. 2.0G ShmTest

元のアプリケーションと同様に、割り当てられた共有メモリのサイズは 2 ギガに制限されています。2352000000 バイトのメモリが "正常に" 割り当てられたとすると、ギガバイト単位 (1024*1024*1024 を使用) は 2.19 Gb になるはずです。

実際のプログラムを実行して MPI を使用してデータをロードすると、次のエラー出力が表示されます。

要求: 2808771120
受信: 2808771120

[c1-master:13894] *** 受信信号の処理 ***
[c1-master:13894] シグナル: バスエラー (7)
[c1-master:13894] シグナルコード: (2)
[c1-master:13894] アドレスで失敗: 0x2b3190157000
[c1-master:13894] [0] /lib64/libpthread.so.0 [0x3a64e0e7c0]
[c1-master:13894] [1] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost12interprocess26uninitialized_copy_or_moveINS0_10offset_ptrIlEEPlEET0_T_S6_S5_PNS_10disable_ifINS0_11move_detail16is_move_iteratorIS6_EEvE218+cf0xE213)
[c1-master:13894] [ 2] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost9container6vectorIlNS_12interprocess9allocatorIlNS2_15segment_managerIcNS2_15rbtree_best_fitINS2_12mutex_familyENS2_10offset_ptrIvEELm0EEENS2_10iset_indexEEEEEE15priv_assign_auxINS7_IlEEEEvT_SG_St20forward_iterator_tag+0xa75) [0x2b310dd0a335]
[c1-master:13894] [ 3] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost9container17containers_detail25advanced_insert_aux_proxyINS0_6vectorIlNS_12interprocess9allocatorIlNS4_15segment_managerIcNS4_15rbtree_best_fitINS4_12mutex_familyENS4_10offset_ptrIvEELm0EEENS4_10iset_indexEEEEEEENS0_17constant_iteratorISF_lEEPSF_E25uninitialized_copy_all_toESI_+0x1d7) [0x2b310dd0b817]
[c1-master:13894] [ 4] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost9container6vectorINS1_IlNS_12interprocess9allocatorIlNS2_15segment_managerIcNS2_15rbtree_best_fitINS2_12mutex_familyENS2_10offset_ptrIvEELm0EEENS2_10iset_indexEEEEEEENS3_ISD_SB_EEE17priv_range_insertENS7_ISD_EEmRNS0_17containers_detail23advanced_insert_aux_intISD_PSD_EE+0x771) [0x2b310dd0d521]
[c1-master:13894] [ 5] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost12interprocess6detail8Ctor3ArgINS_9container6vectorINS4_IlNS0_9allocatorIlNS0_15segment_managerIcNS0_15rbtree_best_fitINS0_12mutex_familyENS0_10offset_ptrIvEELm0EEENS0_10iset_indexEEEEEEENS5_ISF_SD_EEEELb0EiSF_NS5_IvSD_EEE11construct_nEPvmRm+0x157) [0x2b310dd0d9a7]
[c1-master:13894] [ 6] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost12interprocess15segment_managerIcNS0_15rbtree_best_fitINS0_12mutex_familyENS0_10offset_ptrIvEELm0EEENS0_10iset_indexEE28priv_generic_named_constructIcEEPvmPKT_mbbRNS0_6detail18in_place_interfaceERNS7_INSE_12index_configISB_S6_EEEENSE_5bool_ILb1EEE+0x6fd) [0x2b310dd0c85d]
[c1-master:13894] [ 7] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN5boost12interprocess15segment_managerIcNS0_15rbtree_best_fitINS0_12mutex_familyENS0_10offset_ptrIvEELm0EEENS0_10iset_indexEE22priv_generic_constructEPKcmbbRNS0_6detail18in_place_interfaceE+0xf8) [0x2b310dd0dd58]
[c1-master:13894] [8] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN7POP_LTL16ExportPopulation22InitializeSharedMemoryEPKc+0x1609) [0x2b310dceea99]
[c1-master:13894] [9] ../LookupPopulationLib/Release/libLookupPopulation.so(_ZN7POP_LTL10InitializeEPKc+0x349) [0x2b310dd0ebb9]
[c1-master:13894] [10] MPI_Release/LookupPopulation.MpiLoader(メイン+0x372) [0x4205d2]
[c1-master:13894] [11] /lib64/libc.so.6(__libc_start_main+0xf4) [0x3a6461d994]
[c1-master:13894] [12] MPI_Release/LookupPopulation.MpiLoader(__gxx_personality_v0+0x239) [0x420009]
[c1-master:13894] *** エラーメッセージの終わり ***
-------------------------------------------------- ------------------------
mpirun は、ノード c1-master 上の PID 13894 のプロセス ランク 0 がシグナル 7 (バス エラー) で終了したことを検出しました。
-------------------------------------------------- ------------------------

これでどこに行くべきか本当にわかりません。何を試してみるべきかについて何か提案はありますか?


Boost バグ トラックに投稿: https://svn.boost.org/trac/boost/ticket/4374

4

1 に答える 1

9

そうですね、答えを探し続けると...

Linux では、使用する共有メモリ メカニズム ( tmpfs) により、デフォルトでシステム RAM の半分に制限されます。私のクラスターでは、4 Gb のシステム RAM があるため、2 Gb です。そのため、共有メモリ セグメントを割り当てようとしたときに、最大サイズまで割り当てられました/dev/shm

しかし、Boost ライブラリがエラーを示さなかったり、要求された量のメモリを割り当てることができなかったときに正しい量の空きメモリを報告したりするときに問題が発生しました。セグメントの最後に到達してからエラーになるまで、どうやら一気飲みしただけでうれしかったです。

長期的な解決策は、/etc/fstabファイルを更新して変更を永続的に行うことですが、コマンド ライン呼び出しを実行して、再起動するまで各ノードで使用可能な共有メモリのサイズを増やすことができます。

mount -o remount,size=XXX /dev/shm

ここで、XXXは使用可能にするメモリの量です (例: size=4G)。

これは、 http: //www.cyberciti.biz/tips/what-is-devshm-and-its-practical-usage.html から把握/取得したものです。

于 2010-06-24T13:51:15.610 に答える