Небольшая оптимизация

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Небольшая оптимизация

Сообщение VladislavS »

Как говорится, любую прошивку можно сделать на байт короче. Так говорили в эпоху 8-биток. Сейчас на 32-битках, наверное, на все 4 байта.

Возился тут как-то с RISC-V. Исследовал особенности архитектуры - доступ к CSR, выравнивание, байтовый и пословный доступ. На включении кварца подумалось, а почему бы на Cortex-M в лице STM32 то же самое не делать? Подумано - сделано. Докладываю результаты.

Берём первый попавшийся STM32 и разными способами включаем кварцевый резонатор. Для этого надо установить один бит в регистре RCC_CR.
Изображение
Большинство (в библиотеках STM скорее всего так же) напишет вот так

Код: Выделить всё

RCC->CR |= RCC_CR_HSEON;

  0x4840         LDR.N     R0, [PC, #0x100]        ; 0x4002'1000
  0x6802         LDR       R2, [R0]
  0xf442 0x3280  ORR.W     R2, R2, #65536          ; 0x1'0000
  0x6002         STR       R2, [R0]
  
data:  
  DC32     0x40021000
Итого: 14 байт - чтение из памяти программ, чтение регистра периферии, логическая операция и запись обратно в регистр периферии.

Хотелось бы оптимальнее. Воспользуемся тем, что мы при включении питания (а по хорошему вообще всегда) знаем полное состояние RCC_CR. И просто запишем это значение с взыдённым битом HSE_ON. Получается так

Код: Выделить всё

RCC->CR = _VAL2FLD(RCC_CR_HSITRIM,16) | RCC_CR_HSION | RCC_CR_HSEON;

  0x483f         LDR.N     R0, [PC, #0xfc]         ; 0x4002'1000
  0x4a3f         LDR.N     R2, [PC, #0xfc]         ; 0x1'0081 (65665)
  0x6002         STR       R2, [R0]

data:
   DC32     0x40021000     
   DC32     0x10081
Те же 14 байт, но теперь это два чтения из памяти программ и запись в регистр периферии. Разменяли чтение регистра периферии и логическую операцию на чтение из памяти программ. Выполняться будет на несколько тактов быстрее.

До сегодняшнего дня у меня в коде так и было и кочевало из контроллера в контроллер. Но ведь можно ещё лучше сделать. Попробуем, сработает ли с байтовым доступом?

Код: Выделить всё

*((volatile uint8_t *)&RCC->CR+2) = RCC_CR_HSEON>>16;

  0x2201         MOVS      R2, #1
  0x483e         LDR.N     R0, [PC, #0xf8]         ; 0x4002'1000
  0x7082         STRB      R2, [R0, #0x2]
  
data:  
  DC32     0x40021000
И того: 10 байт - загрузка короткой константы в регистр процессора, одно чтение из памяти программ и одна запись в регистр периферии. Сработало. Ещё минус несколько таков и 4 байта кода!

Замечания: 1. Загрузка адреса регистра RCC_CR принадлежит не только операции включения кварца, а всему блоку работы с RCC. Дальше по коду наверняка будет включение PLL и это всё та же байтовая запись в старший байт того же RCC_CR не задевая младших.
2. Не вся периферия поддерживает байтовый доступ. Нужно читать документацию или пробовать.
изображение_2022-12-18_113346628.png
(16.71 КБ) 592 скачивания
Реклама
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

Ну что ж, поздравляю конечно же. Однако, всю эту прелесть сэкономленных пары-тройки тактов с лихвой обгадит время запуска кварца и выхода его на рабочий режим. И вы обязаны проверять флаг готовности HSE, поскольку если кварц сдох или просто не вышел на рабочий режим, а вы переключаетесь на него, то всей дальнейшей работе придет гитлер-капут.
Реклама
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

Ну лично я бы сделал (да иногда и делал) проще - через бит-бандинг (в тем МК, где он есть) - отдельное включение/выключение бита, отдельная проверка состояния бита. Это уж если настолько заэкономиться.
Хотя такой экономный подход лучше применять там, где он действительно будет заметен, например при частых вкл/выкл одного бита, например в таймерах, в SPI, еще в чем-то.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Небольшая оптимизация

Сообщение VladislavS »

[uquote="MLX90640",url="/forum/viewtopic.php?p=4338802#p4338802"]Однако, всю эту прелесть сэкономленных пары-тройки тактов с лихвой обгадит время запуска кварца и выхода его на рабочий режим. И вы обязаны проверять флаг готовности HSE, поскольку если кварц сдох или просто не вышел на рабочий режим, а вы переключаетесь на него, то всей дальнейшей работе придет гитлер-капут.[/uquote]Как это вообще связано с командой включения кварца? Сэкономленные такты и байты куда-то пропадут? Нет.

[uquote="MLX90640",url="/forum/viewtopic.php?p=4338828#p4338828"]Ну лично я бы сделал (да иногда и делал) проще - через бит-бандинг (в тем МК, где он есть)[/uquote]Во-первых, Cortex-M3/M4 это далеко не все кортексы. А то что я описал и на RISC-V работает. Во-вторых, не всегда нужно один бит изменять.

[uquote="MLX90640",url="/forum/viewtopic.php?p=4338828#p4338828"]Хотя такой экономный подход лучше применять там, где он действительно будет заметен, например при частых вкл/выкл одного бита, например в таймерах, в SPI, еще в чем-то.[/uquote]А если подумать? Работа с периферией обычно не ограничивается одним регистром. В любом случае загружается базовый адрес периферийного модуля и от него идёт относительная адресация к разным регистрам. Ради одного бита загружать ещё один адрес? Антиэкономия какая-то.
Реклама
Эиком - электронные компоненты и радиодетали
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

А если подумать? Сэкономленные три такта растворятся в вариациях времени запуска кварца.
Вы просто не в том месте начали оптимизировать. Хотя конечно хорошо, что вы наконец-то открыли для себя побайтовый доступ, это вам пригодится в будущем.
Ну и не стоит натягивать универсальный шаблон поведения на разные микроконтроллеры. Надо быть гибким и мыслить всегда в конкретной плоскости, а не философствовать о сферических конях в вакууме. Успешный программист - он всегда гибкий и применяющий конкретные методы из своего арсенала в различных задачах.
А тот, кто пытается, образно говоря, натянуть одинаковые трусы на все существующие жопы мира, он потратит кучу времени и создаст нечто хреново-безобразное и кривое.
Реклама
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Небольшая оптимизация

Сообщение VladislavS »

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]А если подумать? Сэкономленные три такта растворятся в вариациях времени запуска кварца.[/uquote]Не растворятся. Время будет всегда меньше на эти такты. А байты то хоть не растворятся?

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]Вы просто не в том месте начали оптимизировать.[/uquote]С чего вы взяли что я только начал оптимизировать? У меня в библиотеках давно вот такие методы есть
Спойлер

Код: Выделить всё

template<uint32_t mask>
static inline void WriteReg32(pVU32 reg, uint32_t value)
{
  if constexpr (mask==0) return;
  if constexpr (mask == 0xFFFF'FFFF)
    *reg = value;
  else if constexpr (mask == 0x0000'FFFF)
    *pVU16(reg) = value;
  else if constexpr (mask == 0xFFFF'0000)
    *(pVU16(reg) + 1) = value >> 16;
  else if constexpr (mask == 0x0000'00FF)
    *pVU8(reg) = value;
  else if constexpr (mask == 0x0000'FF00)
    *(pVU8(reg) + 1) = value >> 8;
  else if constexpr (mask == 0x00FF'0000)
    *(pVU8(reg) + 2) = value >> 16;
  else if constexpr (mask == 0xFF00'0000)
    *(pVU8(reg) + 3) = value >> 24;
  else if constexpr ((mask & 0xFFFF'FF00)==0)
    *pVU8(reg) = (*pVU8(reg) & ~mask) | value;
  else if constexpr (!(mask & 0xFFFF'00FF))
    *(pVU8(reg) + 1) = (*(pVU8(reg) + 1) & ~(mask >> 8)) | (value >> 8);
  else if constexpr (!(mask & 0xFF00'FFFF))
    *(pVU8(reg) + 2) = (*(pVU8(reg) + 2) & ~(mask >> 16)) | (value >> 16);
  else if constexpr (!(mask & 0x00FF'FFFF))
    *(pVU8(reg) + 3) = (*(pVU8(reg) + 3) & ~(mask >> 24)) | (value >> 24);
  else if constexpr (!(mask & 0xFFFF'0000))
    *pVU16(reg) = (*pVU16(reg) & ~mask) | value;
  else if constexpr (!(mask & 0x0000'FFFF))
    *(pVU16(reg) + 1) = (*(pVU16(reg) + 1) & ~(mask >> 16)) | (value >> 16);
  else
      *reg = (*reg & ~mask) | value;
}
[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]Хотя конечно хорошо, что вы наконец-то открыли для себя побайтовый доступ, это вам пригодится в будущем.[/uquote]Думаете таким мелким хамством меня задеть? Да чхать я хотел. Клоном больше, клоном меньше...

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]Ну и не стоит натягивать универсальный шаблон поведения на разные микроконтроллеры.[/uquote]Почему бы нет? Если они работают на разных контроллерах.

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]Надо быть гибким и мыслить всегда в конкретной плоскости, а не философствовать о сферических конях в вакууме.[/uquote]То то вас c одной конкретной темы на "гитлер капут" понесло.

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]Успешный программист - он всегда гибкий и применяющий конкретные методы из своего арсенала в различных задачах.[/uquote]Флаг в руки!

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339151#p4339151"]А тот, кто пытается, образно говоря, натянуть одинаковые трусы на все существующие жопы мира, он потратит кучу времени и создаст нечто хреново-безобразное и кривое.[/uquote]Жопы и анал это не ко мне, а к Eddy_Em.
Реклама
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

А если подумать получше? Время запуска кварца нестабильно, зависит от внешней среды, а она изменичива. Время запуска кварца значительно превышает те пару-тройку сэкономленных тактов, а разброс времени запуска и вовсе съест экономию чисто из-за разброса. Вы бы знали это, если бы больше практиковались.
Зря вы обижаетесь, зря! Я вам добра желаю и подсказываю, что где и как работает. Оптимизировать такты нужно там, где постоянно дергается один бит в цикле. Например, тот же самый SPI в полудуплексном режиме, когда идет смена направления передачи. Многие устройства работают по полудуплексному SPI, и чтобы прочитать регистр из устройства, нужно сначала передать в него адрес регистра, затем перевести интерфейс на прием и принимать байты.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Небольшая оптимизация

Сообщение VladislavS »

На пальцах.

Код: Выделить всё

// (1) Включить HSE  
WriteReg32<0x00FF'0000>(&RCC->CR, RCC_CR_HSEON); 
  
// (2) Включить FPU
WriteReg32<0x00FF'0000>(&SCB->CPACR, 0x00F0'0000);

// (3) Ждать включения HSE
while(!(RCC->CR & RCC_CR_HSERDY));
Команда N3 полностью "съедает" все такты (не только сэкономленные) команды N2, но не команды N1. И никак не влияет на сэкономленные байты обеих команд.
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

А вы молодец, что шуршите байтиками головного мозга :) Правда, еще не достаточно интенсивно. Я ж говорю, если бы в больше практиковались, то понимали бы, что время запуска кварца намного превышает время прохода нескольких инструкций, и во-вторых и это самое главное тут - оно ИЗМЕНЧИВО! :))) Понимаете, оно непостоянно, и мера его непостоянности превышает количество сэкономленных тактов.

Вот на практике, по результатам 4-х измерений:
Изображение
Как видно, время запуска кварца в среднем чуть больше 300 мкс (более 2400 тактов при HSI 8 МГц), а вариации в четырех попытках даже в одних и тех же условиях составляют 7 мкс или 56 тактов при HSI 8 МГц. Если частота HSI будет 16 МГц, то разница будет еще более заметна. А сколько сэкономили вы? Пусть даже 20 тактов. Всё равно они отбиваются вариациями времени запуска, особо заметными при изменении температуры и питания.
И вы сами можете в этом убедиться, конечно если у вас вообще есть осциллограф или лог.анализатор, и вообще есть микроконтроллер в железе :)))
Ну а когда дорастете до запуска "часового" LSE, поразитесь еще больше - время запуска и его вариации измеряются аж в секундах!
Вот так то! Это, брат, не теория, это практика, суровая и беспощадная :))) Вот только ради бога не обижайтесь, это же реалии, а на них нельзя обижаться.
А вот вам еще тема для "подумать, поковыряться": зачем сделано прерывание по готовности HSE? Показанное время его запуска и кол-во тактов ожидания как бы проясняют и намекают на ответ :)
В общем, пожелание - в наступающем году купите лог.анализатор и отладочную плату и потыкайте всё это на практике. Ну, с новым годом, удачи! :)
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Небольшая оптимизация

Сообщение VladislavS »

Поразительно. Столько энергии тратить чтобы доказать, что бесплатное уменьшение размера прошивки и увеличение скорости исполнения команды это плохо. Даже какую-то диаграмму, совершенно не относящуюся к делу, снял зачем-то. Она показвает время исполнения команды? Нет. Может размер прошивки на ней видно? Тоже нет. Показывает, что у дяди на работе есть дешёвенький осциллограф и неумение поставить эксперимент. А все эти рассуждения о наличии у меня приборов, отладочных плат, автомобилей, яхт и т.д. это банальное хамство, которым прикрывается отсутствие аргументов. Остаётся только сожалеть, что модератор покрывает это.

PS: Человек мало мальски разбирающийся в вопросе спросил бы: а какое ядро процессора, есть ли там конвейер, кэши, предвыборка, предсказание переходов и т.д. А "форумный эксперд" будет время запуска кварца измерять зачем-то...
Аватара пользователя
MLX90640
Опытный кот
Сообщения: 848
Зарегистрирован: Ср авг 03, 2022 05:22:56

Re: Небольшая оптимизация

Сообщение MLX90640 »

Долго ж вы думали, как ответить. Вчера зашли, прочитали, задумались и ушли, долго примеряли то да сё, пытаясь хоть чето вкурить, сегодня поняли, что ничерта не врубились и за неимением адекватных аргументов, решили что лучше будет просто нахамить, чем признаться в своей неправоте. Даже когда наглядно показал вам время запуска кварца, вы все ещё ничего не поняли. Это говорит о том, что вы совершенно оторваны от практики и не способны осознать физические явления. Ну и судя по тому, что не умеете прочесть и понять цифры, то ни осциллом, ни анализатором вы не пользовались. Иначе бы поняли!
Никакие кэши и предсказания переходов не помогут, когда время ФИЗИЧЕСКОГО запуска кварца более 2 тыс тактов. Вы это не можете осознать просто потому, что не пробовали вживую в железе :)

И прекращайте хамить и ябидничать уже! С вами тут цацкаются, а вы ведёте себя как хамло какое-то форумное. Некрасиво это, некрасиво.
Ели вы считаете, что задето ваше непогрешимое ЧСВ, ну что ж поделать, напишите все ваши претензии и недовольства на бумажке и сходите с ней в туалэт типа сортир :) ничем другим никто вашему безумно ущемленному ЧСВ не поможет
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Небольшая оптимизация

Сообщение AVI-crak »

[uquote="MLX90640",url="/forum/viewtopic.php?p=4339925#p4339925"]Как видно, время запуска кварца в среднем чуть больше 300 мкс (более 2400 тактов при HSI 8 МГц), а вариации в четырех попытках даже в одних и тех же условиях составляют 7 мкс или 56 тактов при HSI 8 МГц.[/uquote]
Кстати , за 2400 тактов можно успеть настроить 20 ног самым топорным способом. Ну или все сразу загрузкой массива.

Оптимизацией приходится заниматься когда прижмёт, ну или когда слишком много свободного времени. Я для этих целей использую https://godbolt.org/z/7hro4zPPz , там очень удобно в плане быстрого переключения между разными мк и компиляторами. Самый уродливый код получается на старой авр (чисто поржать).

VladislavS - забей на этот бит-бандинг, с ним у тебя будут большие проблемы на старших чипах.
Аватара пользователя
VladislavS
Собутыльник Кота
Сообщения: 2562
Зарегистрирован: Вт май 01, 2018 19:44:47

Re: Небольшая оптимизация

Сообщение VladislavS »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4340768#p4340768"]VladislavS - забей на этот бит-бандинг, с ним у тебя будут большие проблемы на старших чипах.[/uquote]Вы что-то путаете, ни разу в жизни не пользовался бит-бандингом.
Ответить

Вернуться в «ARM»