Модераторы: Daevaorn
  

Поиск:

Ответ в темуСоздание новой темы Создание опроса
> Memory Mapped file 
:(
    Опции темы
cupper
Дата 11.10.2011, 15:39 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Сравниваю производительность FILE (fwrite) и аналога для MMap.

Начну сразу с результатов. 
FILE работает стабильно быстрее, не сжирает оперативку, сжирает весь кеш.
MM работает произвольно (т.е. один запуск может дать время x, запуск через некоторое время может дать время 2*x), сжирает весь кэш, если в ручную не делать flush, так же сжирает все оперативку под ноль, система аж загибается.


В тесте, произвожу запись n-го числа записей. Общий размер получаемого файла ~3GB. Время замеряю через 
Код

clock_t start_load = clock();
// do
cout << "    --> result time: " << (clock() - start_get)/CLOCKS_PER_SEC << endl;


Делаю запуски отдельно для FILE отдельно для MM с временным интервалом, на передышку железу.
Испытуемые функции
Код

void write_f(const string& msg, size_t count)
{
    remove("file");
    cout << "Start test fwite\n";
    clock_t start = clock();

    FILE *file = fopen("file", "w+");

    for(int i = 0; i < count; i++)
        fwrite(msg.c_str(), 1, msg.size(), file);

    fclose(file);

    cout << "result time: " << (clock() - start)/CLOCKS_PER_SEC << endl;
}
void write_mm(const string& msg, size_t count)
{
    remove("file");
    FILE *file = fopen("file", "w+");
    fclose(file);
    cout << "Start test mm wite\n";
    clock_t start = clock();

    {
        file_mapping file1("file", mode_t::read_write);
        MMFile file(&file1, 1);
        
        for(int i = 0; i < count; i++)
            file.write(msg.c_str(), msg.size());
        
    }

    cout << "result time: " << (clock() - start)/CLOCKS_PER_SEC << endl;
}


Реализация MM используется бустовская, из за кроссплатформенности.

MMFile, имплементация, над file_mapping и region_mapped.
Функция write()
Код

size_t MMFile::write( char const* buf, size_t size )
{
    Offset tell_size = static_cast<offset_t>(tell() + size);
    size_t retWtire = size;

    if(tell_size > fileSize_ )
    {
        truncate(tell_size);
    }

    char const* end = buf + size;
    char* windowEnd = reinterpret_cast<char *>( region_.get_address() ) + windowSize_;

    for( ;; )
    {
        if( size <= bytesLeft_ )
        {
            memcpy( windowEnd - bytesLeft_, end - size, size );
            bytesLeft_ -= size;
            break;
        }
        else
        {
            memcpy( windowEnd - bytesLeft_, end - size, bytesLeft_ );
            size -= bytesLeft_;

            bytesLeft_ = windowSize_;

            if(flushPage_++ > 10)
            {
                region_.flush();
                flushPage_ = 0;
            }
            region_ = mapped_region( file_, read_write, region_.get_offset() + windowSize_, windowSize_ );
            windowEnd = reinterpret_cast<char *>( region_.get_address() ) + windowSize_;
            
        }
    }

    return retWtire;
}


Код
Код

            if(flushPage_++ > 10)
            {
                region_.flush();
                flushPage_ = 0;
            }

вставлен для избежания сжирания всей оперативки. Иначе это происходит.

Собстно, проблема именно в том почему MM работает медленнее, когда все бьют в грудь что мол работает быстрее и лучше.


Как это вижу я:
В случаем с MM:
при маппинге очередного региона, он считывается из диска в кеш, после чего отображается в пространство пользователя (т.е. не происходит копирования). При большом числе итераций записи, кеш забивается новыми страницами, которые так же быстро отображаюсться в пространство процесса, из за чего тот сжирает всю оперативку, так как flush не происходит при достигании какого то лимита, я происходит когданибудь потом. Как правило когда оперативка и кешь весь сожран и деваться уже некуда, и тут начинаются тормоза. Которые и сводят на 0 все эти плюшки с отображением.

-------------------------------------------------------------------------
Маппим ровно по page_size.



Измененные условия теста:
Маппим по 10 * page_size, делаешм flush перед каждый новым маппингом, получаем время работы x (примерно равное fwrite)
Маппим по 10 * page_size, делаешм flush на каждый 10 маппинг, получаем время работы 2.3 * x 

Маппим по 10 * page_size, не делаешм flush, получаем время работы x/3. размер файла примерно равен размеру свободной оперативки. После система на некоторое время подвисла.

Сохраню поста, и попробую с файлом большем чем размер оперативки.

Добавлено через 14 минут и 34 секунды
В общем если не делать flush то это происходит только при сжиранию всей оперативки, что приводит к временному зависанию системы. Такой вариант совсем неудовлетворительный.
PM MAIL   Вверх
cupper
Дата 11.10.2011, 16:07 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



если делать flush в ручную, то в лучшем случае время работы такое же как у fwrite, в худшем на 30% дольше.

На основе чего напрашивается вывод, для для логики, когда требуется постоянная запись в файл и соответственно его увеличение, MM не лучший вариант :(
Думаю для логики когда надо прочитать весь файл небольшими кусочками это тоже не даст прироста, собственно как и при доступе к произвольной позиции.


PM MAIL   Вверх
newbee
Дата 11.10.2011, 16:48 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



Цитата(cupper @  11.10.2011,  17:07 Найти цитируемый пост)
Думаю для логики когда надо прочитать весь файл небольшими кусочками это тоже не даст прироста, собственно как и при доступе к произвольной позиции.


Скорость чтения через read сложно довести до скорости чтения через mmap. То есть теоретически ее можно подогна вплотную, но код получится очень системозависимым, тут плясать нужно не столько в сторону page_size, сколько в размер кешей процессора. В общем эксперементальным путем мне удавалось практически сравнять скорости, но это был метод тыка. mmap это делает сам.

Еще mmap зачастую намного удобнее, стандартные функции работы с памятью намного богаче тех, что связаны с файловым вводом-выводом, не нужно городить еще один слой буферизации данных. Я честно не знаю на практике ка кобстоят дела с массированной записью черз mmap, но думаю у тебя все уперлось в кривую настройку шедулера процессов и памяти, по симптомам очень похоже.

ПС. ОС, архитектура какие?


--------------------
You're face to face
With man who sold the world
PM   Вверх
cupper
Дата 12.10.2011, 10:17 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



Цитата(newbee @ 11.10.2011,  16:48)
Цитата(cupper @  11.10.2011,  17:07 Найти цитируемый пост)
Думаю для логики когда надо прочитать весь файл небольшими кусочками это тоже не даст прироста, собственно как и при доступе к произвольной позиции.


Скорость чтения через read сложно довести до скорости чтения через mmap. То есть теоретически ее можно подогна вплотную, но код получится очень системозависимым, тут плясать нужно не столько в сторону page_size, сколько в размер кешей процессора. В общем эксперементальным путем мне удавалось практически сравнять скорости, но это был метод тыка. mmap это делает сам.

Еще mmap зачастую намного удобнее, стандартные функции работы с памятью намного богаче тех, что связаны с файловым вводом-выводом, не нужно городить еще один слой буферизации данных. Я честно не знаю на практике ка кобстоят дела с массированной записью черз mmap, но думаю у тебя все уперлось в кривую настройку шедулера процессов и памяти, по симптомам очень похоже.

ПС. ОС, архитектура какие?

ОС кросcплатформенность, x32/x64.

Если сравнивать только операции write и memcpy (в случае mm), с файлом заданного размера, и если мапим весь файл сразу, то да прирост в 10 раз. Только вот на сколько такой тест верен? Ведь, если файл будет большой (для чего собсно mm и используется) то придется городить огороды с маппингом по частям, что все равно приведет к сжиранию всей оперативки под ноль и временному отказу систему (пока ОС не сбросит буфера на диск). А еще и размер файла далеко не константный и заранее не известный и он растет по мере появления данных, следовательно постоянные truncat, и опять таки (в зависимости от скорости пробега по файлу) сжирание всей оперативки.

А причем тут шедулер ?
PM MAIL   Вверх
boostcoder
Дата 12.10.2011, 10:40 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


pattern`щик
****


Профиль
Группа: Завсегдатай
Сообщений: 5458
Регистрация: 1.4.2010

Репутация: 49
Всего: 110



ну не знаю, откуда могло взяться мнение что маппинг файла работает быстрее прямых файловых операций. удобно? - да. но не производительней.
PM WWW   Вверх
newbee
Дата 12.10.2011, 10:47 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Бревно
**


Профиль
Группа: Участник
Сообщений: 703
Регистрация: 24.8.2011

Репутация: 4
Всего: 19



Цитата(cupper @  12.10.2011,  11:17 Найти цитируемый пост)
ОС кросcплатформенность, x32/x64.
То есть ты проводил одинаковые тесты на нескольких платформах?

Цитата(cupper @  12.10.2011,  11:17 Найти цитируемый пост)
Если сравнивать только операции write и memcpy (в случае mm), с файлом заданного размера, и если мапим весь файл сразу, то да прирост в 10 раз. Только вот на сколько такой тест верен? Ведь, если файл будет большой (для чего собсно mm и используется) то придется городить огороды с маппингом по частям, что все равно приведет к сжиранию всей оперативки под ноль и временному отказу систему (пока ОС не сбросит буфера на диск). А еще и размер файла далеко не константный и заранее не известный и он растет по мере появления данных, следовательно постоянные truncat, и опять таки (в зависимости от скорости пробега по файлу) сжирание всей оперативки.
1. Фактическая запись файла на диск через mmap не может быть быстрее в 10 раз записи через write. Скорее всего ты увидел работу кешей, т.е. write пишет прямо сейчас, а mmap бросила в буфер, а когда уж оно там реально запишется - не ее дело. Я знаю, что при записи через write тоже используется буферизация.

2. mmap в первую очередь предоставляет удобство программисту, и она не виновата, что он пытается использовать ее несколько не по назначению.

Цитата(cupper @  12.10.2011,  11:17 Найти цитируемый пост)
А причем тут шедулер ? 
У тебя система колом встает при свопинге! Настрока более агрессивной политики сброса ненужных данных на диск должна помочь. Ну а шедулер именно процессов тут и правда ни при чем.

ПС. Весь цимес в пункте 2.


--------------------
You're face to face
With man who sold the world
PM   Вверх
xvr
Дата 12.10.2011, 11:29 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Комодератор
Сообщений: 7046
Регистрация: 28.8.2007
Где: Дублин, Ирландия

Репутация: 60
Всего: 223



Цитата(cupper @  12.10.2011,  10:17 Найти цитируемый пост)
и если мапим весь файл сразу, то да прирост в 10 раз.

А если не сразу - то нужно 10 раз прежде подумать, нужен ли тут mmap  smile 
Постоянные изменения мэпинга могут запросто быть более накладными, чем 10 прямых записей в параллель  smile 

PM MAIL   Вверх
cupper
Дата 12.10.2011, 14:37 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Опытный
**


Профиль
Группа: Участник
Сообщений: 525
Регистрация: 29.11.2006

Репутация: 1
Всего: 1



ну по сути подтвердили мои предположения.

Тогда вопрос, mmap может дать реальный прирост только в ситуациях когда мы с файлом работаем много и часто что проще держать его в памяти ну или в его часть.
PM MAIL   Вверх
bsa
Дата 12.10.2011, 18:14 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Модератор
Сообщений: 9185
Регистрация: 6.4.2006
Где: Москва, Россия

Репутация: 63
Всего: 196



cupper, имхо, mmap удобней тогда, когда ты работаешь с большим (не огромным!) файлом фиксированной длины.  Причем функции обработки данных умеют работать только с памятью. Или они выполняют случайный доступ к случайных ячейкам.
В остальных случаях, имхо, проще работать с файлом напрямую.
PM   Вверх
math64
Дата 12.10.2011, 21:59 (ссылка) | (нет голосов) Загрузка ... Загрузка ... Быстрая цитата Цитата


Эксперт
****


Профиль
Группа: Завсегдатай
Сообщений: 2505
Регистрация: 12.4.2007

Репутация: 8
Всего: 72



Ещё mmap можно использовать для общего доступа к памяти двух программ, в Linux физический файл на диске можно не создавать, в Windows наверно тоже - в этом случае mmap действительно будет работать быстрее.
PM   Вверх
  
Ответ в темуСоздание новой темы Создание опроса
Правила форума "С++:Общие вопросы"
Earnest Daevaorn

Добро пожаловать!

  • Черновик стандарта C++ (за октябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика(4.4мб).
  • Черновик стандарта C (за сентябрь 2005) можно скачать с этого сайта. Прямая ссылка на файл черновика (3.4мб).
  • Прежде чем задать вопрос, прочтите это и/или это!
  • Здесь хранится весь мировой запас ссылок на документы, связанные с C++ :)
  • Не брезгуйте пользоваться тегами [code=cpp][/code].
  • Пожалуйста, не просите написать за вас программы в этом разделе - для этого существует "Центр Помощи".
  • C++ FAQ

Если Вам понравилась атмосфера форума, заходите к нам чаще! С уважением, Earnest Daevaorn

 
0 Пользователей читают эту тему (0 Гостей и 0 Скрытых Пользователей)
0 Пользователей:
« Предыдущая тема | C/C++: Общие вопросы | Следующая тема »


 




[ Время генерации скрипта: 0.0566 ]   [ Использовано запросов: 22 ]   [ GZIP включён ]


Реклама на сайте     Информационное спонсорство

 
По вопросам размещения рекламы пишите на vladimir(sobaka)vingrad.ru
Отказ от ответственности     Powered by Invision Power Board(R) 1.3 © 2003  IPS, Inc.