メモリ マップト ファイルを使用して 2 つのファイルを比較するルーチンを作成しています。ファイルが大きすぎて一度にマップできない場合。ファイルを分割し、パーツごとにマップします。たとえば、1049MB のファイルをマップするには、512MB + 512MB + 25MB に分割します。
コード ロジックはまったく同じですが、残りの部分 (この例では 25MB) を比較するのに常に非常に長い時間がかかります。3 つの観察:
- 主要部分 (512MB * N) と残り (この例では 25MB) のどちらが先に比較されても、結果は同じままです。
- 残りの余分な時間はユーザーモードで費やされているようです
- VS2010 ベータ 1 でのプロファイリングでは、時間は t 内で費やされ
std::_Equal()
ますが、この関数はほとんど (プロファイラーは 100% と言います) I/O および他のスレッドを待機しています。
私は試した
- VIEW_SIZE_FACTOR を別の値に変更する
- ラムダファンクターをメンバー関数に置き換える
- テスト中のファイルサイズの変更
- 残りの実行順序をループの前後に変更する
結果は非常に一貫していました。残りの部分とユーザーモードでより多くの時間がかかりました。
マップされたサイズがマッピングの配置 (私のシステムでは 64K) の倍数ではないという事実と関係があると思われますが、その方法はわかりません。
以下は、ルーチンの完全なコードと 3G ファイルで測定されたタイミングです。
誰か説明してくれませんか、ありがとう?
// using memory-mapped file
template <size_t VIEW_SIZE_FACTOR>
struct is_equal_by_mmapT
{
public:
bool operator()(const path_type& p1, const path_type& p2)
{
using boost::filesystem::exists;
using boost::filesystem::file_size;
try
{
if(!(exists(p1) && exists(p2))) return false;
const size_t segment_size = mapped_file_source::alignment() * VIEW_SIZE_FACTOR;
// lanmbda
boost::function<bool(size_t, size_t)> segment_compare =
[&](size_t seg_size, size_t offset)->bool
{
using boost::iostreams::mapped_file_source;
boost::chrono::run_timer t;
mapped_file_source mf1, mf2;
mf1.open(p1, seg_size, offset);
mf2.open(p2, seg_size, offset);
if(! (mf1.is_open() && mf2.is_open())) return false;
if(!equal (mf1.begin(), mf1.end(), mf2.begin())) return false;
return true;
};
boost::uintmax_t size = file_size(p1);
size_t round = size / segment_size;
size_t remainder = size & ( segment_size - 1 );
// compare the remainder
if(remainder > 0)
{
cout << "segment size = "
<< remainder
<< " bytes for the remaining round";
if(!segment_compare(remainder, segment_size * round)) return false;
}
//compare the main part. take much less time, even
for(size_t i = 0; i < round; ++i)
{
cout << "segment size = "
<< segment_size
<< " bytes, round #" << i;
if(!segment_compare(segment_size, segment_size * i)) return false;
}
}
catch(std::exception& e)
{
cout << e.what();
return false;
}
return true;
}
};
typedef is_equal_by_mmapT<(8<<10)> is_equal_by_mmap; // 512MB
出力:
残りのラウンドのセグメント サイズ = 354410496 バイト
実際の 116.892 秒、CPU 56.201 秒 (48.1%)、ユーザー 54.548 秒、システム 1.652 秒
セグメント サイズ = 536870912 バイト、ラウンド #0
実際の 72.258 秒、CPU 2.273 秒 (3.1%)、ユーザー 0.320 秒、システム 1.953 秒
セグメント サイズ = 536870912 バイト、ラウンド #1
実際の 75.304 秒、CPU 1.943 秒 (2.6%)、ユーザー 0.240 秒、システム 1.702 秒
セグメント サイズ = 536870912 バイト、ラウンド #2
実際の 84.328 秒、CPU 1.783 秒 (2.1%)、ユーザー 0.320 秒、システム 1.462 秒
セグメント サイズ = 536870912 バイト、ラウンド #3
実際の 73.901 秒、CPU 1.702 秒 (2.3%)、ユーザー 0.330 秒、システム 1.372 秒
レスポンダーによる提案後のさらなる観察
残りをボディとテールにさらに分割します (残り = ボディ + テール)。
- ボディ = N * アライメント()、テール < 1 * アライメント()
- 本体 = m * 配置 ()、および末尾 < 1 * 配置 () + n * 配置 ()、ここで m は偶数です。
- ボディ = m * アライメント()、テール < 1 * アライメント() + n * アライメント()、m は 2 の指数です。
- 本体 = N * 配置 ()、テール = 残り - 本体。N はランダムです。
合計時間は変化しませんが、時間は必ずしも尻尾に関係しているのではなく、体と尻尾のサイズに関係していることがわかります。大きい部分ほど時間がかかります。時間は、私には最も理解できないユーザータイムです。
また、Procexp.exe を介してページ フォールトも確認します。残りは、メイン ループより多くのフォールトを取りません。
アップデート 2
他のワークステーションでいくつかのテストを実行しましたが、問題はハードウェア構成に関連しているようです。
テストコード
// compare the remainder, alternative way
if(remainder > 0)
{
//boost::chrono::run_timer t;
cout << "Remainder size = "
<< remainder
<< " bytes \n";
size_t tail = (alignment_size - 1) & remainder;
size_t body = remainder - tail;
{
boost::chrono::run_timer t;
cout << "Remainder_tail size = " << tail << " bytes";
if(!segment_compare(tail, segment_size * round + body)) return false;
}
{
boost::chrono::run_timer t;
cout << "Remainder_body size = " << body << " bytes";
if(!segment_compare(body, segment_size * round)) return false;
}
}
観察:
私と同じハードウェア構成を持つ別の 2 台の PC では、結果は次のように一貫しています。
------VS2010Beta1ENU_VSTS.iso [1319909376 バイト] ------
残りのサイズ = 44840960 バイト
Remainder_tail サイズ = 14336 バイト
実際の 0.060 秒、CPU 0.040 秒 (66.7%)、ユーザー 0.000 秒、システム 0.040 秒
Remainder_body サイズ = 44826624 バイト
実際の 13.601 秒、CPU 7.731 秒 (56.8%)、ユーザー 7.481 秒、システム 0.250 秒
セグメント サイズ = 67108864 バイト、合計ラウンド数 = 19
実際の 172.476 秒、CPU 4.356 秒 (2.5%)、ユーザー 0.731 秒、システム 3.625 秒
ただし、ハードウェア構成が異なる PC で同じコードを実行すると、次の結果が得られました。
------VS2010Beta1ENU_VSTS.iso [1319909376 バイト] ------ 残りのサイズ = 44840960 バイト
Remainder_tail サイズ = 14336 バイト
実際の 0.013 秒、CPU 0.000 秒 (0.0%)、ユーザー 0.000 秒、システム 0.000 秒
Remainder_body サイズ = 44826624 バイト
実際の 2.468 秒、CPU 0.188 秒 (7.6%)、ユーザー 0.047 秒、システム 0.141 秒
セグメント サイズ = 67108864 バイト、合計ラウンド数 = 19
実際の 65.587 秒、CPU 4.578 秒 (7.0%)、ユーザー 0.844 秒、システム 3.734 秒
システム情報
私のワークステーションは理解できないタイミングをもたらします:
OS名:Microsoft Windows XP Professional
OS バージョン: 5.1.2600 サービス パック 3 ビルド 2600
OSメーカー:マイクロソフトコーポレーション
OS 構成: メンバー ワークステーション
OS ビルド タイプ: ユニプロセッサ フリー
元のインストール日: 2004-01-27, 23:08
システム稼働時間: 3 日 2 時間 15 分 46 秒
システム メーカー: Dell Inc.
システム モデル: OptiPlex GX520
システムの種類: X86 ベースの PC
プロセッサ: 1 プロセッサがインストールされています。
[01]: x86 Family 15 Model 4 Stepping 3 GenuineIntel ~2992 Mhz
BIOS バージョン: DELL-7
Windows ディレクトリ: C:\WINDOWS
システム ディレクトリ: C:\WINDOWS\system32
起動デバイス: \Device\HarddiskVolume2
システム ロケール: zh-cn;中国語 (中国)
入力ロケール: zh-cn;中国語 (中国)
時間帯: (GMT+08:00) 北京、重慶、香港、ウルムチ
合計物理メモリ: 3,574 MB
利用可能な物理メモリ: 1,986 MB
仮想メモリ: 最大サイズ: 2,048 MB
仮想メモリ: 利用可能: 1,916 MB
仮想メモリ: 使用中: 132 MB
ページ ファイルの場所: C:\pagefile.sys
ネットワーク カード: 3 NIC がインストールされています。
[01]: VMware Virtual Ethernet Adapter for VMnet1
Connection Name: VMware Network Adapter VMnet1
DHCP Enabled: No
IP address(es)
[01]: 192.168.75.1
[02]: VMware Virtual Ethernet Adapter for VMnet8
Connection Name: VMware Network Adapter VMnet8
DHCP Enabled: No
IP address(es)
[01]: 192.168.230.1
[03]: Broadcom NetXtreme Gigabit Ethernet
Connection Name: Local Area Connection 4
DHCP Enabled: Yes
DHCP Server: 10.8.0.31
IP address(es)
[01]: 10.8.8.154
「正しい」タイミングをもたらす別のワークステーション: OS 名: Microsoft Windows XP Professional
OS バージョン: 5.1.2600 サービス パック 3 ビルド 2600
OSメーカー:マイクロソフトコーポレーション
OS 構成: メンバー ワークステーション
OS ビルド タイプ: マルチプロセッサ フリー
元のインストール日: 2009 年 5 月 18 日、午後 2:28:18
システム稼働時間: 21 日 5 時間 0 分 49 秒
システム メーカー: Dell Inc.
システム モデル: OptiPlex 755
システムの種類: X86 ベースの PC
プロセッサ: 1 プロセッサがインストールされています。
[01]: x86 Family 6 Model 15 Stepping 13 GenuineIntel ~2194 Mhz
BIOS バージョン: DELL-15
Windows ディレクトリ: C:\WINDOWS
システム ディレクトリ: C:\WINDOWS\system32
起動デバイス: \Device\HarddiskVolume1
システム ロケール: zh-cn;中国語 (中国)
入力ロケール: en-us;英語 (米国)
時間帯: (GMT+08:00) 北京、重慶、香港、ウルムチ
合計物理メモリ: 3,317 MB
利用可能な物理メモリ: 1,682 MB
仮想メモリ: 最大サイズ: 2,048 MB
仮想メモリ: 利用可能: 2,007 MB
仮想メモリ: 使用中: 41 MB
ページ ファイルの場所: C:\pagefile.sys
ネットワーク カード: 3 NIC がインストールされています。
[01]: Intel(R) 82566DM-2 Gigabit Network Connection
Connection Name: Local Area Connection
DHCP Enabled: Yes
DHCP Server: 10.8.0.31
IP address(es)
[01]: 10.8.0.137
[02]: VMware Virtual Ethernet Adapter for VMnet1
Connection Name: VMware Network Adapter VMnet1
DHCP Enabled: Yes
DHCP Server: 192.168.154.254
IP address(es)
[01]: 192.168.154.1
[03]: VMware Virtual Ethernet Adapter for VMnet8
Connection Name: VMware Network Adapter VMnet8
DHCP Enabled: Yes
DHCP Server: 192.168.2.254
IP address(es)
[01]: 192.168.2.1
説明理論はありますか?ありがとう。