
hi, Fri, May 09, 2025 at 10:12:31, alex wrote about "[uanog] Re: NIC interrupts / IRQs / Cores": VN>> Описана, да. Но: VN>> 1) Неточные прерывания (imprecise interrupts/exceptions/etc.) в VN>> современных архитектурах не присутствуют. Ну, может, в самых VN>> маргинальных осталось.
Тут надо понимать, что в книге точно описаны прерывания "как это работает". И с 90х ничего не поменялось в этом плане. Прерывания трех видов: 1) аппаратное, когда "все стоп! сохраняем все регистры в стеке и прыгаем на прогу обработки прерывания".
Или же ничего не сохраняем кроме текущего адреса и режима привилегий, а сохранение данных отдаём на откуп коду обработчика. Современные архитектуры ведут к этому. Но не так принципиально.
2) аппартное, мы выставляем "флаг" в каком-то регистре и идем дальше, если никто не пришел за данными, то они перезаписываются следующими. 3) аппаратное, Учтройство приняло кусок данных, и само инициировало по Прямому Доступу к Памяти (ПДП) перенос данных в некую область Памяти. После этого Устройство продолжает работу.
И эти оба варианта уже не называются прерыванием, по крайней мере у подавляющем большинства авторов и архитектурных документов. Если где-то умудрились назвать "прерыванием" выставление флага в состоянии устройства — покажите точный источник и цитату.
Т.е. Процессор сам по себе, Устройство само по себе, а данные блокируют доступ Процессора к Памяти только на момент "перелива".При этом если Процессор н е"ходит" в той области памяти куда льет Устройство по ПДП, то ничего не тормозится.
Нечеткие прерывания это скорее к (2) т к (3) . А (1) ничего не поменялось.
Нет. У понятия imprecise exceptions совершенно чёткий смысл, к которому ни одно из этих вообще не относится. Пусть у нас, например, последовательность команд (x86, Intel syntax) mov mem1, eax inc mem2 Если первая команда получает исключение (скорее всего, страничное, если страницы с mem1 нет или в неё нельзя писать), то вторая не должна быть выполнена, чтобы обработчик мог вернуться туда же. Если же она выполнена, то при возврате мы можем получить некорректное увеличение на 2 вместо ожидаемого 1. Поэтому в процессоре должна быть жёсткая сериализация _видимого результата_ действий по их зависимости по порядку нахождения в потоке команд: пока мы знаем, что первая команда не даст исключения, мы не имеем права писать результат второй. А вот имеем право прочитать mem2 или нет, чтобы подготовить результат — зависит от режима доступа к соответствующему участку памяти (uncached — не можем, writeback, writethrough и т.п. — можем). Аналогично представим себе, что вместо записи в память первая команда — деление (пусть и пишет в регистры, но на x86 и ряде других может дать исключение). В Skylake, например (для более поздних данных не видел) такой конвейер растягивается до 97 команд и 224 микроопераций, в которые транслируются команды. Меня эти цифры реально ужасают, но это следствие чудовищно неравномерных времён доступа к памяти. Так вот, те архитектуры, на которых imprecise exceptions когда-то были разрешены, допускали их на ряд проблем, но только не аппаратные прерывания (то есть от внешних устройств), потому что эти прерывания приходят непредсказуемо, и в этом случае вообще ничего бы не работало. Они допускались только на ошибки, вызванные исполнением собственно кода, и то не на все. И постепенно это устранили, потому что толку в них никакого, добавить разумное упорядочение команд не так сложно. Таненбаум тут, откровенно говоря, лажает. Надо поискать оригинал, какое слово там было исходно, но если он сказал imprecise interrupts, говоря про аппаратные, то это просто глупость и враньё, а если про программные (которые чаще называются исключениями) — то он отстал от реальности.
Если же мы говорим о "делении на ноль" то это может быть как аппартное прерывание так и программное,
В современной терминологии это исключительно программное прерывание, потому что инициировано выполнением кода, а не сигналом от внешнего устройства.
т.е. Операционка сама, какие-то кванты времени, "смотрит" в "лог событий" и там если видит эксепшн или некое "уведомление о событии" то запускает процесс который с этим что-то делает. Или не делает :-) Посмотрите в ВИнде сколько "ошибок страниц" там пролетает за минуту. И ниче — все живы :-)
Страничные ошибки (page faults) отрабатываются процессором и далее ОС в момент их поступления, вызывая переключение в режим ядра, обработку ситуации и переключение обратно, если не генерируется ошибка доступа. Обработка постфактум через лог событий — не их случай. Я не знаю, с чего вы так решили, но нигде так не делается.
А вот теперь скажите мне: если у вас в Процессоре есть 16 ядер, то КАКОЙ ИЗ НИХ должно отвлекаться на прерывание?
Программное прерывание (исключение, в наиболее типичной терминологии) — ровно то ядро, в котором выполнялась команда, выполнение которой вызвало это исключение. И никак иначе. (Возможно, где-то есть варианты, что тяжёлое событие, после которого выполнение вообще невозможно, порождает machine check exception, которое передаётся на другой процессор. Но это отдельный разговор.) А вот аппаратное (от внешнего устройства) передаётся согласно раутингу таких прерываний, и дальше вопрос, как этот раутинг настроен. Могут на одно конкретное ядро. Могут рандомизировать для распределения нагрузки. Оба варианта имеют свой смысл в конкретных условиях.
Вопрос еще усложняется когда у каждого Ядра есть свой Кеш "уровня Х", куда заранее подгружается кусок исполняемого кода? Тут такой хаос можно устройить...
На каких современных (хотя бы от 2010) процессорах вы видели управляемую подгрузку заранее в кэш, чтобы там код хранился и не вымывался?
Я не хочу сильно углубляться в проблемы "железа и то как пишут Люди", но сейчас вот все это отдается на откуп Компилятору С, который уже сам решает все эти пролемы - т.е. кто что из Ядер должен делать, как настроить Обработчик прерываний и т.п.
Компилятор этим не занимается. Занимается код ОС — при её наличии, рантайм — в случае без ОС. Вероятно, для какого-то AVR/PIC/etc. подключается стандартный рантайм, в котором это реализовано, и именно это вы назвали компилятором. Но это некорректно.
Вы на "верхнем уровне" писанины программ этого не видите вообще.
Не видим, да. И не нужно, потому что достаточно гарантий корректности нижнего уровня.
Поэтому и получаются глюки - компилятор не имеет "мозга" а работает стандартными кусками кода (конфифгурации).
???
И если вы специально не лезете в регистры управления Устройства(микросхем) то вы полностью зависите от Компилятора и того что курили индусы которые написали код этого компилятора :-) Я пишу для низкого уровня , микропроцессоры, и пишу на С99 так, чтобы в коде потом все было как мне нужно (асемблерный код). Полезно использовать https://godbolt.org/ для того чтобы понимать как вот этофсе вот что ты сейчас написал, будет вывернуто в ассемблер.
godbolt хорош, но не в состоянии учесть, например, как у конкретного компилятора с конкретным кодом сработает инлайнинг и как от этого изменится выбор команд в реализации кода.
И сколько "подвызовов процедур" реально "стоит" твоя вот эта команда с передачей параметров через стек.
VN>> Аппаратные - вообще я не слышал, чтобы такое хоть где-то было, потому VN>> что это недопустимо, чтобы в непредсказуемые моменты тебе VN>> невосстановимо ломало всю работу.
Вы ошибаетесь. Ничего не ломается. Просто Процессор складывает в стек часть или все регистры и прыгает по адресу "Обработки прерывания".
Не ошибаюсь. Состояние, которое процессор "складывает в стек", соответствует "архитектурному" состоянию (значения видимых программисту регистров и памяти, без учёта кэша и т.п.) для завершения какой-то команды в промежутке от той, которая самая ранняя ещё выполнялась в момент поступления запроса на прерывание, и до самой поздней, которая только начала выбираться из памяти. Где именно будет зафиксировано состояние в этом диапазоне — зависит от массы факторов, но будет на какой-то точно определённый момент после завершения одной команды и перед началом выполнения другой. (Например, простейший, хоть далеко не лучший вариант, это просто остановить выборку команд и ждать, пока все не выполнятся.) И именно это критически важно, потому что "неточные прерывания", как их описал Таненбаум, это когда такой однозначности нет, разные регистры, разные адреса памяти могут отражать результаты разных позиций в этом диапазоне команд. Именно поэтому это никто сейчас не использует: с такого состояния нельзя корректно восстановить выполнение.
Тут ничего не изменилось с 90х годов, просто добавились всякие косвенные и т.п. адресации для удобства. Даташит на любой Процессор открываем и читаем.
Ага, и в нём в случае x86 или ARM не описано как раз самое вкусное для обсуждаемой темы. Интересующиеся выясняют это всё косвенно из экспериментов, или из утечек.
В случае одного Процессора, вы будете иметь "лаг-задержку" на время пока Процессор отработает код в прерывании, и вернется в точку откуда прыгал, загрузит спрятанные в стеке регистры, и продолжит работу с того же места. С вашей точки зрения вы даже не увидите что это все было - только "вдруг лаг" по тактам выполнения (строчкам выполнения).
Спасибо, кэп;) Всё так (с мелкими поправками, типа кто именно сохраняет/восстанавливает регистры), но это далеко не всё, что важно в данном контексте.
Если же у нас несколько ядер то каждое Ядро это отдельный Процессор. Там уже и своя память и Арбитр Прерываний - т.е. Программа (после компилятора) должна как-то указывать как будут распределяться обработки прерываний среди Ядер. Это про аппаратное я написал.
Да. И для того что поднял автор треда — нужно использовать средства ОС для привязки. Я такое видел, например, с DPDK. Под конкретную сетевую карту выделяется ядро целиком, только одна нить имеет право работать на нём, и прерывания направляются на это ядро. (Если есть аппаратный гипертрединг, "ядро" уже плохой термин. В RISC-V придумали hart == hardware thread. Мне этот термин нравится больше остальных.)
Теперь про любимые "типа реал тайм системы" :-) Под этими RTOS сейчас для железа есть то что просто тупо по таймеру выдает "кванты ресурсов на обработку", и потом то же самое: прячер мегистры, указатели, и отдаем память Процессору и новому "треду" или новому куску кода.Это получается НАДстройка НАД аппартными прерываниями как от Устройств так и от Таймеров.
Да.
Кому интересно - полистайте исходный код Адупайлота - основной проги БПЛА, которая управляет "типа реал тайм" всем самолетом.
Есть такая штука, угу. Самое смешное, что историческое название от работы на Arduino, но на Arduino её теперь исполнить нельзя — слишком толстая. Нужен минимум STM32 или аналог. И он может работать и поверх Linux.
Все RTOS так устроены. И Линукс тоже, просто в нем нет такой жесткой слежки за "квантами вычислений". Я сейчас сильно упрощаю, чтобы мысль свою донести.
Только я не понял, к чему эта мысль в данном обсуждении. VN>> Было в некоторых (например, SPARC до VN>> какого-то момента) для _исключений_, вызванных программными событиями, VN>> типа неподдерживаемой команды, и то не всех (page fault, например, VN>> туда не входил). VN>> Судя по тому, что в POWER точные исключения завезли в 1990, в x86 с VN>> момента его перехода в OoO (PentiumPro - 1996), а в S/370 ещё в 70-х - VN>> он отстал уже к моменту написания книги.
Вы не поняли. Я выше описал как это работает, в Книге тоже точно описано. Ничего не поменялось.
Ну кроме того, что imprecise exceptions не имеют никакого отношения к аппаратным прерываниям и вообще вымерли.
И ваша "сетевуха" может работать как я писал выше - в одном из трех режимов. Но сейчас все стараются делать (3) чтобы Устройство работало "в иной реальности времени" само по себе, а некий Арбитр должен управлять потоками данных. Иначе полная жопа будет...
Реально то, что я вижу для случаев реализации под большие нагрузки — это что на устройство (сетевая карта) возлагается задача разместить принятый кадр в память и дать свисток процессу, который будет этот кадр разбирать. Или наоборот, читать из памяти и отправлять (ну и оповещать о темпе прогресса). То есть это ваш вариант (3), с поправкой на то, что ПДП контроллер встроен в неё саму.
И число ядер тут как раз при чем - Устройство (Сеть) это ПОСЛЕДОВАТЕЛЬНЫЙ ОБМЕН. Т.е. пока летит в сетевом кабеле один пакет, второй никто не примет. Значит Устройство должно принимать все что "нормальное" куда-то в буфер,
Сразу в оперативную память. Может, да, с буфером до одного кадра.
выставлять "флаги" а потом Ядра как-то(?) должны весь этот буфер разгребать. И если Ядра быстрые то они стоят, а Устройство тупо принимает пакеты и складывает.
Ну.
Можно в Устройство всунуть свой Процессор, очень быстрый, который будет устанавливать "еще один уровень" между Сетью(кабель) и Процессорными Ядрами (верхний уровень). Типа предварительной фильтрации по MAC "а это вообще мне?" . Вы поняли что я написал сейчас ?
Вы ничего не написали, что не было бы (лично мне) известно уже много лет как. Вопрос не в фактах, как я понимаю, а в их связи между собой и обсуждаемой темой. Хотя и в фактах, как вижу, у вас местами странные представления.
Вы расплачиваетесь за нежелание "лезть ниже" тем что теряете производительность в 1000 раз примерно :-(.
Чего это?
Яркие примеры сейчас - писанина для STM32 любимых контроллеров БПЛА на HAL библиотеках просто уничтожает все эти 70-150МГц таковой частоты :-( оно тупо еле вывозит такие программы.
Проблемы HAL уровня я слышал, хотя лично не доводилось щупать. Но это вопрос того, как этот HAL написан, а не в принципе его наличие.
А еще сейчас куча проблем с ИИ, который "в библиотеках", которые неподьемные из-за такой вот наплевательской манеры написани кода вида "и так сойдет, если не хватает мощщи то поставьте проц пошустрее". :-( То эе самое сейчас с "переходом на цифру". Задержки на обработке видео с камеры и передаче этого в радиоканал.
Сколько задержка? Если менее 100 мс то для большинства, кажется, несущественно, это вам не Counter Strike. Ну и от целевого назначения зависит. Для простого FPV-камикадзе, наверно, невыгодно. -netch-