我正在编写一个例程,以使用内存映射文件比较两个文件。如果文件太大而无法一次映射。我拆分了文件,并部分地映射它们。例如,要映射1049MB的文件,我将其拆分为512MB + 512MB + 25MB。
除一件事外,其他所有事物都可以正常工作:比较其余部分(本示例中为25MB)通常会花费很多,更长的时间,尽管代码逻辑是完全相同的。 3个观察结果:
std::_Equal()
内部,但是此功能主要(分析器认为100%)等待I/O和其他线程。 我试过了
结果是非常一致的:在其余部分和用户模式中,这花费了更多时间。
我怀疑这与以下事实有关:映射的大小不是映射对齐方式的倍数(在我的系统上为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.892s,cpu 56.201s(48.1%),用户54.548s,系统1.652s
段大小= 536870912字节,第0回合
真实72.258s,cpu 2.273s(3.1%),用户0.320s,系统1.953s
段大小= 536870912字节,第1回合
实际75.304s,cpu 1.943s(2.6%),用户0.240s,系统1.702s
段大小= 536870912字节,第2回合
实际84.328s,cpu 1.783s(2.1%),用户0.320s,系统1.462s
段大小= 536870912字节,第3回合
真实73.901s,cpu 1.702s(2.3%),用户0.330s,系统1.372s
回应者的建议后,更多观察
进一步将其余部分拆分为 body 和尾部(剩余= body +尾部),其中
总时间保持不变,但是我可以看到时间不一定与尾部有关,而与 body 和尾部的大小有关。更大的部分需要更多的时间。时间是USER TIME,这对我来说是最不可理解的。
我也通过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.060s,cpu 0.040s(66.7%),用户0.000s,系统0.040s
Remainder_body大小= 44826624字节
实际13.601s, cpu 7.731s(56.8%),用户7.481s ,系统0.250s
段大小= 67108864字节,总回合数= 19
真实172.476s,cpu 4.356s(2.5%),用户0.731s,系统3.625s
但是,在具有不同硬件配置的PC上运行相同代码会产生:
------ VS2010Beta1ENU_VSTS.iso [1319909376字节] ------
剩余大小= 44840960字节
Remainder_tail大小= 14336字节
实际0.013s,cpu 0.000s(0.0%),用户0.000s,系统0.000s
Remainder_body大小= 44826624字节
真实2.468s,cpu 0.188s(7.6%),用户0.047s,系统0.141s
段大小= 67108864字节,总回合数= 19
真实65.587s,cpu 4.578s(7.0%),用户0.844s,系统3.734s
系统信息
我的工作站产生了难以理解的时间安排:
操作系统名称:Microsoft Windows XP Professional
操作系统版本:5.1.2600 Service Pack 3 Build 2600
操作系统制造商:Microsoft Corporation
操作系统配置:成员工作站
操作系统内部版本类型:单处理器免费
原始安装日期: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
另一个产生“正确”计时的工作站:
操作系统名称:Microsoft Windows XP Professional
操作系统版本:5.1.2600 Service Pack 3 Build 2600
操作系统制造商:Microsoft Corporation
操作系统配置:成员工作站
操作系统内部版本类型:多处理器免费
原始安装日期: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
有什么解释理论吗?谢谢。
最佳答案
这种行为看起来很不合逻辑。我想知道如果我们尝试一些愚蠢的事情会怎样。如果整个文件大于512MB,则可以再比较最后一部分的完整512MB,而不是剩余大小。
就像是:
if(remainder > 0)
{
cout << "segment size = "
<< remainder
<< " bytes for the remaining round";
if (size > segment_size){
block_size = segment_size;
offset = size - segment_size;
}
else{
block_size = remainder;
offset = segment_size * i
}
if(!segment_compare(block_size, offset)) return false;
}
这样做似乎很愚蠢,因为我们会将文件的一部分与进行两次比较,但是如果您的分析数据准确,它应该会更快。
它不会给我们答案(但是),但是如果确实更快,则意味着我们正在寻找的响应取决于您的程序对小块数据的处理方式。
关于c++ - 使用内存映射文件所花费的时间无法理解,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/1371996/