Я пишу процедуру для сравнения двух файлов с использованием файла с отображением памяти. В случае, если файлы слишком большие, чтобы их можно было сопоставить за один раз. Я разделял файлы и составлял их по частям. Например, чтобы отобразить файл 1049 МБ, я разделил его на 512 МБ + 512 МБ + 25 МБ.
Все прекрасно работает, кроме одного: для сравнения остатка всегда требуется намного больше времени (25 МБ в этом примере), хотя логика кода точно такая же. 3 наблюдения:
- Не имеет значения, что сначала сравнивается: первая часть (512 МБ * N) или остаток (25 МБ в этом примере) на первом месте, результат остается тем же самым
- дополнительное время в остатке, по-видимому, расходуется в режиме пользователя
- Профилирование в VS2010 beta 1 показывает, что время тратится на t
std::_Equal()
, но эта функция в основном (профайлер говорит 100%) ждет ввода-вывода и других потоков.
Я пробовал
- изменение VIEW_SIZE_FACTOR на другое значение
- заменив лямбда-функтор на функцию-член
- изменение размера файла в тесте
- изменение порядка выполнения остатка до/после цикла
Результат был довольно последовательным: он занимает намного больше времени в оставшейся части и в режиме пользователя.
Я подозреваю, что он имеет какое-то отношение к тому факту, что сопоставленный размер не кратен выравниванию сопоставления (64 КБ в моей системе), но не уверен, как это сделать.
Ниже приведен полный код для процедуры и время, измеренное для файла 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 байт для оставшегося раунда
real 116.892s, cpu 56.201s (48.1%), пользователь 54.548s, система 1.652s
размер сегмента = 536870912 байтов, раунд # 0
real 72.258s, cpu 2.273s (3.1%), пользователь 0.320s, система 1.953s
размер сегмента = 536870912 байтов, раунд № 1
real 75.304s, cpu 1.943s (2.6%), пользователь 0.240s, система 1.702s
размер сегмента = 536870912 байтов, раунд № 2
real 84.328s, cpu 1.783s (2.1%), пользователь 0.320s, система 1.462s
размер сегмента = 536870912 байтов, раунд № 3
real 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 = остаток - тело. 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 ПК с теми же конфигурациями h/w с моим, результат последователен, как показано ниже:
------ VS2010Beta1ENU_VSTS.iso [1319909376 bytes] ------
Размер остатка = 44840960 байт
Размер Remainder_tail = 14336 байт
real 0.060s, cpu 0.040s (66.7%), пользователь 0.000s, система 0.040s
Размер Remainder_body = 44826624 байта
real 13.601s, cpu 7.731s (56.8%), пользователь 7.481s, система 0.250s
размер сегмента = 67108864 байт, общий раунд # = 19
real 172.476s, cpu 4.356s (2.5%), пользователь 0.731s, система 3.625s
Однако запуск одного и того же кода на ПК с другой конфигурацией h/w дало:
------ VS2010Beta1ENU_VSTS.iso [1319909376 bytes] ------ Размер остатка = 44840960 байт
Размер Remainder_tail = 14336 байт
real 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
real 65.587s, ccu 4.578s (7.0%), пользователь 0.844s, система 3.734s
Информация о системе
Моя рабочая станция дает непонятные сроки:
Название ОС: Microsoft Windows XP Professional
Версия ОС: 5.1.2600 Service Pack 3 Build 2600
ОС Производитель: Microsoft Corporation
Конфигурация ОС: рабочая станция участника
OS Тип сборки: Uniprocessor Free
Оригинальная дата установки: 2004-01-27, 23:08
Время работы системы: 3 дня, 2 часа, 15 минут, 46 секунд
Производитель системы: Dell Inc.
Модель системы: OptiPlex GX520
Тип системы: ПК на базе X86
Процессор (ы): 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 МБ
Доступная физическая память: 1,986 МБ
Виртуальная память: Макс. размер: 2,048 МБ
Виртуальная память: доступно: 1,916 МБ
Виртуальная память: при использовании: 132 МБ
Местоположение файла: C:\pagefile.sys
Карта (и) NetWork: Установлены 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
Конфигурация ОС: рабочая станция участника
Тип сборки ОС: безпроцессорный
Оригинальная дата установки: 18.05.2009, 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 МБ
Доступная физическая память: 1,682 МБ
Виртуальная память: Макс. размер: 2,048 МБ
Виртуальная память: доступно: 2,007 МБ
Виртуальная память: при использовании: 41 МБ
Местоположение файла: C:\pagefile.sys
Карта (и) NetWork: Установлены 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
Любая теория объяснений? Спасибо.