除了一件事情外,一切都正常:无论先比较哪一个,主要部分(512MB * N)还是余数(在这个例子中为25MB),结果都是相同的。三个观察结果:
1. 先比较哪一个并不重要,结果都是相同的,不管是先比较主要部分还是先比较余数。 2. 余数部分似乎花费了更多时间在用户模式下。 3. 在VS2010 beta 1中进行分析显示,时间花费在
std::_Equal()
内部,但该函数大多数时间(分析器说100%)在等待I/O和其他线程。我尝试了以下操作:
1. 将VIEW_SIZE_FACTOR更改为其他值。 2. 用成员函数替换Lambda函数。 3. 更改要测试的文件大小。 4. 更改余数执行的顺序为循环之前或之后。
结果非常一致:在余数部分和用户模式下需要更长的时间。
我怀疑这与映射大小不是映射对齐的倍数(在我的系统上为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秒
第0轮的段大小为536870912字节
实际时间72.258秒,CPU时间2.273秒(3.1%),用户时间0.320秒,系统时间1.953秒
第1轮的段大小为536870912字节
实际时间75.304秒,CPU时间1.943秒(2.6%),用户时间0.240秒,系统时间1.702秒
第2轮的段大小为536870912字节
实际时间84.328秒,CPU时间1.783秒(2.1%),用户时间0.320秒,系统时间1.462秒
第3轮的段大小为536870912字节
实际时间73.901秒,CPU时间1.702秒(2.3%),用户时间0.330秒,系统时间1.372秒
回应者建议后的更多观察
进一步将剩余部分分为主体和尾部(remainder = body + tail),其中
- 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 = remainder - 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;
}
}
观察:
在另外两台与我的硬件配置相同的电脑上,结果如下:
------VS2010Beta1ENU_VSTS.iso [1319909376 字节] ------
剩余大小 = 44840960 字节
剩余尾部大小 = 14336 字节
实际时间为 0.060 秒,CPU 时间为 0.040 秒(66.7%),用户时间为 0.000 秒,系统时间为 0.040 秒
剩余主体大小 = 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 秒
然而,在一台不同硬件配置的电脑上运行同样的代码产生了以下结果:
------VS2010Beta1ENU_VSTS.iso [1319909376 字节] ------
剩余大小 = 44840960 字节
剩余尾部大小 = 14336 字节
实际时间为 0.013 秒,CPU 时间为 0.000 秒(0.0%),用户时间为 0.000 秒,系统时间为 0.000 秒
剩余主体大小 = 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 秒
系统信息
我的工作站产生了无法理解的计时:
操作系统名称:Microsoft Windows XP Professional
操作系统版本号:5.1.2600 Service Pack 3 Build 2600
操作系统制造商:Microsoft Corporation
操作系统配置:成员工作站
操作系统类型:单处理器 Free
最初安装日期: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 张网卡。
[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的个人电脑 处理器:已安装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
有任何解释理论吗?谢谢。