LINUX.ORG.RU

Таненбаум против Торвальдса - часть вторая


1

1

В продолжение недавних дебатов о микроядре, в очередной раз разгоревшихся между Торвальдсом и Таненбаумом, последний опубликовал свои комментарии к аргументам Торвальдса. В частности он перечисляет различные микроядерные ОС с указанием их применения.

>>> Подробности

★★★

Проверено: Shaman007 ()
Ответ на: комментарий от alman

>> О DMA слышал, и даже программировал 8-P.

>А с этого места пожалуйста подробнее. С каких это пор любой процесс микроядра может обращаться к любому диапазону портов ввода вывода? Это заблуждение, что раз микроядро, значит любой поток или задача имеет доступ ко всему железу. Причём, весьма распространённое заблуждение.

Процесс "драйвер" может - и он своим кривым dma убьет систему.

>alman * (*) (16.05.2006 19:11:51)

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

>Думаю, данная проблема одинакова для микроядер и монолита.
Но при этом монолит работает быстрее.
Причем, работает быстрее ВСЕ ВРЕМЯ ЭКСПЛУАТАЦИИ. В рабочих ситуациях это важно.
P.S. Что делает руководство фирмы, когда не хватает мощности системы? Добавляет еще один узел в кластер. А на каком ядре этот узел работает, дело десятое (если на монолитном быстрее, то ...). Такова селява.

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

>... в мире, где только ядро, терминал и X.
А если еще модем 2400, то вообще гайки :-)

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

> ... в мире, где только ядро, терминал и X.

Я имел в виду что эти три вещи помогли линуксу стать таким, каким мы его привыкли видеть сегодня ) Остальное - мозилла с файерфоксом и апач появились от них (правда насчёт апача не уверен :-))) ).

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

> помогли линуксу стать таким, каким мы его привыкли видеть сегодня

Дык это ж мы, ЛОРовские;). А вот мозилла, файрфокс, апач - сделали опенсорц _всемирным_ явлением не в меньшей мере, чем линух. Да, еще важный проект, без которого ничего б этого не было - gcc.

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

> Но дело в том, что при использовании DMA и отсуствии IOMMU драйвер может случайно или намеренно затереть ЛЮБУЮ область памяти в системе, даже не имея доступа к "чужим" портам и регистрам. Устройства оперируют физическими (ну ладно, шинными :)) адресами, мимо MMU, и пишут туда, куда скажет драйвер. Если же в системе есть IOMMU, и его контролирует микроядро - тогда другое дело. Если дать доступ к IOMMU драйверу - мы снова там, где начали.

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

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

> Остынь и скажи, что произойдет в твоей микроядерной системе в случае отказа оборудования, к примеру, HDD, при условии:

>1. модуль работает отлично, HDD сдох (физицски).

Дык, это не проблема. Если сдох HDD, то или не прийдёт прерывание и модуль получит таймаут и отработает эту ситуацию. Или получит код ошибки от контроллера и также отработает ситуацию.

>2. сбой модуля (ошибка в коде модуля, повторная его загрузка приводит к тому же сбою), HDD жив.

Эта ситуация гораздо интереснее. Во первых, на момент отладки ядра модуль не будет автоматически перезагружаться и есть возможность отладить такую ситуацию. Что, несомненно, легче, если при этом не упадёт вся система.

Вторая ситуация, когда ошибка спрятана глубоко и при отладке её не нашли. Здесь можно организовать счётчик падений и при достаточно частом сбое исключить драйвер из автозагрузки. Это проблема дизайна системы. В том же /sbin/init есть реализована такая возможность: "Process respawning too fast. Will disabled for 5 minutes" :)

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

> Он абсолютно прав.

Абсолютная истина существует только в религиях. И дело даже не в том, хороший он кодер или нет. Если бы его подход был бы жизнеспособен (в данный момент), то найти хороших программистов можно было бы. Видимо, проблема лежит глубже, хотя и не обязательно в каких-либо технических недостатках. Если мне не изменяет память, профессор долгое время не желал вносить изменения, предоставляемые третьими лицами - а без сообщества вытянуть сколь-нибудь серьезный проект просто невозможно. Вот поэтому сейчас популярность Minix близка к 0, несмотря на возможное техническое преимущество этой ОС перед, скажем, Linux в примерно одинаковой стадии зрелости.

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

> Ну дак и ядро - у всех есть, а драйвер к винмодему - только у избранных.

а сам винмодем - у самых одаренных

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

> Помимо IPC, в микроядра входят (обычно) еще планировщики ;) Но это тоже не имеет отношения к вопросу, который рассматривался. Вопросу о том, являются ли Win2k, QNX и Mach "микроядерными", если исходить из _приведенного_ определения.

Ок. Признаю, в данном случае я не прочувствовал контекст и погорячился. Наверное горячие противники микроядерности, не имеющие о нём представления, на меня так подействовали.

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

> Дык это ж мы, ЛОРовские;). А вот мозилла, файрфокс, апач - сделали опенсорц _всемирным_ явлением не в меньшей мере, чем линух. Да, еще важный проект, без которого ничего б этого не было - gcc.

YOU RIGHT

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

>>1. модуль работает отлично, HDD сдох (физицски).

>Дык, это не проблема. Если сдох HDD, то или не прийдёт прерывание и модуль получит таймаут и отработает эту ситуацию. Или получит код ошибки от контроллера и также отработает ситуацию.

Так же работает драйвер в монолитном Linux.

>>2. сбой модуля (ошибка в коде модуля, повторная его загрузка приводит к тому же сбою), HDD жив.

>Эта ситуация гораздо интереснее. Во первых, на момент отладки ядра модуль не будет автоматически перезагружаться и есть возможность отладить такую ситуацию. Что, несомненно, легче, если при этом не упадёт вся система.

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

>alman * (*) (16.05.2006 20:29:08)

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

> а сам винмодем - у самых одаренных

Сории конесчно но за каким херов в линухе винмодем ? Тем более что даже на lucent-чипе уже появились платные дрова - ограничивают скорочть до 14400 и не позволяют её менять. Все эти дешёвые поделки надо использовать в винде ) Да и ваще - эпоха диалапа секоро уже закончится, даже уже заканчивается ) За та спасибо сотивым и выделёнкам. УРА.

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

> КАК может Танненбаум просить попробовать свою MINIX у Линуса ? Или предлагать ставить её желающим ? Детский лепет просто...

А вот Линус снесет попсовый Линукс и тряхнет стариной, поставит MINIX жаст фор фан.

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

>>Что значит подвесил устройство?

>Привел его в состояние, из которого оно не может выйти.

bios же каким-то образом обходит это ограничение :)

>> Почти все устройства поддерживают аппаратный сброс, так что проблема надумана.

> Ээх... если бы 8( Ты драйверов не писал, так ведь?

Не так. Писал для Windows NT, Linux и кучи всяческих специализированных контроллеров на базе ARM.

> Как сказал Alan Cox: "Everything has bugs". Устройства тоже. Некоторые их этих багов обходятся в драйверах, некоторые - нет. Некоторые могут убить не только устройство, а и машину (на shared bus вроде PCI). Точно так же - ошибки в драйвере, причем этого никакое микроядро и не заметит.

Да пока Бог миловал - практически всё, с чем имел дело, сбрасывалось при установке соответсвующего бита в соответсвующем регистре или посылкой спецаильной команды. Естественно, опыт Алана Кокса на несколько порядков более моего, однако, я бы не стал преувеличивать проблему аппаратного сброса устройств. В подавляющем большинстве случаев устройства корректно сбрасываются.

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

> А вот Линус снесет попсовый Линукс и тряхнет стариной, поставит MINIX жаст фор фан.

И тада поёдёт новая тема обсуждения и новый топик ) Жжжжжжжждём-с ! )))

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

>> Верхний протокол отвалится по таймауту. В резельтате какой либо вызов вернёт ошибку. Ничего фатального не случится.

> А нижний?

А до нижнего протокола запрос не дойдёт и его состояние не изменится. А если сбой произойдёт после ответа от нижнего протокола, то самое страшное что может случиться - потеряются данные. С учётом того, что верхний протокол обнаружит ошибку по таймауту, то опять же - ничего фатального.

> Насчет ошибки - а если, скажем, пейджер не смог загрузить страницу процесса - процесс будет прибит? Если да, то получается, что, хотя система и выжила, приложение, ради которого система и нужна, померло. Где надежность?

Я не могу представить ситуацию, по которой пейджер не сможет замапить страницу процесса. Честное слово. Однако, могу точно назвать ситуацию, когда процесс будет прибит - если страница, вызвавшая запрос к пейджеру, не лежит ни в одном из сегментов - CODE, DATA, BSS или STACK. Если такое произошло, значит с приложением что-то не так и оно должно быть прибито.

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

>Тогда на каждое событие необходим запрос/ответ по ipc, что существенно медленнее блокировки в разделяемом контексте.

>IPC - это главная характерная черта (и главный тормоз) microkernel.

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

Но я готов поспорить. Как только к одному ресурсу начинают активно обращаться несколько потоков, то разница в скорости двух подходов резко сокращается. К сожалению, я не готтов представить реальные цифры.

Но самое интересное начинается на многопроцессорных и многоядерных архитектурах. В этом случае использольвание IPC может дать преимущество.

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

>Но самое интересное начинается на многопроцессорных и многоядерных архитектурах. В этом случае использольвание IPC может дать преимущество.

Блокировки-блокировкам рознь, giant/bkl безусловно приведут к потере производительности, но fain-grained locks - нет. При использовании IPC будет постоянно вымываться кэш, происходить очень много переключений контекста и связанных с этим накладных расходов, так же много "системных вызовов" для создания/посылки/приема IPC сообщений, плюс на каждое сообщение в одном ipc канале (например от net driver к phys access device) будет необходима блокировка между потоками нескольких сетевых адаптеров (phys access device по крайней мере в minix один), плюс вопрос об аллокации памяти для ipc сообщений - либо разделяемая (что быстрее, но опаснее), либо отдельная с копированием между уровнями (что медленнее, чревато page fault и т.п.) и много других неприятностей.

>alman * (*) (16.05.2006 21:27:37)

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

>> Ну да, а в микроядре локи не нужны? Там их еще больше, т.к. доступ происходит из всегда равноправных контекстов.

> Объекты синхронизации нужны для пользовательских приложений. А в прослойке между микроядром и пользовательскими задачами (т.е. в том, что мы называем ОС) блокировки как раз не нужны - потоки общаются между собой посредством сообщений. Вся синхронизация происходит на уровне IPC.

> Естественно, моё утверждение верно при правильном дизайне ОС.

что-то Вы замудрили

допустим получает ядро сигнал от высокоприоритетного железа. Запускает обработчик. Что бы он отработан ставится блокировка. Во время обработки приходит сигнал от низкоприоритетного железа. Запускатся обработчик, находит блокировку и сидит ждет. Первый обработчик заканчивает работу, блокировка снимается, запускается второй.

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

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

> Но при этом монолит работает быстрее. Причем, работает быстрее ВСЕ ВРЕМЯ ЭКСПЛУАТАЦИИ. В рабочих ситуациях это важно.

Монолит работает значительно быстрее в однопроцессорных конфигурациях с однопоточными приложениями.

В случае многопоточности, разница в скорости сокращается.

В случае многопроцессорности или многоядерности железа - микроядра могут оказаться даже быстрее монолитных решений.

Почему? Несколько факторов. Первое - другой подход к организации системы, например, организация протоколов посредством конечных автоматов. Я уже приводил пример в предыдущем обсуждении. Второе - другой подход к реализации планировщика задач. В случае синхронных IPC, переключение контекста становится более оптимальным. Третье - уход от спинлоков.

С учетом того, что мир сейчас помешался на многоядерных процессорах, то у микроядерных решенений весьма хорошие перспективы.

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

>>Миникс создавался исключительно для изучения внутренннего устройства операционных систем.

> И продавался за деньги. Студентам. Этот баум профессор или манагер по продажам?

студентам продавался не minix, а книга с детальным описание системы (перевод которой на русский бегает в djvu формате)+CD c системой, а голый minix, без книги, можно качнуть из инета

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

> Если мне не изменяет память, профессор долгое время не желал вносить изменения, предоставляемые третьими лицами - а без сообщества вытянуть сколь-нибудь серьезный проект просто невозможно. Вот поэтому сейчас популярность Minix близка к 0, несмотря на возможное техническое преимущество этой ОС перед, скажем, Linux в примерно одинаковой стадии зрелости.

Да, что-то такое было. Типа он не принимал патчи, потому что это, якобы, увеличит сложность понимания системы, что недопустимо для Minix, который создавался для студентов.

Кажется, потом он своё мнение таки изменил и Миникс оброс многими возможностями, в т.ч. TCP/IP стек. Но поезд ушёл....

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

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

>> Насчет ошибки - а если, скажем, пейджер не смог загрузить страницу процесса - процесс будет прибит? Если да, то получается, что, хотя система и выжила, приложение, ради которого система и нужна, померло. Где надежность?

>Я не могу представить ситуацию, по которой пейджер не сможет замапить страницу процесса.

Не замапить, а подкачать из backing store. Со сбойнувшего сервера ФС, например ;)

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

> Блокировки-блокировкам рознь, giant/bkl безусловно приведут к потере производительности, но fain-grained locks - нет. При использовании IPC будет постоянно вымываться кэш, происходить очень много переключений контекста и связанных с этим накладных расходов, так же много "системных вызовов" для создания/посылки/приема IPC сообщений, плюс на каждое сообщение в одном ipc канале (например от net driver к phys access device) будет необходима блокировка между потоками нескольких сетевых адаптеров (phys access device по крайней мере в minix один), плюс вопрос об аллокации памяти для ipc сообщений - либо разделяемая (что быстрее, но опаснее), либо отдельная с копированием между уровнями (что медленнее, чревато page fault и т.п.) и много других неприятностей.

Создаётся впечатление что в своё время Вы пристально смотрели в сторону Mach и он Вас разочаровал. Предлагаю теперь посмотреть в сторону L4. Все мои рассуждения в этом топике базируются именно на L4 - микроядре второго поколения.

Навскидку - аллокация памяти для IPC не используется, поскольку IPC синхронные. Для всех IPC только один системный вызов, который может содержать фазу приёма и/или фазу посылки. Причём, в случае посылки и приёма внутри одного IPC, этот IPC атомарный.

alman ★★★
()
Ответ на: Вышла новая OPERA от binr

>Слышал рассказку про софт, который загружается только под виндой, затем всё инициализирует, а потом ловко убирает винду из системы

loadlin?

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

> допустим получает ядро сигнал от высокоприоритетного железа. Запускает обработчик. Что бы он отработан ставится блокировка.

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

> Во время обработки приходит сигнал от низкоприоритетного железа.

Приходит во время обработки аппаратного IRQ? Такого не бывает - прерывания замаскированы.

> Запускатся обработчик, находит блокировку и сидит ждет.

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

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

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

[такая схема обработки - не привилегия микроядра. -rt патчи к Linux делают так же]

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

Почему у менеджера памяти наивысший приоритет?

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

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

> Создаётся впечатление что в своё время Вы пристально смотрели в сторону Mach и он Вас разочаровал. Предлагаю теперь посмотреть в сторону L4. Все мои рассуждения в этом топике базируются именно на L4 - микроядре второго поколения.

Воот. Нельзя ли вкратце изложить разницу между поколениями? Или ссылку на документ, где они излагаются.

> Навскидку - аллокация памяти для IPC не используется, поскольку IPC синхронные.

Это хорошо, но ведь переключение контекста между клиентом и сервером всё равно необходимо? Насколько я помню, в необходимости делать при этом TLB flush была одна из главных причин плохой производительности микроядер. Как с этим справляется второе поколение? Или рассчитывает на tagged TLB? :)

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

> что-то Вы замудрили

Блокировка блокировке рознь. Я скажу вам одну вещь, только не удивляйтесь. Нормальное состояние системы (во всяком случае десктопа) - блокировка. Что в линуксе, что в виндовсе большую часть времени процессор сидит в HLT. Естественно, если Вы в это время не запустили числодробильную задачу или бесконечный цикл сам на себя.

Надеюсь, оспаривать это не будете?

> допустим получает ядро сигнал от высокоприоритетного железа. Запускает обработчик. Что бы он отработан ставится блокировка. Во время обработки приходит сигнал от низкоприоритетного железа. Запускатся обработчик, находит блокировку и сидит ждет. Первый обработчик заканчивает работу, блокировка снимается, запускается второй.

Я покажу на примере L4, с котторым работаю довольно плотно и на изучение которого потратил несколько лет. В L4 обработчик аппаратных прерываний от железа - такой же поток как и все остальные. Большую часть времени он находится внутри IPC в фазе приёма. (При этом не кушая ресурсов процессора) При возникновении прерывания, IPC завершается и возвращает информацию о номере прерывния. Далее, поток делает своё дело, например читает вычитывает данные из железки, и/или парсит протокол, и/или посредством IPC передаёт [обработанные] данные другому протоколу. Причём, всё это происходит синхронно. После этого поток прерывания заново переходит в фазу приёма IPC и ждёт следующего прерывания. Такая вот абстракция. Всё это происходит очень быстро. Подозреваю что число комманд и переключений контекста в этом случае не больше чем в ядре линукса, фри или виндоуз.

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

В случае же нескольких железок, работа ведётся параллельно. Т.е. в другом потоке. Остаётся только назначить прироритет потокам в соответствии с приоритетом железа.

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

менеджер памяти в L4 называется пейджер. Всё, что делает этот процесс - как и прерывание сидит в фазе приёма IPC и не кушает никаких ресурсов. В случае Page fault фаза приёма заканчивается и пейджер получает fault address и номер потока, в котором произошло обращение к памяти. Затем пейджер анализирует, принадлежит ли адрес адресному пространству задачи, и если принадлежит - отображает физическую страницу в адресное пространство потока. После этого пейджер ждёт следующего Page Fault. Всё до безобразия просто.

Итог простой - рассматривайте операционную систему на базе L4, как набор потоков, которые в большинстве своём находятся в состоянии фазы приёма IPC. В нормальном состоянии все потоки ждут. Ждут событий. Всё есть события: нажание на клавишу - событие, движение мыши - событие, запись/чтение блока на диск - событие, приём/передача пакета от сетевой карты - событие, втыкание USB устройства - событие, сигнал от таймера - событие. Когда Вы это прочувствуете, мир станет краше.

Кстати, насчёт таймера я слукавил - нет их в прямом виде в L4. Каждое IPC имеет свойство Timeout, которое может быть равным нулю, какому-то времени или бесконечности. Таким образом таймер легко реализуется в виде потока и IPC с таймаутом.

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

> Не замапить, а подкачать из backing store. Со сбойнувшего сервера ФС, например ;)

Идею понял. В таком случае критические серврисы надо стартовать в Non paged pull. Другой вариант - не держать swap на файловой системе, а выделить для него физический раздел. Ну или вообще без свопа, для критических приложений, виртуальная память ведь не подразумевает наличие swap.

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

> поскольку IPC синхронные

Кстати, о синхронных IPC... Буквально вчера наткнулся на интересный документ: http://www.coyotos.org/docs/ukernel/spec.html Там в пункте "Overrun by Hurd" как раз говорится о синхронности IPC в L4 ;)

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

Хотя как драйвероклепателю идея userspace-драйверов мне очень нравится :)

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

> Воот. Нельзя ли вкратце изложить разницу между поколениями? Или ссылку на документ, где они излагаются.

Вот тут много всего:

http://l4ka.org/publications/ Признаюсь, эти документы для меня слишком академические - в них по большей части теория.

А для изучения ознакомления с L4 Pistachio ничего не видел лучше чем http://l4ka.org/projects/pistachio/l4-x2-r5.pdf в купе с примерами этого документа достаточно чтобы начать использовать L4.

>> Навскидку - аллокация памяти для IPC не используется, поскольку IPC синхронные.

> Это хорошо, но ведь переключение контекста между клиентом и сервером всё равно необходимо? Насколько я помню, в необходимости делать при этом TLB flush была одна из главных причин плохой производительности микроядер. Как с этим справляется второе поколение? Или рассчитывает на tagged TLB? :)

Скажу честно - не знаю. Судя по инфе, что пробегает в Сети и по бенчмаркам, разработчкимам L4 действительно как-то обошли эту проблему.

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

> Кстати, о синхронных IPC... Буквально вчера наткнулся на интересный документ: http://www.coyotos.org/docs/ukernel/spec.html Там в пункте "Overrun by Hurd" как раз говорится о синхронности IPC в L4 ;)

Аааа, товарищь Marcus Brinkmann частенько светился в мэйллисте L4 Pistachio. Потом в интернете появилась новость, что он запустил Banner под L4 Hurd - http://www.nixp.ru/news/5398

В то же время у меня глубокое и стойкое предубеждение против GNU Hurd. Когда он был ещё на ядре Mach, поставил его на свой ноут. Какого же было удивление, когда в после загрузки Hurd'f процессор стал сильно греться. Это чувствовалось по бешенно вращающемуся кулеру, который крутился на полную мощность...

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

Не совсем так. Вот цитата из ссылки, приведённой Вами:

The space concern is a blatant failing in blocking designs. Suppose there is a server that wishes to wait simultaneously for activity on one of 1024 network connections. In a blocking IPC design you need a thread to wait on each of these connections. The register state of a modern Pentium-family processor occupies nearly four kilobytes, and there is additional state needed within the operating system. Estimate it at two pages, or 8 kilobytes. Ignoring their address space, runtime storage requirements, or any other space that may be needed, the mere existence of these 1024 threads requires about 8 megabytes. It could be argued that this is acceptable on a modern desktop PC (though I disagree). It is simply not acceptable on smaller embedded systems. The requirement for many threads solely for the purpose of demultiplexing presents an intrinsic failure of scalability

Здесь предлагается подход, при котором на каждое сетевое соединение создаётся свой поток. Это, мягко говоря, неправильный подход. Даже в случае с синхронными IPC для всех 1024 соединений нужен только один поток. Максимум два потока - для развязки. Задача такого потока - принять данные, быстро их обработать и как можно быстрее избавиться, т.е. передать другому потому потоку. ВСЁ! Доказать это очень легко. Зачем плодить лишние потоки, если они всё равно работают _псевдопараллельно_? Не лучше ли всю работу выполнить в пределах одного потока? Реализуется это не весьма тривиально, но в результате получается значительный выигрыш в скорости и экономия ресурсов. Многопоточность - это круто, но её следует использовать с умом.

Я всё больше и больше разочаровываюсь в разработчиках Hurd. Теперь вот думаю что тормозил он вовсе не из за медленного Mach...

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

> Вообще создается впечатление что, несмотря на элегантность идей микроядерных архитектур, никто толком не знает, как эти идеи использовать.

Осмелюсь утверждать, что я знаю как использовать эти идеи.

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

Также следует избегать соблазна создавать поток на каждое сетевое соединение. Этот подход тоже порочный.

В чём недостатки таких подходов? Неоправданная трата памяти и... процессорного времени. Насчёт памяти понятно - каждый поток имеет контрольные данные а число процессорв или соединений может быть весьма велико. Насчет процессорного времени - во первых, поскольку потоки конкурирующие, на переключение между ними будет тратится процессорное время. Во вторых, в случае общих структур данных, например иноды в файловой системе, их придется защищать при помощи критических секций (мютексов), на что тоже уйдет значительная часть времени.

Как же быть? Потоки не нужны?

Прежде всего, необходимо разнести разные уровни протолов по различным потокам. Например, парсер ethernet пакетов в одном потоке, парсер IP пакетов в другом, парсер UDP в третьем, парсер TCP в четвёртом и так далее. Возникает закономерный вопрос, как быть в случае когда создаётся несколько тысяч TCP коннекшенов? Как их обрабатывать? Прежде всего стоит принять во внимание тот факт, что на самом деле потоки выполняются не параллельно, а псевдопараллельно. То есть в каждый квант времени активен только один поток (есть исключения для многоядерных и многопроцессорных систем, но для данной задачи этим можно пренебречь). Исходя из этого следует организовать TCP стек таким образом, что при получении каждого пакета от IP парсера, пэйлоад должен как можно быстрее передан в пользовательское приложение. Анализируем TCP заголовок, находим соответствие TCP порта пользовательскому потоку, ожидающего данные, и передаём ему пэйлоад посредством IPC, затем анализируем следующий пакет. И так далее. Смею вас заверить, что это будет на порядок быстрее, чем тысяча конкурирующих потоков. Для передачи данных от пользовательского приложения имеет смысл создать TCP sender поток. Таким образом, libc'шная send() не что иное как IPC к посылающему потоку. TCP layer приняв такой запрос, добавляет к данным TCP заголовок и посылает полученный пакет в IP layer. В результате мы имеем два потока (принимающий и посылающий) для TCP layer. Я нарочно упростил схему схему для более простого понимания - на самом деле формат TCP пакета не такой уж и простой.

Более интересная ситуация получается в случае с файловой системой. Все запросы (open, read, write, mount и т.д.) принимаются в ядром в одном потоке. Это означает что в один момент времени только одна пользовательская задача может выполнить запрос. Возьмём, к примеру, read() Всё бы ничего, если запрошенные данные будут находится в буффере, в этом случае запрос выполнится мгновенно и ядерный поток будет готов обслужить следующий запрос от другого процесса. С точки зрения пользователя эту будет выглядеть мгновенно. Но как быть если данных в буффере нет и их надо запросить у потока, обслуживающего внешний накопитель? Ни о какой параллельной рабботе тут речи и быть не может. Ситуация усугубляется тем, что запрос от второго процесса запросил даннные, которые находятся в буффере, но файловая система не может обслужить этот запрос, поскольку заняты выполнением предыдущего.

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

Неужели нет выхода? Выход есть!

Для этого надо ввести понятие контекста запроса и модифицировать парсер входящих запросов таким образом, чтобы он принимал не только запросы от пользовательских задач, но и ответы от потока, обслуживающий дисковый накопитель. Ещё нам понадобится конечный автомат, который будет анализировать входящие IPC и, в зависимости от источника, выполнять трубуемые действия. Поясню на примере. Запрос read от процесса 3 не нашёл данных в буфере и запросил и их у драйвера винта. После этого снова перешёл в режим ожидания. Следующий запрос пришёл от процесса 5 и данные в буфере обнаружились, они передаются процессу 5 и поток файловой системы снова перешёл в режим ожидания. На этот раз пришёл ответ от винчестера. Мы анализируем контекст и определяем какому пользовательскому процессу предназначены данные. Отдаём данные процессу и снова переходим в режим ожидания. Естественно, я нарочито утрировал роль файловой системы чтобы показать однопоточный метод обработки множественных запросов. Несмотря на то, что операции с файловой системой требуют множество операций, таких как поисх в буферах, анализ inode и проче, в случае если данные находятся в буфере, с точки зрения пользователя запрос будет выполнен мгновенно.

Боюсь, я не очень доходчиво всё объяснил, но главная мысль такая - если система, написанная вами, тормозит, значит проблема не в реализации, а в дизайне.

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

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

Кстати, преимущества вышеприведённого подхода - максимальная скорость, которая будет рвать многие монолитные реализации.

А недостаток - слишком сложная реализация конечного автомата. Очень большая сложность. Напрмер, гораздо легче написать с нуля minix fs или ext2 fs через конечный автомат, чем привести к автомату уже существующий код.

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

>А вот Линус снесет попсовый Линукс и тряхнет стариной, поставит MINIX жаст фор фан.

А потом создаст в talksах тему "я неосилил minix".

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

То есть контекст будет передаваться в сообщении? Не слишком ли высокий тогда будет расход памяти?

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

> Здесь предлагается подход, при котором на каждое сетевое соединение создаётся свой поток. Это, мягко говоря, неправильный подход.

Вообще-то там этот подход не предлагается, а критикуется как нежизнеспособный ;)

>> Вообще создается впечатление что, несмотря на элегантность идей микроядерных архитектур, никто толком не знает, как эти идеи использовать.

>Осмелюсь утверждать, что я знаю как использовать эти идеи.

Не сомневаюсь! :) Я говорю о том, что консенсуса нет.

> Прежде всего, необходимо разнести разные уровни протолов по различным потокам. Например, парсер ethernet пакетов в одном потоке, парсер IP пакетов в другом, парсер UDP в третьем, парсер TCP в четвёртом и так далее.

Хм... Это, наверное, лучше, чем "нить-на-соединение",,, Но, если я правильно понимаю, в твоей схеме прием пакета сопровождается ТРЕМЯ переключениями контекста (Ethernet -> IP -> UDP) ? Переключение нитей - это вход в ядро как минимум. Нити - они в одном адресном пространстве или в разных? Если в разных - это еще и 3 TLB flush. И весь этот оверхэд - ради одного пакета. А, и еще будет 4-е переключение контекста (и TLB flush) для отдачи пакета в пользовательскую прогу. Я правильно понял картину? А пэйлоад - он будет копироваться между потоками (возможно, разбросанными по разным процессорам, так что как минимум L1-кэш у них разный)? В общем, это же кошмарный сон контроллера кэша 8)

> Для этого надо ввести понятие контекста запроса > ...

Как я понял, это обобщение идеи, изложенной выше, так?

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

Не всегда, но сейчас согдасен.

Предложенный тобой способ интеграции: каждый _уровень_ стека протоколов - свой сервер (нить) - не единственный. Есть системы (тоже, IIRC, микроядерные), в которых интеграция не "горизонтальная", а "вертикальная", то есть проход пакета через _все_ уровни стека выполняется на контексте одной нити в рамках одного приложения. Это отсуствие входов в ядро, переключения контекстов, и идеальное использование процессорного кэша.

Очень похожая идея сейчас обсуждается (и находится на ранних этапах реализации) для Linux: http://lwn.net/Articles/169961, http://lwn.net/Articles/182060

[обязательно прочти - очень интересно]

В общем, у меня такое впечатление, что микроядра заставляют платить слишком много за свои возможности. По-моему, для достижения _большинства_ предлагаемых ими выгод (в надежности) было бы достаточно иметь возможность вынести из ядра драйверы и, м.б, файловые системы. А core kernel - пусть будет там, где и сейчас. Его сбой даже в микроядерных системах смертелен.

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

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

Современное состояние "монолитных" ядер (возьмем, к примеру Linux) таково, что _неотъемлемой_ частью ядра являются планировщик и средства IPC. Весь остальной код, выполняющийся в контексте ядра является опциональным - драйвера файловых систем, сетевого стека, большая часть драйверов оборудования может быть скомпонована на этапе выполнения (динамически). Таким образом, все отличие "монолитного" ядра от микроядра заключается лишь в том, что

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

2. факультативный код выполняется на одном уровне привилегий с обязательным. потенциально, крах в коде, не несущем жизненно-важные функции приводит к краху всего ядра. Да, это так. Но посудите сами: это важно лишь для тех людей, которые по тем или иным причинам вынуждены использовать ошибочный код. А это, фактически, лишь разработчики соответствующих драйверов. А для них некритична ситуация с зависанием, хотя и может быть неудобна. Но для _реального_ использования в промышленной системе _недопустимо_ использовать ошибочный код, ибо результат непредсказуем. И тут мы можем попасть в другую крайность - излишняя устойчивость системы к ошибкам в отдельных модулях приведет к их "маскированию" и к тому, что заметят их много позже.

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

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

> То есть контекст будет передаваться в сообщении? Не слишком ли высокий тогда будет расход памяти?

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

alman ★★★
()

Ребятки, а кто-нить с QNX работал серьезно? Или может читал вот такую книжицу http://www.swd.ru/qnx/support/literature/5-94656-025-9.html ;) И почему-то не Linux используется в системах управления стратегическими ракетами на подводных лодках и автомобильных контроллерах (что гораздо важнее для обычного автомобилиста) а QNX. Кстати микроядро QNX всего 8К ;) Про скорость работы я тихо умолчу.

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

>студентам продавался не minix, а книга с детальным описание системы (перевод которой на русский бегает в djvu формате)+CD c системой, а голый minix, без книги, можно качнуть из инета
Продавалось и то, и другое:
...
Учебник по Minix продавался в книжном магазине, но поскольку на саму операционку спрос был маленький, то ее надо было заказывать через тот же книжный. Она стоила 169 долларов, плюс налоги, плюс затраты на конвертацию, плюс всякое-разное.
...
Эндрю Таненбаум -- тот амстердамский профессор, который написал Minix, -- хотел, чтобы система оставалась учебным инструментом. Поэтому она была намеренно изуродована. Существовали заплатки -- то есть усовершенствования к Minix, в том числе знаменитая заплатка австралийского хакера Брюса Эванса (это был царь и бог Minix 386). С его заплаткой Minix на 386-м становилась намного лучше. Я начал читать телеконференцию по Minix в онлайне еще до покупки нового компьютера, поэтому с самого начала знал, что хочу установить именно усовершенствованную версию Эванса. Но из-за лицензионных ограничений пришлось сначала _купить_ исходную версию Minix, а потом изрядно повозиться, приделывая заплатки Эванса. Это было целое дело.
...
Linus Torvalds, Just for fun.

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

>Ребятки, а кто-нить с QNX работал серьезно?
Хорошая, надежная, но:
- платная, закрытая и под неё сложно разрабатывать "Hello, worldы". К тому же принадлежит 1(одной) компании.
В своей нише будет жить, но системой общего назначения не станет.
>Про скорость работы я тихо умолчу.
Такая быстрая? А под слакой пойдет? :-)

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

> Хм... Это, наверное, лучше, чем "нить-на-соединение",,, Но, если я правильно понимаю, в твоей схеме прием пакета сопровождается ТРЕМЯ переключениями контекста (Ethernet -> IP -> UDP)?

В идеале тремя. Хотя, наверное, не имеет смысл разносить IP и UDP протоколы по разным адресным пространствам. В этом случае можно использовать Local IPC чья "стоимость" приблизительно равна обычному call

> Переключение нитей - это вход в ядро как минимум. Нити - они в одном адресном пространстве или в разных?

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

> Если в разных - это еще и 3 TLB flush. И весь этот оверхэд - ради одного пакета.

Дык, насколько мне известно, разработчикам L4 каким то образом удалось минимизировать потери при переключении контекста. Всё, что я знаю об этом, работу TLB они оптимизировали для каждой поддерживаемой архитектуры. В подробоности я не вдавался.

> А, и еще будет 4-е переключение контекста (и TLB flush) для отдачи пакета в пользовательскую прогу. Я правильно понял картину?

В идеале - всего три переключения контекста. На физическом уровне, на протокольном уровне и отдача данных в пользовательское приложение. При условии, что в парсерах протоколов используется одно адресное пространство. Т.е. потоки взаимодействуют при помощи Local IPC. Кстати, такая съхема очень гибка - с минимальными телодвижениями потоки протоколов могут быть пересены программистом в разные адресные пространства или наоборот в одно адресное пространство - схема взаимоодействия между ними с точки зрения реализации протоколов не изменияется.

> А пэйлоад - он будет копироваться между потоками (возможно, разбросанными по разным процессорам, так что как минимум L1-кэш у них разный)? В общем, это же кошмарный сон контроллера кэша 8)

А это очень интересная особенность L4. Копирование данных между потоками делается средствами L4 во время IPC. Для этого используется так называемые compоund strings. Вообще, копирования данных между потоками - это отдельная и большая тема.

> Предложенный тобой способ интеграции: каждый _уровень_ стека протоколов - свой сервер (нить) - не единственный. Есть системы (тоже, IIRC, микроядерные), в которых интеграция не "горизонтальная", а "вертикальная", то есть проход пакета через _все_ уровни стека выполняется на контексте одной нити в рамках одного приложения. Это отсуствие входов в ядро, переключения контекстов, и идеальное использование процессорного кэша.

Да, это интересная и многообещающая идея. Спасибо.

> Очень похожая идея сейчас обсуждается (и находится на ранних этапах реализации) для Linux: http://lwn.net/Articles/169961, http://lwn.net/Articles/182060

> [обязательно прочти - очень интересно]

Спасибо. Сейчас прочитаю.

> В общем, у меня такое впечатление, что микроядра заставляют платить слишком много за свои возможности. По-моему, для достижения _большинства_ предлагаемых ими выгод (в надежности) было бы достаточно иметь возможность вынести из ядра драйверы и, м.б, файловые системы. А core kernel - пусть будет там, где и сейчас. Его сбой даже в микроядерных системах смертелен.

Ситуация кардинально изменится, когда процессоры станут затачивать под микроядра. Например, больщую часть функциональности L4 можно запихнуть непосредсвенно в железо. Тут открываются такие перспективы, от которых дух захватывает.

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

> Хорошая, надежная, но: - платная, закрытая и под неё сложно разрабатывать "Hello, worldы". К тому же принадлежит 1(одной) компании. В своей нише будет жить, но системой общего назначения не станет.

Здесь разговор не о написании таких супрепрограмм, а о возможностях ядер. Она кстати уже давно стала и не кричит об этом на весь мир!

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

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

Ничего не хочу сказать плохого против Линукса, но очень скоро сложность поддержки ядра достигнет предела. Это выразится в том, что добавление новой фичи или исправление бага повлечёт за собой возникновение новых багов. Уже сейчас не редки случаи, когда правят в одном месте, а нескольких местах ломается. Со временем такие ситуации будут возникать всё чаще и чаще.

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

> Ничего не хочу сказать плохого против Линукса, но очень скоро сложность поддержки ядра достигнет предела. Это выразится в том, что добавление новой фичи или исправление бага повлечёт за собой возникновение новых багов. Уже сейчас не редки случаи, когда правят в одном месте, а нескольких местах ломается. Со временем такие ситуации будут возникать всё чаще и чаще.

Вы, безусловно правы, но в то же время признаете, что микроядро более сложно для написания (человеком).

Возможно, нужны какие-то проблемно-ориентированные высокоуровневые языки (для написания ядер ОС), но пока, afaik, никто не задумывался об этом всерьез (опять-таки только в контексте написания ядра).

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

> Также следует избегать соблазна создавать поток на каждое сетевое соединение. Этот подход тоже порочный.

что интересно, mysql так работает: при запуске создается несколько потоков (в 5.0.3 было 4 потока), после чего они засыпают, один из них ждет входящий обращений и на каждый запрос создается поток по его обработке.

> Более интересная ситуация получается в случае с файловой системой. Все запросы (open, read, write, mount и т.д.) принимаются в ядром в одном потоке.

в какой-то степени это похоже на AS-планировщик (elevator) в линуксе: "Упреждающий конвейер (Anticipatory) вводит управляемую задержку перед обработкой операции в попытке объединить и/или переупорядочить запросы, улучшая смежность и уменьшая количество операций перемещения по диску. Этот алгоритм предназначен для оптимизации систем с небольшой или медленной дисковой подсистемой. Одним из побочных эффектов AS планировщика может оказаться увеличенная задержка ввода/вывода."

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

> Современное состояние "монолитных" ядер (возьмем, к примеру Linux) таково, что _неотъемлемой_ частью ядра являются планировщик и средства IPC.

IPC - не является ;) Если серьезно, то что значит - компонент является "неотъемлемой" частью? То, что его нельзя выбросить в menuconfig? Или то, что он очень тесно взаимодействует с другими компонентами? Если первое, то... ;) Если второе - неотъемлемыми компонентами ядра являются и система управления виртуальной памятью, и страничный кэш, и сетевой стек.

> 1. связи между опциональными компонентами ядра определяются на этапе компиляции в формате системных вызовов. Потеря гибкости здесь с лихвой компенсируется простотой межмодульного обмена информацией.

Эх, если бы всё было так просто. Интерфейс должен быть еще и быстрым. И здесь внутриядерные интерфейсы, основанные на вызовах функций, рвут message-passing как Тузик шапку.

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

:D Вот поработаешь лет 10-15, и понимание того, что фраза "в любой программе есть как минимум одна лшибка" - это ни разу не шутка, а грустная реальность, войдет в твою кровь. Так что мы _все_ используем ошибочный код.

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

Ну, логи надо смотреть регулярно.

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

Если это когда-нибудь произойдет, никакие ядра уже не понадобятся 8). Ядра - это защита памяти. Обсуждаемая статья посвящена живучести ситемы в присуствии ошибок в ее критических компонентах. А если в программе гарантированно нет ошибок - то зачем весь этот оверхэд ?

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