jcxz 243 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба В 12.12.2023 в 05:00, tonyk_av сказал: Можно теперь послушать тех, кто изучал математику ЭВМ, численные методы и знает, как обрабатывать ошибки вычислений FPU? Как уже выше сказали - не нужно закладываться на обработку ошибок. Нужно их не допускать. А обработка - только для тех ошибок, которые не смогли обнаружить (багов в программе). И только с целью - устранить их в дальнейшем, чтобы таких срабатываний не было. Закладываться на обработку ошибок FPU, это примерно то же самое, что закладываться на срабатывание WDT (из-за ошибок в ПО) как на штатную работу программы. 6 часов назад, tonyk_av сказал: Странно, что люди выполняют расчёты, но даже не знают, как проверить их достоверность, иначе сразу бы отослали меня к этому РМ. Видимо "люди выполняющие расчёты" не лепят костыли по вашему методу. Не задумывались? 3 часа назад, tonyk_av сказал: Такие ситуации невозможно выявить проверками до начала вычислений Сомнительное утверждение. 3 часа назад, tonyk_av сказал: Не такая уж и узкая и специфическая. Дело в другом. Если кто-то выполняет вычисления на FPU в задачах управления, то перед выдачей управляющих воздействий он должен проверить достоверность результата хотя бы с точки зрения математики, а то получит NaN и фиганёт его в виде 0xFFFFFFFF на ЦАП. Для этого проверяются исходные данные на их допустимость. Чтобы не было NaN и пр. Условия возикновения NaN вроде как везде прописаны - в чём проблема проверить эти условия? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба 6 hours ago, jcxz said: Видимо "люди выполняющие расчёты" не лепят костыли по вашему методу. Не задумывались? Шедеврально! Я даже в лёгком шоке, ибо не могу сходу ответить на обзывание костылями того, без чего не работает ни одно серьёзное приложение. Что вы увидите, когда запустите вашу программу под Виндой, в которой есть строчка? x /= 0; Не BSoD, а сообщение о недопустимой операции. Не задумывались, откуда оно взялось? 6 hours ago, jcxz said: Нужно их не допускать. А обработка - только для тех ошибок, которые не смогли обнаружить Так именно это и делается. Вычислительный алгоритм может быть сложным, да ещё и циклическим, поэтому при одном наборе данных алгоритм может давать нормальное число, а при другом- не число. 6 hours ago, jcxz said: Условия возникновения NaN вроде как везде прописаны - в чём проблема проверить эти условия? Посмотрите для начала список исключений, которые могут возбуждать команды FPU. Большинство команд могут возбуждать по несколько исключений в зависимости от значений своих операндов, поэтому общепринятой практикой является отсутствие проверок перед выполнением команд FPU и информирование пользователя в том или ином виде, что при выполнении вычислений произошла ошибка. Вы в своих программах перед каждым сложением или вычитаем проверяете каждый целочисленный операнд да допустимость их значений, гарантирующих, что при сложении/вычитании не произойдёт переполнения? Представляете, во что выливается такая проверка? Ниже пример реализации целочисленного сложения. Код этого функционального блока: Spoiler // В - флаг заёма; // С - флаг переполнения; // Z - флаг нулевого результата. void PLC_base::ADD( void ) { if( hasnotPulsFlag ) { int16 a = getValue(), b = getValue(); if ( ( ( b > 0 ) && ( a > SHRT_MAX - b ) ) || ( ( b < 0 ) && ( a < SHRT_MIN - b ) ) ) { if( ( a > 0 ) && ( b > 0 ) ) { clearSpecialMarker( 8021 ); // B setSpecialMarker( 8022 ); // C } else { setSpecialMarker( 8021 ); // B clearSpecialMarker( 8022 ); // C } } else { clearSpecialMarker( 8021 ); // B clearSpecialMarker( 8022 ); // C } acc.i16[ 0 ] = a + b; // Z ( acc.i16[ 0 ] == 0 ) ? ( setSpecialMarker( 8020 ) ) : ( clearSpecialMarker( 8020 ) ); putValue(); } else { pc += 6; } } FPU при работе на аппаратном уровне вычисляет и результат, и флаги, причём делает это очень быстро. Так нафига мне делать туеву хучу проверок, когда FPU просто дёрнет прерывание в случае недопустимых данных? Зачем _программно_ дублировать _аппаратный_ функционал FPU? Не задумывались? Или все люди имбицилы, которые только и занимаются делением на ноль и извлечением корня из отрицательного числа? Меня окружают люди, которые понимают математику, поэтому их программы в процессе вычислений крайне редко делают ошибки, так зачем тратить кучу времени на проверки, существенно замедляющие работу, когда можно в редких случаях обработать прерывание от FPU при ошибке вычислений и установить флаг недостоверности результата вычислений? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 13 декабря, 2023 Опубликовано 13 декабря, 2023 · Жалоба 27 минут назад, tonyk_av сказал: Вы в своих программах перед каждым сложением или вычитаем проверяете каждый целочисленный операнд да допустимость их значений, гарантирующих, что при сложении/вычитании не произойдёт переполнения? Очевидно, что проверять нужно только там, где это необходимо. И да - я проверяю везде где это необходимо. Т.е. - везде где операция может привести к исключению (переполнению, делению на 0 и т.п.). И не вижу никаких проблем сделать это. Перед каждым это не делать не нужно. Вы в школе когда-нить учились? Если учились, то должны знать, что например если складываете 2 аргумента, про значения которых известно, что они занимают не более N бит каждое, то сумма их займёт не более (N+1) бит. Если перемножаете два значения, то разрядность их произведения не должна превышать суммы разрядности операндов. Отсюда можно догадаться - когда и где нужно проверять. Вроде очевидные вещи. Не думал, что на этом форуме кто-то может не знать этого. 27 минут назад, tonyk_av сказал: Представляете, во что выливается такая проверка? Представляю - в одну команду CMP на каждое сравнение. 27 минут назад, tonyk_av сказал: так зачем тратить кучу времени на проверки, существенно замедляющие работу, когда можно в редких случаях обработать прерывание от FPU при ошибке вычислений и установить флаг недостоверности результата вычислений? Зачем городить кучу кода, в котором определять - где именно случилось это прерывание? И где нужно что-то корректировать. В нормальной программе, работающей с математикой, обычно множество математических операций. К тому же часто такие вычисления собраны в модули логические законченные обособленные друг от друга. Часто бывает ещё и с условной компиляцией. Допустим - есть у меня драйвер или библиотека, функционально законченная, выполняющая какую-то математику. С моим подходом - она легко переносима из проекта в проект, к тому-же - на разные платформы (хоть embedded, хоть win/linux). А как прикажете переносить ваши костыли в другой проект? Или на другую платформу? А если в том проекте уже реализовали ваш костыльный метод - как будете объединять? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 14 декабря, 2023 Опубликовано 14 декабря, 2023 (изменено) · Жалоба 9 hours ago, jcxz said: Зачем городить кучу кода, в котором определять - где именно случилось это прерывание? А зачем определять где? Как оказалось, достаточно знать, что при вычислениях была ошибка. Выполнение основного потока команд продолжается, пусть и с прерыванием на установку флага ошибки. Так что кода там мизер. Пример в PM0214. 9 hours ago, jcxz said: С моим подходом - она легко переносима из проекта в проект, к тому-же - на разные платформы (хоть embedded, хоть win/linux). Здесь STM32, поэтому я просто использую доступный на STM32 функционал. Никого же не смущает, что код работы с UART на STM32 не работает под Виндой. 9 hours ago, jcxz said: И да - я проверяю везде где это необходимо. Т.е. - везде где операция может привести к исключению (переполнению, делению на 0 и т.п.). И не вижу никаких проблем сделать это. То есть тупо дублируете функционал FPU. Зачем? Не доверяете FPU? Ведь проще выполнить операцию и посмотреть флаги результата её выполнения, чем городить кучу кода для проверок или вычисление флагов. Пример выше, в функции ADD, где значения флагов B, C, и Z определяются _до_ выполнения операции сложения, хотя если уйти от кросплатформенности, то можно просто копировать в маркеры значения флагов процессора после выполнения сложения, что будет значительно быстрей и потребует значительно меньше кода. Ещё раз: это нормальный способ. На разных платформах разные механизмы обработки. Изменено 14 декабря, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 25 14 декабря, 2023 Опубликовано 14 декабря, 2023 · Жалоба Я тоже не понимаю, что делать в обработчике исключения FPU. Сохранять дамп стека для диагностики и уходить в рестарт? Чем не устраивает проверка результата на NaN? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 14 декабря, 2023 Опубликовано 14 декабря, 2023 · Жалоба 17 minutes ago, amaora said: Я тоже не понимаю, что делать в обработчике исключения FPU Пример в PM0214. Плюс установить для пользователя флаг ошибки вычислений 18 minutes ago, amaora said: Чем не устраивает проверка результата на NaN? NaN только пример. У FPU есть ещё исключения. Ещё раз: смысл обработки исключений FPU в том, чтобы не тратить время на проверки перед выполнением операций, дублируя функционал FPU, а реагировать на ошибки, выявляемые FPU в процессе его работы. Ведь ошибки должны возникать редко, так какой смысл тратить на проверки значений операндов команд времени больше, чем выполняется сама команда? 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 14 декабря, 2023 Опубликовано 14 декабря, 2023 · Жалоба 1 час назад, tonyk_av сказал: Ещё раз: смысл обработки исключений FPU в том, чтобы не тратить время на проверки перед выполнением операций, дублируя функционал FPU, а реагировать на ошибки, выявляемые FPU в процессе его работы. Ведь ошибки должны возникать редко, так какой смысл тратить на проверки значений операндов команд времени больше, чем выполняется сама команда? Обычно в серьёзной программе математики бывает много. Она бывает часто размазана по множеству файлов, функций. Эти функции могут вызываться из разных задач ОС и ISR. В каких-то из этих функций - ошибку можно проигнорить (сбросить), в других - её быть не должно (ошибка - следствие программного бага, который нужно исправить), в третьих - нужно сделать что-то ещё (скорректирорвать операнды например). Что значит "тратить на проверки значений операндов команд времени больше, чем выполняется сама команда" если предлагаемый вами способ приведёт как раз к увеличению трат? При таком событии, чтобы найти где именно возникла ошибка, и как на неё реагировать, придётся вводить какие-то флажки состояний. По которым ISR FPU сможет понять - где произошла ошибка? К тому же - эти флажки нужно оперативно переключать при переключении задачи ОС и при активации прерывания (в котором тоже могут быть вычисления). У вас весь вычислительный код будет утыкан переключениями флажков. А также - переключатели контекста задач ОС должны содержать средства для сохранения/восстановления этих флажков в контексте прерванной задачи ОС. Это породит кучу лишнего кода. При том, что и сам анализ в ISR FPU будет тоже развесистым. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 14 декабря, 2023 Опубликовано 14 декабря, 2023 · Жалоба 16 minutes ago, jcxz said: При таком событии, чтобы найти где именно возникла ошибка, Искать не нужно, адрес в стэке. 17 minutes ago, jcxz said: В каких-то из этих функций - ошибку можно проигнорить (сбросить) Ошибка FPU сбрасывается всегда. Для пользователя выставляется флаг ошибки, с которым он волен делать что хочет. 20 minutes ago, jcxz said: При таком событии, чтобы найти где именно возникла ошибка, и как на неё реагировать, придётся вводить какие-то флажки состояний Ессно! В используемой модели данных ПЛК уже есть флаги ошибок вычисления. Мне просто нужно их устанавливать. 21 minutes ago, jcxz said: По которым ISR FPU сможет понять - где произошла ошибка? Читаем PM0214. И какая ошибка, и где она возникло- всё известно при входе в обработчик. 23 minutes ago, jcxz said: эти флажки нужно оперативно переключать при переключении задачи ОС У каждой задачи свой набор исключений, так что это не проблема. 24 minutes ago, jcxz said: при активации прерывания (в котором тоже могут быть вычисления) Ну так сделайте приоритет прерывания FPU выше, чем у прерываний, использующих FPU. В чём проблема? 25 minutes ago, jcxz said: У вас весь вычислительный код будет утыкан переключениями флажков Какими переключателями? Нет там никаких переключателей флажков, в этом-то и смысл использования прерывания FPU. Это же ПЛК, там нет кучи флагов, а есть условное исполнение: загрузил инверсию флага ошибки в LRO и всё. В зависимости от этого флага все команды, зависящие от него или будут, или не будут исполнятся. 36 minutes ago, jcxz said: переключатели контекста задач ОС должны содержать средства для сохранения/восстановления этих флажков в контексте прерванной задачи ОС. Используется FreeRTOS, для которой написана обёртка на С++. При создании задачи ОС в параметрах задачи сохраняется указатель на экземпляра класса задачи, в котором будет флаг ошибки FPU. Думаю, в FreeRTOS API найдётся функция извлечения дескриптора выполняемой задачи. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 14 декабря, 2023 Опубликовано 14 декабря, 2023 · Жалоба 19 минут назад, tonyk_av сказал: Искать не нужно, адрес в стэке. И дальше что? Как этот адрес будете сопоставлять конкретному участку си-кода? Разбивать этот код на кучу мелких функций? Кроме того: Вот есть какая-то вычислительная функция. Которая может генерить исключение. Вызывается она из кода в котором нужно игнорировать ошибки FPU и из кода в котором их игнорироввать нельзя. В ней происходит прерывание FPU. Как по одному только адресу этой функции определите - нужно сбрасывать или не нужно? А если та функция вызывает из себя другую функцию? А если оптимизатор обнаружил общий участок кода в функции, в которой надо игнорить флажок и в функции в которой нельзя игнорить (и вынес их в отдельную функцию, которую он сам создал)? И ошибка случилась именно в этом участке кода: как будете определять - нужно сбрасывать или нет? 19 минут назад, tonyk_av сказал: Ошибка FPU сбрасывается всегда. Для пользователя выставляется флаг ошибки, с которым он волен делать что хочет. А ничего, что сбросить её можете и там, где не нужно? Где её быть не должно, а возникла она из-за программного бага? 19 минут назад, tonyk_av сказал: Какими переключателями? Нет там никаких переключателей флажков, в этом-то и смысл использования прерывания FPU. Если задача может как выполнять код, в котором надо сбрасывать ошибки так и код в котором их не надо сбрасывать, то надо флажком обозначить место, где нужен сброс. А значит нужно сохранять/восстанавливать этот флажок при переключении задач в контексте прерванной задачи. 40 минут назад, tonyk_av сказал: Это же ПЛК, там нет кучи флагов Кроме кода ПЛК в программе что-ли нет другого кода, использующего FPU? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 19 декабря, 2023 Опубликовано 19 декабря, 2023 (изменено) · Жалоба On 12/14/2023 at 5:32 PM, jcxz said: И дальше что? Как этот адрес будете сопоставлять конкретному участку си-кода? Разбивать этот код на кучу мелких функций? В этом нет необходимости. Задача ПЛК исполняет байт-код, дескриптор задачи ОС известен, номер шага программы ПЛК, вызвавшего сбой, тоже известен, так что ошибка определяется с точностью до команды ПЛК, что, собственно, и требуется. On 12/14/2023 at 5:32 PM, jcxz said: А ничего, что сбросить её можете и там, где не нужно? Код ошибки запоминается в поле задачи. Spoiler class Task : protected TaskBase { ... public: enum FPU_error // Флаги ошибок FPU { NO_ERROR = 0x00, // нет ошибок; INVALID_OPERATION = 0x01, // неправильный код команды FPU; DIVIZION_BY_ZERO = 0x02, // деление на ноль; OVERFLOW = 0x04, // переполнение вверх; UNDERFLOW = 0x08, // переполнение вниз; INEXACT = 0x10, // потеря точности; INPUT_DENORMAL = 0X80 // денормализапция числа. } fpu_error; ... } //////////////////////////////////////////////////////////////////////////////// void Task::handleFPUerror( Task::FPU_error _error ) { if ( _error & \ ( Task::FPU_error::INVALID_OPERATION | Task::FPU_error::DIVIZION_BY_ZERO | Task::FPU_error::OVERFLOW | Task::FPU_error::UNDERFLOW | Task::FPU_error::INEXACT | Task::FPU_error::INPUT_DENORMAL ) ) { __disable_irq(); { fpu_error = _error; } __enable_irq(); } } //////////////////////////////////////////////////////////////////////////////// void FPU_device::IRQ_Handler( void ) { volatile uint32 fpscr_val; // Читаем регистр флагов состояния VFP. asm volatile( "VMRS %0, FPSCR" : "=r" ( fpscr_val ) ); // Получаем указатель на класс выполняющейся сейчас задачи. Task* curr_task = Task::getCurrentTask(); if( curr_task != 0 ) { curr_task -> handleFPUerror( ( Task::FPU_error )( fpscr_val & 0x9F ) ); } // Сбрасываем все флаги ошибок. fpscr_val &= ( uint32 )~0x9F; asm volatile("VMSR FPSCR, %0" : : "r" ( fpscr_val ) ); // Очищаем запрос прерывания. IRQ::clearIRQ( FPU_IRQn ); } On 12/14/2023 at 5:32 PM, jcxz said: Кроме кода ПЛК в программе что-ли нет другого кода, использующего FPU? Пока нет. Я понимаю о чём речь. Приоритет прерывания от VFP выше, чем у планировщика FreeRTOS, поэтому пока не отработает прерывание VFP, задачи не переключатся. В других прерываниях VFP не используется, но если потребуется, то нужно будет сохранять его контекст при входе в обработчик, но пока при входе в другие обработчики я не делаю даже ленивого сохранения. Изменено 19 декабря, 2023 пользователем tonyk_av Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 19 декабря, 2023 Опубликовано 19 декабря, 2023 · Жалоба 13 минут назад, tonyk_av сказал: В других прерываниях VFP не используется, но если потребуется, то нужно будет сохранять его контекст при входе в обработчик, но пока при входе в другие обработчики я не делаю даже ленивого сохранения. Ну если так, то наверное будет работать. Но нужно быть аккуратнее с использованием чужого кода (если будете его использовать). Кто его знает - что там в глубинах чужого кода делается? Вдруг там по какой-то ветке операции FPU выполняются... а вы контекст не сохранили... Так можно получить трудноуловимый баг. Я тоже так раньше делал (отключал ленивое сохранение контекста для экономии стека прерываний), так как использовал FPU только в одной задаче. Но нужно быть уверенным, что знаешь все места, где в твоём коде используется FPU. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 19 декабря, 2023 Опубликовано 19 декабря, 2023 · Жалоба 18 minutes ago, jcxz said: Но нужно быть аккуратнее с использованием чужого кода Согласен. Я посмотрел пару использованных библиотек, но там плавающей точки нет. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
amaora 25 19 декабря, 2023 Опубликовано 19 декабря, 2023 · Жалоба В некоторых случаях видел как компилятор реализовывал примитивный цикл копирования 32-битных слов через 64-битные регистры fpu. Долго ловил жука, не ожидал, что инструкции fpu окажутся в том месте где работы с fp не было ни в каком виде. 1 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
tonyk_av 45 20 декабря, 2023 Опубликовано 20 декабря, 2023 · Жалоба 7 hours ago, amaora said: В некоторых случаях видел как компилятор реализовывал примитивный цикл копирования 32-битных слов через 64-битные регистры fpu. Долго ловил жука, не ожидал, что инструкции fpu окажутся в том месте где работы с fp не было ни в каком виде. О как. Возьму на заметку, буду обращать внимание на дизассемблер. По-моему, такие фишки должны управляться опциями компилятора, разве нет? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 20 декабря, 2023 Опубликовано 20 декабря, 2023 · Жалоба 7 часов назад, amaora сказал: В некоторых случаях видел как компилятор реализовывал примитивный цикл копирования 32-битных слов через 64-битные регистры fpu. Долго ловил жука, не ожидал, что инструкции fpu окажутся в том месте где работы с fp не было ни в каком виде. Согласен. Тоже сталкивался с таким. Даже где-то здесь на форуме писал об этом (можно поискать). Именно после этого я и перестал выключать сохранение контекста FPU. 12 минут назад, tonyk_av сказал: По-моему, такие фишки должны управляться опциями компилятора, разве нет? IAR это делает автоматом. Иногда. И отключить это можно только полным запретом использования FPU (насколько помню - к такому выводу пришли в результате обсуждения тут). 10 часов назад, tonyk_av сказал: Согласен. Я посмотрел пару использованных библиотек, но там плавающей точки нет. А стандартную библиотеку Вы какую используете? С плавающей точкой или без? Использование плавучки может быть малозаметным. И обнаруживаться только в листинге. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться