LINUX.ORG.RU

Кто выталкивает грязный дисковый кэш?


0

0

subj

Я понимаю, что ядро ;)

Кому интересно происхождение вопроса:

Аппликуха построена на MPI, а она шибко с диском взаимодействует. А у MPI тенденция имеется -- синхронизироваться a-la busy work, то есть, в лучшем случае типа while(blah-blah)sched_yield(); в надежде, что оно одно такое живет на процессоре.

И у меня сомнения возникают -- а КТО же на диск-то из кэша пишет, если все процессоры отгрызены толстыми MPI - болтающими процессами...

★★★★★

Die-Hard:

По умолчанию в Linux все нити выполняются в time-sharing приоритетах, поэтому каждая нить, готовая к работе, получает квант (в т.ч. kupdate, bdflush). Если же выставить realtime приоритет своей нити и занять ей весь процессор, то результаты будут очень неприятными.

Murr ★★
()
Ответ на: комментарий от Murr

2Murr :

Блин, я тебя не понимаю.

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

> ...поэтому каждая нить, готовая к работе, получает квант (в т.ч. kupdate, bdflush

вопрос у меня и был -- откуда берутся ядерные нити типа kupdate и bdflush? И, далее, кто из подобных отвечает за выталкивание кэша?

Я думал (наверное, это был бред), что соответствующие ядерные нити рождаются и умирают в рамках некоего юзером стартованного процесса, в пределах его "ядерной" части.

К сожалению, я сейчас не располагаю временем для чтения даже мурзилки типа Advanced Linux Programming.

> Если же выставить realtime приоритет ...

Все пускается обычными юзерами как шелл скрипты.

Извиняюсь за наивные вопросы, но обычно вы (Murr и idle) мне все растолковывали, и до сих пор все было понятно. Конечно, надо читать основы, и т.п. -- но до сих пор у неня не было нужды лезть в потроха...

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Murr

2 Murr

Уважаемый, что надо читать, чтобы так шарить в тонкостях работы ядра (кроме самого ядра, разумеется)? Подкиньте ссылок, пожалуйста.

theSoul ★★★
()
Ответ на: комментарий от Die-Hard

всякие кернел нити(KT) рождаются ядром после запуска init. кернел нить это некий контекст ядра который имеет полноценную proccess запись, но не имеет (возможно необязательно) юзер спейса. Эти KT обычно спять, и пробуждаються только для выполнения какой либо задачи, в случае bdflush(я не уверен что это оно и есть в linux) при выделении/освобождении памяти она будет пробуждена в случае если требуется сброс кешей для успешного выполнения операции выделения/освобождения. Также она может быть пробуждена для так называемого аварийного сброса (в случае unmount например). А пробудиться она потомучто действительно получит квант(несколько квантов) на выполнение как и любой нормальный процесс.

lg ★★
()
Ответ на: комментарий от Die-Hard

Die-Hard:

Я аж расплылся от гордости. Только ж я больше по пиву и кино.
Вот idle - да, и правда злой kernel hacker.

Изначально я просто не понял вопроса - думал, что речь о приоритетах.

Объясняю я плохо, но сейчас попробую (очень упрощенно для 2.4):

В Linux данные кэшируются в т.н. страничном кэше. Страничный кэш - это просто набор страниц, которые могут быть отображены в память процесса, которые также обычно являются источником для read и write (VFS при запросах read и write просто оттуда копирует данные).

Также есть т.н. буферный кэш - в нем обычно кэшируются метаданные (суперблоки, директории, иноды и т.п.).

С точки зрения файловой системы нет каких-то принципиальных различий между страничным и буферным кэшом. В принципе, и данные можно читать и держать в буферном кэше (так и делал UNIX до появления SUN VFS), так и метаданные можно читать и держать в страничном, это просто менее удобно.

Запрос на ввод-вывод в ядре происходит обычно такими способами:
1) запросы пользователя read/write через страничный кэш ставят запрос в очередь блочного элеватора (commit_write -> submit_bh)
2) файловая система может использовать буфер под метаданные и может поместить запрос на ввод-вывод в очередь блочного элеватора (submit_bh)
3) файловая система может пометить буфер "грязным"(mark_buffer_dirty) вместо непосредственного помещения запроса на запись в элеватор. Это - фактически форма отложенной записи.

Поскольку зачастую синхронный вывод невозможен или нецелесообразен, для реализации отложеного ввода-вывода в Linux есть 3 нити:
bdflush, kupdate, kswapd.
Они порождаются при загрузке ядра и обслуживают ядро до упора. :)

1) bdflush искусственно пробуждается некоторыми подсистемами ядра, когда они считают, что нужно записать часть "грязного" буферного кэша на диск. bdflush пытается записать(отдать элеватору) фиксированное число буферов и вызывает сброс элеватора (фактически - синхронную дисковую операцию в своем контексте).

2) kupdate пробуждается через каждые n секунд и пытается записать (отдать элеватору) все(?) грязные буферы, которые пора записать (при "грязнении" буфера ставится пометка, когда именно его нужно записать), после чего вызывает сброс элеватора (run_task_queue(&tq_disk)).

3) kswapd пробуждается, когда нет свободной памяти (в Linux это нормальное явление, поскольку страничный кэш не херится без надобности) - он бегает по адресным пространствам процессов и пытается записать "грязные" страницы, отображенные в память процессов, после чего удаляет PTE для страницы и освобождает саму страницу. Запись обычно проходит синхронно, в контексте kswapd(то есть запрос подсовывается элеватору, после чего вызывается сброс элеватора).

Бегать по адресным пространствам нужно для того, чтобы понять, менялась ли страница или нет (а единственный способ это эффективно проверить - это проверка аппаратных PTE). В RH9 для ускорения и систематизации процесса проверки грязности страницы все представления страницы в памяти процессов связываются в цепочки (т.н. pte chains), т.о. для каждой страницы легко определить изменялась ли она в контексте хотя бы одного из процессов, в которых она отображена в память.


Элеватор - это надстройка над блочными устройствами, которая позволяет кластеризовать ввод-вывод и делает прочие полезные вещи. Элеватор можно рассматривать как буферизирующую прослойку между файловой системой и драйверами блочных устройств.

В Linux 2.4 есть два интерфейсных маразма, связанных с элеватором.
Первый из них заключается в том, что единицей ввода-вывода для элеватора является буфер, что является естественным для буферного кэша и совершенно неестественным для страничного. Из-за этого для ввода-вывода на странице нужно ее выложить fake буферами и сделать на них ввод-вывод. При этом это никак не сближает буферный кэш (у буферов буферного кэша есть ряд характерных свойств: принадлежность к спискам, данные в адресном пр-ве ядра) и страничный, но может привести к путанице. В 2.6 был введен новый интерфейс для элеватора - bio.
Второй интерфейсный маразм заключается в том, как происходит сброс элеватора, поскольку единственный интерфейс сброса элеватора - это сброс целиком(всех запросов по всем блочным устройствам). Отсюда в Linux такие замечательные жемчужины, как block_sync_page.


Если есть еще вопросы, попробую ответить в меру своих знаний.

Murr ★★
()

> а КТО же на диск-то из кэша пишет, если все процессоры отгрызены
> толстыми MPI

если очень поверхностно, до "грязные" данные сбрасываются
несколькими процессами (нитями) ядра.

kupdate: когда грязные данные слишком долго болтаются в cache.

bdflush: когда грязных данных становится "слишком" много.

swapper: не напрямую, в случае нехватки памяти.

Murr имел в виду, что user-level realtime process вполне
может отобрать cpu у этих потоков, и это правда.

> Все пускается обычными юзерами как шелл скрипты.

тогда, похоже, у вас таких процессов нет.

> Я думал (наверное, это был бред), что соответствующие ядерные нити
> рождаются и умирают в рамках некоего юзером стартованного процесса,
> в пределах его "ядерной" части.

в 2.6 у нас действительно есть динамически создаваемые процессы
(pdflush) для i/o, но они никак не связаны ни с каким user-level
процессом. на самом деле весь i/o в linux анонимный в том смысле,
что ядро вообще не знает кто инициировал "вот эту" запись.
соответственно, в настоящее время нельзя задать для процесса
i/o priority.

опять-таки, если все чудовищно упростить, то можно понимать
все это таким образом. всякая запись в файл означает, что
в некоторую очередь попадает страничка, которая содержит
новые данные, дескриптор этой странички содержит "адрес"
этих данных в файле. это, кстати, и есть page cache.

если таких страниц становится слишком много, просыпается
bdflush, и инициирует операцию вывода для некоторых страниц.

в любом случае, через 30 сек за ней придет kupdate с тем
же намерением.

idle ★★★★★
()
Ответ на: комментарий от theSoul

theSoul:

IMHO, чтобы понять, как работает Linux, надо понять, как устроена VM. В сети много неплохих книг по Linux VM(в том числе в LDP), особенно свежих. В Edonkey можно найти много книг по Linux.

Вот то, что я читал на первых порах: UNIX Баха, BSD4.3 Макьюзика, UNIX Internals Вахалии, какая-то книжка Тиграна Айвазяна по Linux kernel.

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

Плюс ко всему у меня до перехода на работу, связанную с Linux kernel был небольшой Windows kernel background. :) Ну и еще плюс - у меня есть знакомый гуру. :)

Murr ★★
()
Ответ на: комментарий от idle

idle:

>ну вот, опять... пишешь, пишешь, нажимаешь >submit, а Murr уже все опошл^W все подробоно >расписал :)

Да ладно, такой зубр как ты без труда может дополнить/подправить. ;)

Murr ★★
()
Ответ на: комментарий от Murr

> Вот то, что я читал на первых порах: UNIX Баха, BSD4.3 Макьюзика, UNIX Internals Вахалии, какая-то книжка Тиграна Айвазяна по Linux kernel.

Спасибо.

theSoul ★★★
()

Огромное спасибо всем ответившим.

А Murr'у я пиво буду должен. Жалко, далеко...

Die-Hard ★★★★★
() автор топика
Ответ на: комментарий от Murr

> Да ладно, такой зубр как ты

перестань, Murr :) большАя, если не бОльшая часть
ядра для меня terra incognita. в частности, vfs,
в которой ты явно разбираешься намного лучше.

так что, за обмен знаниями!

idle ★★★★★
()
23 декабря 2004 г.
Ответ на: комментарий от idle

Парни у меня тут вопрос как раз в тему, может что посоветуете?

задача такова: валится куча файлов, надо бы сделать очистку оперативной памяти при закрытии больших файлов, так как при закрытии страницы с данными держатся в памяти пока (как я думал) bdflush их не очистит(от вас узнал что еще с этим работают kupdate и kswapd), а мне срочно необходима память уже под другие данные. Пытаюсь это сделать с ядром 2.6.8, довольно новое ядро и в основном по исходникам смотрю как работает. Попробовал использовать функцию truncate_inode_pages() для удаления страниц из ОП. Поместил вызов этой функции в конце системного вызова sys_close() : ..sys_close(...){ ... if (!strncmp(dentry->d_parent->d_name.name,"namedir",7)) truncate_inode_pages(&inode->i_data,0); ... }

с одним файлом это работает ,но если начинается активная работа с многими файлами то работает еще хуже чем без этого может вообще так в корне не верно..?

может надо другим путем, вот например bdflush страницы херит или только синхронизирует? если он не убирает страницы из памяти -тогда наверно надо сделать чтоб убирал

guestes
()
Ответ на: комментарий от guestes

> валится куча файлов, надо бы сделать очистку оперативной
> памяти при закрытии больших файлов

во-первых, зачем?

во-вторых, почему это нужно делать в kernel-mode?
fsync(), fdatasync(), open(O_SYNC)

> Попробовал использовать функцию truncate_inode_pages()
> для удаления страниц из ОП. Поместил вызов этой функции
> в конце системного вызова sys_close()

это вы что-то не туда... это удаление страниц. в файле
будет мусор.

idle ★★★★★
()
Ответ на: комментарий от idle

>во-первых, зачем?
для выжимания максимальной производительности...

>во-вторых, почему это нужно делать в kernel-mode?
>fsync(), fdatasync(), open(O_SYNC)
kernel-mode такова специфика задачи,
fsync(), fdatasync(), open(O_SYNC) не удобно использовать, хотя в крайнем случае придется так

>это вы что-то не туда... это удаление страниц. в файле
>будет мусор.
почему вы так считаете? судя по коду это удаление страничного кэша файла, причем перед удалением страницы синхронизируются, то есть файл записывается на диск. (внутри функции truncate_inode_pages() перед удалением вызывается wait_on_page_writeback(page) )
поправьте, если ошибаюсь

я же писал выше что с одним-двумя файлами это работает..
..может надо добавить блокировки?

guestes
()
Ответ на: комментарий от guestes

> > во-первых, зачем?
>
> для выжимания максимальной производительности...

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

> > во-вторых, почему это нужно делать в kernel-mode?
>
> kernel-mode такова специфика задачи,

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

> > в файле будет мусор.
>
> причем перед удалением страницы синхронизируются, то есть файл
> записывается на диск. (внутри функции truncate_inode_pages()
> перед удалением вызывается wait_on_page_writeback(page)

нет. wait_on_page_writeback() просто ждет, когда закончится
запись страницы _если_ она (эта запись) уже началась. после
чего truncate_inode_pages() просто выбрасывает страницу
из page cache сняв PG_dirty и PG_uptodate.

idle ★★★★★
()
Ответ на: комментарий от idle

Во-первых благодарю за ответы. во-вторых - не посоветовали бы что нибудь почитать на эту тему (ссылочку)? именно по ядру 2.6

возможно необходимо пересмотреть задачу, сказывается недостаточное знание ядра..

>нет. wait_on_page_writeback() просто ждет, когда закончится >запись страницы _если_ она (эта запись) уже началась. после >чего truncate_inode_pages() просто выбрасывает страницу >из page cache сняв PG_dirty и PG_uptodate.

ждет? можно расписать такой граф: truncate_inode_pages() => wait_on_page_writeback() => wait_on_page_bit() => sync_page() =>block_sycn_page => ... это не приводит к синхронизации страницы? если нет значит я ошибаюсь а натолкнула меня на использование truncate_inode_pages() статья http://rus-linux.net/MyLDP/BOOKS/lki-ru/lki-3.html

guestes
()
Ответ на: комментарий от guestes

> ждет? можно расписать такой граф:
> ...
> sync_page() =>block_sycn_page => ...
> это не приводит к синхронизации страницы?

ну вы на код-то посмотрите:

void wait_on_page_writeback(struct page *page)
{
        if (PageWriteback(page))
                wait_on_page_bit(page, PG_writeback);
}

то есть, если у страницы нет PG_writeback, ничего
не произойдет, даже если она PG_dirty.

block_synс_page() вызывает bdi->unplug_io_fn(), то есть,
фактически, wait_on_page_bit() пинает девайс в цикле и
и ждет пока дойдет дело до нашей страницы.

idle ★★★★★
()
Ответ на: комментарий от guestes

не сразу заметил второй вопрос...

> не посоветовали бы что нибудь почитать на эту тему (ссылочку)? > именно по ядру 2.6

есть какая-то документация про 2.4 vm, автор - Mel Gorman. не читал. по 2.6 вообще, кажется, ничего такого нет.

anonymous
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.