
Привет ! мои ответы ниже. Thursday, May 8, 2025, 5:35:22 PM, Valentin Nechayev netch@netch.kiev.ua you wrote: VN> Thu, May 08, 2025 at 16:11:35, alex wrote about "[uanog] Re: NIC interrupts / IRQs / Cores":
с 380 страницы - как раз про железо и обмены. и я особенно рекомендую с 393 страницы - "Точные и неточные прерывания". Очень хорошо описана проблематика простыми словами.
VN> Описана, да. Но: VN> 1) Неточные прерывания (imprecise interrupts/exceptions/etc.) в VN> современных архитектурах не присутствуют. Ну, может, в самых VN> маргинальных осталось. Тут надо понимать, что в книге точно описаны прерывания "как это работает". И с 90х ничего не поменялось в этом плане. Прерывания трех видов: 1) аппаратное, когда "все стоп! сохраняем все регистры в стеке и прыгаем на прогу обработки прерывания". 2) аппартное, мы выставляем "флаг" в каком-то регистре и идем дальше, если никто не пришел за данными, то они перезаписываются следующими. 3) аппаратное, Учтройство приняло кусок данных, и само инициировало по Прямому Доступу к Памяти (ПДП) перенос данных в некую область Памяти. После этого Устройство продолжает работу. Т.е. Процессор сам по себе, Устройство само по себе, а данные блокируют доступ Процессора к Памяти только на момент "перелива".При этом если Процессор н е"ходит" в той области памяти куда льет Устройство по ПДП, то ничего не тормозится. Нечеткие прерывания это скорее к (2) т к (3) . А (1) ничего не поменялось. Если же мы говорим о "делении на ноль" то это может быть как аппартное прерывание так и программное, т.е. Операционка сама, какие-то кванты времени, "смотрит" в "лог событий" и там если видит эксепшн или некое "уведомление о событии" то запускает процесс который с этим что-то делает. Или не делает :-) Посмотрите в ВИнде сколько "ошибок страниц" там пролетает за минуту. И ниче - все живы :-) А вот теперь скажите мне: если у вас в Процессоре есть 16 ядер, то КАКОЙ ИЗ НИХ должно отвлекаться на прерывание? Вопрос еще усложняется когда у каждого Ядра есть свой Кеш "уровня Х", куда заранее подгружается кусок исполняемого кода? Тут такой хаос можно устройить... Я не хочу сильно углубляться в проблемы "железа и то как пишут Люди", но сейчас вот все это отдается на откуп Компилятору С, который уже сам решает все эти пролемы - т.е. кто что из Ядер должен делать, как настроить Обработчик прерываний и т.п. Вы на "верхнем уровне" писанины программ этого не видите вообще. Поэтому и получаются глюки - компилятор не имеет "мозга" а работает стандартными кусками кода (конфифгурации). И если вы специально не лезете в регистры управления Устройства(микросхем) то вы полностью зависите от Компилятора и того что курили индусы которые написали код этого компилятора :-) Я пишу для низкого уровня , микропроцессоры, и пишу на С99 так, чтобы в коде потом все было как мне нужно (асемблерный код). Полезно использовать https://godbolt.org/ для того чтобы понимать как вот этофсе вот что ты сейчас написал, будет вывернуто в ассемблер. И сколько "подвызовов процедур" реально "стоит" твоя вот эта команда с передачей параметров через стек. VN> Аппаратные - вообще я не слышал, чтобы такое хоть где-то было, потому VN> что это недопустимо, чтобы в непредсказуемые моменты тебе VN> невосстановимо ломало всю работу. Вы ошибаетесь. Ничего не ломается. Просто Процессор складывает в стек часть или все регистры и прыгает по адресу "Обработки прерывания". Тут ничего не изменилось с 90х годов, просто добавились всякие косвенные и т.п. адресации для удобства. Даташит на любой Процессор открываем и читаем. В случае одного Процессора, вы будете иметь "лаг-задержку" на время пока Процессор отработает код в прерывании, и вернется в точку откуда прыгал, загрузит спрятанные в стеке регистры, и продолжит работу с того же места. С вашей точки зрения вы даже не увидите что это все было - только "вдруг лаг" по тактам выполнения (строчкам выполнения). Если же у нас несколько ядер то каждое Ядро это отдельный Процессор. Там уже и своя память и Арбитр Прерываний - т.е. Программа (после компилятора) должна как-то указывать как будут распределяться обработки прерываний среди Ядер. Это про аппаратное я написал. Теперь про любимые "типа реал тайм системы" :-) Под этими RTOS сейчас для железа есть то что просто тупо по таймеру выдает "кванты ресурсов на обработку", и потом то же самое: прячер мегистры, указатели, и отдаем память Процессору и новому "треду" или новому куску кода.Это получается НАДстройка НАД аппартными прерываниями как от Устройств так и от Таймеров. Кому интересно - полистайте исходный код Адупайлота - основной проги БПЛА, которая управляет "типа реал тайм" всем самолетом. Там внутри своя операционка, с описанием сколько "таймслотов" надо выделит какой из подпрограмм. И что делать если прога зависла (через сколько милисек перезапуск подпрограммы). вот характерный кусочек: ... const AP_Scheduler::Task Plane::scheduler_tasks[] PROGMEM = { { SCHED_TASK(read_radio), 1, 700 }, // 0 { SCHED_TASK(check_short_failsafe), 1, 1000 }, { SCHED_TASK(ahrs_update), 1, 6400 }, { SCHED_TASK(update_speed_height), 1, 1600 }, { SCHED_TASK(update_flight_mode), 1, 1400 }, { SCHED_TASK(stabilize), 1, 3500 }, { SCHED_TASK(set_servos), 1, 1600 }, { SCHED_TASK(read_control_switch), 7, 1000 }, { SCHED_TASK(gcs_retry_deferred), 1, 1000 }, { SCHED_TASK(update_GPS_50Hz), 1, 2500 }, { SCHED_TASK(update_GPS_10Hz), 5, 2500 }, // 10 { SCHED_TASK(navigate), 5, 3000 }, { SCHED_TASK(update_compass), 5, 1200 }, { SCHED_TASK(read_airspeed), 5, 1200 }, { SCHED_TASK(update_alt), 5, 3400 }, { SCHED_TASK(adjust_altitude_target), 5, 1000 }, { SCHED_TASK(obc_fs_check), 5, 1000 }, { SCHED_TASK(gcs_update), 1, 1700 }, { SCHED_TASK(gcs_data_stream_send), 1, 3000 }, { SCHED_TASK(update_events), 1, 1500 }, // 20 { SCHED_TASK(check_usb_mux), 5, 300 }, { SCHED_TASK(read_battery), 5, 1000 }, { SCHED_TASK(compass_accumulate), 1, 1500 }, { SCHED_TASK(barometer_accumulate), 1, 900 }, { SCHED_TASK(update_notify), 1, 300 }, { SCHED_TASK(read_rangefinder), 1, 500 }, #if OPTFLOW == ENABLED { SCHED_TASK(update_optical_flow), 1, 500 }, #endif { SCHED_TASK(one_second_loop), 50, 1000 }, { SCHED_TASK(check_long_failsafe), 15, 1000 }, { SCHED_TASK(read_receiver_rssi), 5, 1000 }, { SCHED_TASK(airspeed_ratio_update), 50, 1000 }, // 30 { SCHED_TASK(update_mount), 1, 1500 }, { SCHED_TASK(log_perf_info), 500, 1000 }, { SCHED_TASK(compass_save), 3000, 2500 }, { SCHED_TASK(update_logging1), 5, 1700 }, { SCHED_TASK(update_logging2), 5, 1700 }, #if FRSKY_TELEM_ENABLED == ENABLED { SCHED_TASK(frsky_telemetry_send), 10, 100 }, #endif { SCHED_TASK(terrain_update), 5, 500 }, }; ... Все RTOS так устроены. И Линукс тоже, просто в нем нет такой жесткой слежки за "квантами вычислений". Я сейчас сильно упрощаю, чтобы мысль свою донести. VN> Было в некоторых (например, SPARC до VN> какого-то момента) для _исключений_, вызванных программными событиями, VN> типа неподдерживаемой команды, и то не всех (page fault, например, VN> туда не входил). Так вот в Винде, да и практически во всех ОС сейчас, вам отрезали все возмождности напрямую работать с жедезом. Вам оставили "виртуалки" которые работают через прокладку ОС и ее драйверов. Фактически все держится на очнеь высоком быстродействии... ... VN> Судя по тому, что в POWER точные исключения завезли в 1990, в x86 с VN> момента его перехода в OoO (PentiumPro - 1996), а в S/370 ещё в 70-х - VN> он отстал уже к моменту написания книги. ничего он не отстал. :-) VN> 2) А какое это вообще имеет отношение к вопросу распределения VN> прерываний по хартам/ядрам/процессорам/назови_как_хочешь? Там вопрос в VN> том, чтобы сетевуха в принципе позволяла настраивать генерацию разных VN> прерываний на разные ситуации, а дальше их раутинга по сети обработки, VN> но сама обработка прерывания не меняется. VN> Или вы про то, что вообще тема сложная? Вы не поняли. Я выше описал как это работает, в Книге тоже точно описано. Ничего не поменялось. Смотрим страницу 396. Тут ничего не поменялось с 90х. Цитата: "...Еще один важный вопрос — какой способ применить для передачи данных, синхронный (блокирующий) или асинхронный (управляемый с помощью прерываний). Большинство физических операций ввода-вывода осуществляется в асинхронном режиме: центральный процессор инициирует передачу данных и устраняется от нее для выполнения каких-нибудь других задач до тех пор, пока не поступит прерывание. А вот прикладные программы значительно легче писать, если операции ввода-вывода осуществляются в блокирующем режиме: после системного вызова read программа автоматически приостанавливается до тех пор, пока данные не поступят в буфер. На операционную систему возлагается задача, чтобы фактически управляемые с помощью прерываний операции выглядели для пользовательской программы как блокирующие. ..." Тут ничего не поменялось с тех пор. И ваша "сетевуха" может работать как я писал выше - в одном из трех режимов. Но сейчас все стараются делать (3) чтобы Устройство работало "в иной реальности времени" само по себе, а некий Арбитр должен управлять потоками данных. Иначе полная жопа будет... И число ядер тут как раз при чем - Устройство (Сеть) это ПОСЛЕДОВАТЕЛЬНЫЙ ОБМЕН. Т.е. пока летит в сетевом кабеле один пакет, второй никто не примет. Значит Устройство должно принимать все что "нормальное" куда-то в буфер, выставлять "флаги" а потом Ядра как-то(?) должны весь этот буфер разгребать. И если Ядра быстрые то они стоят, а Устройство тупо принимает пакеты и складывает. Можно в Устройство всунуть свой Процессор, очень быстрый, который будет устанавливать "еще один уровень" между Сетью(кабель) и Процессорными Ядрами (верхний уровень). Типа предварительной фильтрации по MAC "а это вообще мне?" . Вы поняли что я написал сейчас ?
Реально вы должны помнить: в современных компиляторах, вы программу пишете НЕ для железа а для "сферического процессора в акууме". Т.е. "программный код" не рассчитан на то что вот сейчас я его запущу именно с вот этогго адреса внутри памяти процессора :-) (я сейчас ОЧЕНЬ упрощаю...) Поэтому и наблюдается сейчас огромный отрыв в Программистах Старой Школы и тех кто начал писать уже с ООП и "джав". Старой школы уже отходят и умирают, а новой школы не появляется :-(
VN> Так тем, кто пишет на верхних уровнях, это всё обычно и не нужно. Зато VN> они другое умеют. Я вот например веб знаю на уровне HTML3.2 без CSS. А VN> они знают и могут за час наклепать морду управления какой-то железякой VN> с неплохим UI, им только надо сказать, за какие рычаги дёргать на VN> стороне сервера - а я бы это неделю писал. Каждому тут своё. Вы расплачиваетесь за нежелание "лезть ниже" тем что теряете производительность в 1000 раз примерно :-(. Яркие примеры сейчас - писанина для STM32 любимых контроллеров БПЛА на HAL библиотеках просто уничтожает все эти 70-150МГц таковой частоты :-( оно тупо еле вывозит такие программы. А еще сейчас куча проблем с ИИ, который "в библиотеках", которые неподьемные из-за такой вот наплевательской манеры написани кода вида "и так сойдет, если не хватает мощщи то поставьте проц пошустрее". :-( То эе самое сейчас с "переходом на цифру". Задержки на обработке видео с камеры и передаче этого в радиоканал. Я слежу за темами с 22 года - там "мрак и пьяные матросы", но все уверены что "вот-вот получится"... а ошибка то в генетике - в неправильном подходе к построению Системы. Но маладежжж только себя слушает.
Так вот, в мультипроцессорной системе, "железо" получается работает ТООЛЬКО через некую прокладку - т.е. ОС или "типа прокладок-драйверов", и вы, как Программист, постоянно оказываетесь в дурацкой ситуации: вы вроде как вынуждены применять некие функции (вызов функции) с передачей параметров, но в то же время вы полностью оторваны от "железных=аппаратных прерываний". ОС вам подсовывает некий "эрзац" который не всегда понятно как отрабатывать... (я сейчас ОЧЕНЬ упрощаю очень сложные процессы...)
VN> А что, просто на уровне ОС это уже не был эрзац? Top half VN> (hardinterrupt), bottom half (softinterrupt), состояние драйвера, VN> wakeup в обработчике, sleep в process land, пока вышел, пока проверил, VN> что нет сигналов процесса, пока шедулер разрешил исполняться...
Все еще усугубляется современным "модным течением" по "низкоуровнему программингу на Питоне". Поубивал-бы... :-( это приводит к тому, что Программисты вообще не понимают "как оно там внутри на низком уровне". Это печально, и это уже привело к "программированию для сферического коня в вакууме".
VN> Что именно надо понимать, если задача выглядит в виде "при условии VN> функция need_buka поставить высокий уровень на выходную ногу 12", VN> когда эта need_buka видит, например, команду оператора "дави его!", VN> а от того питона там клей между serial и gpio? VN> (чисто условно) VN> Разве что то, что это будет отрабатывать, условно, 20мс вместо VN> 100мкс, но если это проблема, будет отдельное ТЗ.
Но всем нравится и пипл хавает, создавая на всем этом прикладухи, а потом искренее удивляется, что оно глючит и хер знает как работает. Как выход предлагается все больше памяти и все больше тактовой частоты... но это путь в пропасть и коллапс.
Спасибо за ваше внимание, я закончил. Я бы хотел чтобы это мое сообщение осталось тут "в архивах" :-) Прочтите Книгу по моей ссылке пожалуйста.
VN> Не могу говорить за всех, но я читал. Как первое описание очень даже VN> неплохо, но надо учесть, сколько туда не попало, и что ей VN> концептуально уже лет 20-30 и она не переписывалась... VN> -netch- -- Best regards, Alexander V Soroka http://www.svr.ua/ AS106-RIPE mailto:alex@euro.net.ua