我正在编写一个例程,使用内存映射文件比较两个文件。以防文件太大而无法一次性映射。我把文件分开,一部分一部分地映射。例如,要映射1049MB文件,我将其拆分为512MB+512MB+25MB。
除了一件事之外,其他事情都很好:比较剩余的(本例中为25mb)总是要花费很长的时间,尽管代码逻辑完全相同。3观察结果:
-
先比较哪个并不重要,不管是主部分(512mb*n)还是剩余部分(本例中是25mb)先比较,结果都是一样的
-
剩下的额外时间似乎花在
用户模式
-
VS2010 Beta 1中的分析显示,时间花费在
std::_Equal()
,但这个函数主要(profiler说是100%)在等待I/O和其他线程。
我试过
-
将视图大小因子更改为另一个值
-
用成员函数替换lambda函子
-
更改测试中的文件大小
-
将余数的执行顺序更改为循环之前/之后
结果是相当一致的:在剩下的部分和在
用户模式
.
我怀疑这与映射的大小不是映射对齐的倍数(在我的系统上是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字节,四舍五入
实际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=n*alignment()和tail<1*alignment()
-
body=m*alignment(),tail<1*alignment()+n*alignment(),其中m为偶数。
-
body=m*alignment(),tail<1*alignment()+n*alignment(),其中m是2的指数。
-
body=n*alignment(),tail=余数-body。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;
}
}
观察:
在另外两台与我公司相同H/W配置的PC上,结果一致如下:
----vs2010beta1enu\u vsts.iso[1319909376字节]-----
剩余大小=44840960字节
余数尾部大小=14336字节
实际0.060s,CPU 0.040s(66.7%),用户0.000s,系统0.040s
余数体大小=44826624字节
实际13.601s,
CPU 7.731(56.8%),用户7.481
,系统0.250s
段大小=67108864字节,总整数=19
实际172.476s,CPU 4.356s(2.5%),用户0.731s,系统3.625s
但是,在具有不同H/W配置的PC上运行相同的代码会产生:
----vs2010beta1enu\u vsts.iso[1319909376字节]-----
剩余大小=44840960字节
余数尾部大小=14336字节
实际0.013s,CPU 0.000s(0.0%),用户0.000s,系统0.000s
余数体大小=44826624字节
真实2.468秒,
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
操作系统制造商:微软公司
操作系统配置:成员工作站
操作系统生成类型:无单处理器
原始安装日期:2004-01-27,23:08
系统启动时间:3天2小时15分46秒
系统制造商:戴尔公司
系统型号: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
启动设备:\设备\硬盘卷2
系统所在地:zh cn;中文(中国)
输入语言环境:zh cn;中文(中国)
时区:(GMT+08:00)北京、重庆、香港、乌鲁木齐
总物理内存:3574 MB
可用物理内存:1986 MB
虚拟内存:最大大小:2048MB
虚拟内存:可用:1916MB
虚拟内存:正在使用:132 MB
页面文件位置:C:\ page file.sys
网卡:已安装3个网卡。
[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
操作系统制造商:微软公司
操作系统配置:成员工作站
OS构建类型:无多处理器
原始安装日期:2009年5月18日下午2:28:18
系统启动时间:21天5小时0分49秒
系统制造商:戴尔公司
系统型号: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
启动设备:\设备\硬盘卷1
系统所在地:zh cn;中文(中国)
输入语言环境:en-us;英语(美国)
时区:(GMT+08:00)北京、重庆、香港、乌鲁木齐
总物理内存:3317 MB
可用物理内存:1682 MB
虚拟内存:最大大小:2048MB
虚拟内存:可用:2007 MB
虚拟内存:正在使用:41 MB
页面文件位置:C:\ page file.sys
网卡:已安装3个网卡。
[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
有什么解释理论吗?谢谢。