Вътрешни елементи на Linux MMAP

Имам няколко въпроса относно внедряването на mmap в Linux системи, които не изглеждат много документирани:

Когато преобразувате файл в памет с помощта на mmap, как бихте се справили с предварителното извличане на данните в такъв файл?

т.е. какво се случва, когато четете данни от mmaped региона? Тези данни преместени ли са в L1/L2 кеш паметта? Чете ли се директно от дисковия кеш? prefetchnta и подобни ASM инструкции работят ли върху mmaped зони?

Какви са режийните разходи на действителното mmap повикване? Относително ли е спрямо количеството картографирани данни или постоянно?

Надявам се, че някой има някаква представа за това. Благодаря предварително.


person Community    schedule 15.04.2009    source източник


Отговори (4)


mmap е основно програмен достъп до подсистемата на виртуалната памет.

Когато имате, да речем, 1G файл и го направите mmap, получавате указател към "целия" файл, сякаш е в паметта.

На този етап обаче нищо не се е случило освен действителната операция по картографиране на резервиране на страници за файла във VM. (Колкото по-голям е файлът, толкова по-дълга е операцията по картографиране, разбира се.)

За да започнете да четете данни от файла, вие просто осъществявате достъп до него чрез указателя, който ви е върнат в извикването mmap.

Ако искате да "заредите предварително" части от файла, просто посетете областта, която искате да заредите предварително. Уверете се, че посещавате ВСИЧКИ страници, които искате да заредите, тъй като VM ще зареди само страниците, до които имате достъп. Например, да речем във вашия 1G файл, че имате 10MB "индексна" област, която искате да картографирате. Най-простият начин би бил просто да "разходите своя индекс" или каквато и да е структура от данни, която имате, оставяйки VM страницата в данни, ако е необходимо. Или, ако „знаете“, че това са „първите 10MB“ от файла и че размерът на вашата страница за вашата виртуална машина е, да речем, 4K, тогава можете просто да прехвърлите указателя mmap към указател char и просто да итерирате през страници.

void load_mmap(char *mmapPtr) {
    // We'll load 10MB of data from mmap
    int offset = 0;
    for(int offset = 0; offset < 10 * 1024 * 1024; offset += 4 * 1024) {
        char *p = mmapPtr + offset;
        // deref pointer to force mmap load
        char c = *p;
    }
}

Що се отнася до кешовете L1 и L2, mmap няма нищо общо с това, това е всичко за начина, по който осъществявате достъп до данните.

Тъй като използвате основната VM система, всичко, което адресира данни в mmap'd блока, ще работи (винаги от асемблирането).

Ако не промените нито една от mmapd данните, VM автоматично ще изчисти старите страници, тъй като са необходими нови страници. Ако наистина ги промените, тогава VM ще запише тези страници обратно вместо вас.

person Will Hartung    schedule 15.04.2009
comment
Няма ли да се оптимизира char c = *p? Трябва ли c да бъде обявен за летлив? - person Laurynas Biveinis; 30.04.2009
comment
В последните версии на Linux можете да зададете MAP_POPULATE в аргумента flags на mmap() и страниците ще бъдат изтеглени преди извикването да се върне. Това ще блокира извикването за период от време, който е някаква функция на размера на файла, така че изпълнението на примерната функция load_mmap() в отделна нишка би подобрило производителността, ако има друга работа, която може да се извърши паралелно, преди съдържанието на файла да е необходимо за четене, особено след като по-голямата част от работата се извършва от страна на ядрото. - person BD at Rivenhill; 10.05.2011
comment
mlock не зарежда ли предварително страниците? - person Giovanni Funchal; 15.11.2011
comment
Така че няма естествен начин за постигане на предварително зареждане на част от mmapped файл, освен ръчно докосване на всяка страница? Четох човека от readahead, но той приема файлов дескриптор и не е ясно дали мога да използвам този, който използвах за mmap на файла или не. - person cYrus; 22.11.2014

Няма нищо общо с кеша на процесора; той го картографира във виртуално адресно пространство и ако впоследствие бъде достъпен или заключен с mlock(), тогава го пренася физически в паметта. В какво се кешира процесорът или не е нищо, върху което наистина имате контрол (поне не чрез mmap).

Обикновено докосването на страниците е необходимо, за да бъде картографирано, но ако направите mlock или mlockall, това ще има същия ефект (те обикновено са привилегировани).

Що се отнася до режийните разходи, наистина не знам, трябва да ги измерите. Предполагам, че mmap(), който не зарежда страници, е повече или по-малко операция с постоянно време, но въвеждането на страниците ще отнеме повече време с повече страници.

Последните версии на Linux също поддържат флаг MAP_POPULATE, който инструктира mmap да зарежда страниците незабавно (вероятно само ако е възможно)

person MarkR    schedule 15.04.2009

Отговаряйки на въпроса на г-н Рави Пхулсундар:

Няколко процеса могат да картографират един и същ файл, стига разрешенията да са зададени правилно. Разглеждайки страницата с ръководство на mmap, просто подайте флага MAP_SHARED (ако трябва да картографирате наистина голям файл, използвайте mmap2 вместо това):

mmap

MAP_SHARED

Споделете това картографиране с всички други процеси, които картографират този обект. Съхраняването в региона е еквивалентно на запис във файла. Файлът всъщност може да не се актуализира, докато не се извикат msync(2) или munmap(2).

person Robert S. Barnes    schedule 30.04.2009

използвате MAP_SHARED

person pp7    schedule 17.11.2010