Ассемблеристы есть ?
Кто то доставал до дна производительности STM32F1 ?
-
V2oD2o
- Встал на лапы
- Сообщения: 90
- Зарегистрирован: Чт дек 09, 2010 12:03:08
- Откуда: Зеленоград
- Контактная информация:
Кто то доставал до дна производительности STM32F1 ?
Очень интересны проекты, так скажем "высоконагруженные" в которых не хватало бы производительности камушков STM32F103
Ассемблеристы есть ?
Ассемблеристы есть ?
Re: Кто то доставал до дна производительности STM32F1 ?
Для этого не нужен ассемблер, это не авр. Для этого надо досконально знать периферию а не юзать софтовоеногодрочерство
-
V2oD2o
- Встал на лапы
- Сообщения: 90
- Зарегистрирован: Чт дек 09, 2010 12:03:08
- Откуда: Зеленоград
- Контактная информация:
Re: Кто то доставал до дна производительности STM32F1 ?
Для этого не нужен ассемблер, это не авр. Для этого надо досконально знать периферию а не юзать софтовоеногодрочерство
Хм, открытия не сделал конечно, я с этим согласен, но все же хотелось бы привлечь в эту ветку ассемблерного умельца
Есть просто проект, который скоро нащупает дно производительности, хотелось бы обсудить отладку и всякие тонкости по тактам выполнения кода
Re: Кто то доставал до дна производительности STM32F1 ?
Очень интересны проекты, так скажем "высоконагруженные" в которых не хватало бы производительности камушков STM32F103
Если удалось "достать до дна", то обычно это уже приводит к неработоспособности алгоритма работающего в реальном времени.
А если говорить не о реальном времени, то любое устройство, которое например отображает какие-то данные для пользователя, может работать на дне (только своей задачей визуализации) - ну и что?
Добавлено after 1 minute 31 second:
Ассемблеристы есть ? 
Иногда пишу отдельные функции на асме. В том числе - и для оптимизации по скорости. Только обычно на CM4.
-
V2oD2o
- Встал на лапы
- Сообщения: 90
- Зарегистрирован: Чт дек 09, 2010 12:03:08
- Откуда: Зеленоград
- Контактная информация:
Re: Кто то доставал до дна производительности STM32F1 ?
[uquote="V2oD2o",url="/forum/viewtopic.php?p=3658085#p3658085"]Очень интересны проекты, так скажем "высоконагруженные" в которых не хватало бы производительности камушков STM32F103
Если удалось "достать до дна", то обычно это уже приводит к неработоспособности алгоритма работающего в реальном времени.
А если говорить не о реальном времени, то любое устройство, которое например отображает какие-то данные для пользователя, может работать на дне (только своей задачей визуализации) - ну и что?
Добавлено after 1 minute 31 second:
Ассемблеристы есть ? 
Иногда пишу отдельные функции на асме. В том числе - и для оптимизации по скорости. Только обычно на CM4.[/uquote]
Тут девайс реального времени, специально нагружал расчётами мусора чтоб посмотреть что будет и как это будет, таймер просто вываливается из своего интервала
Может есть какие то примерчики реализаций оптимизации? я конечно местами использую асм для обхода ситуаций - не понятно почему генерируемых компилятором - но не уверен что делаю все правильно, т.к. литературы и примеров - раз-два в доступе..
Так скажем на перспективу изучаю вопрос
Re: Кто то доставал до дна производительности STM32F1 ?
Может есть какие то примерчики реализаций оптимизации?
Ну что значит "примерчики"? Для каждой задачи - своё решение.
А из общий мелочей, ну например вместо:
int i;
if ((int)(i -= N) < 0) i = 0;
если известно, что (uint)i < (1u<<31) можно использовать:
i = __USAT(i - N, 31);
Изучайте систему команд CPU - много полезного найдёте!
т.к. литературы и примеров - раз-два в доступе..
Единственная литература которая для этого нужна: http://infocenter.arm.com/help/topic/co ... 3_dgug.pdf
Больше ничего не нужно.
-
V2oD2o
- Встал на лапы
- Сообщения: 90
- Зарегистрирован: Чт дек 09, 2010 12:03:08
- Откуда: Зеленоград
- Контактная информация:
Re: Кто то доставал до дна производительности STM32F1 ?
[uquote="V2oD2o",url="/forum/viewtopic.php?p=3658164#p3658164"]Может есть какие то примерчики реализаций оптимизации?
Ну что значит "примерчики"? Для каждой задачи - своё решение.
А из общий мелочей, ну например вместо:
int i;
if ((int)(i -= N) < 0) i = 0;
если известно, что (uint)i < (1u<<31) можно использовать:
i = __USAT(i - N, 31);
Изучайте систему команд CPU - много полезного найдёте!
т.к. литературы и примеров - раз-два в доступе..
Единственная литература которая для этого нужна: http://infocenter.arm.com/help/topic/co ... 3_dgug.pdf
Больше ничего не нужно.[/uquote]
Вот этот документ как раз то что нужно - спасибо!
Re: Кто то доставал до дна производительности STM32F1 ?
На 72МГц ногодрыг предел 12МГц и это синтетически на ассемблере просто переключение ноги в цикле и с учетом особенностей конвеера. Если просто на Си это же написать, уже будет вроде 8МГц, просто переключение ноги в цикле. Что-то осмысленное вообще драматические цифры выдаст по сравнению с тактовой.
Чтобы просто поменять значение ноги на порту, нужно:
1. Загрузить в регистр адрес.
2. Загрузить в регистр значение по этому адресу.
3. Изменить значение.
4. Записать обратно.
В том же STM8 это можно сделать одной командой bset/bres
. На 16МГц STM8 из аккумулятора через bccm можно выплюнуть ногодрыгом осмысленный байт на 8МГц.
Благо у STM32 богатая периферия и следует ее хорошо изучить и использовать.
Чтобы просто поменять значение ноги на порту, нужно:
1. Загрузить в регистр адрес.
2. Загрузить в регистр значение по этому адресу.
3. Изменить значение.
4. Записать обратно.
В том же STM8 это можно сделать одной командой bset/bres
Благо у STM32 богатая периферия и следует ее хорошо изучить и использовать.
Последний раз редактировалось dekus Вт июл 02, 2019 13:16:12, всего редактировалось 1 раз.
Re: Кто то доставал до дна производительности STM32F1 ?
На 72МГц ногодрыг предел 12МГц и это синтетически на ассемблере просто переключение ноги в цикле и с учетом особенностей конвеера.
Про ногодрыг тут никто вроде и не говорил. С чего Вы его сюда приплели?

Re: Кто то доставал до дна производительности STM32F1 ?
Я ничего не приплетал. Второе сообщение прочитайте. Про ногодрыг и перефирию. Я продолжил
.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Кто то доставал до дна производительности STM32F1 ?
Если просто на Си это же написать, уже будет вроде 8МГц, просто переключение ноги в цикле.
Неправда, будет то же самое. С-ные компиляторы сейчас умные. Что-то осмысленное вообще драматические цифры выдаст по сравнению с тактовой.
Чтобы просто поменять значение ноги на порту, нужно:
1. Загрузить в регистр адрес.
2. Загрузить в регистр значение по этому адресу.
3. Изменить значение.
4. Записать обратно.
В том же STM8 это можно сделать одной командой bset/bres
.
Вы мешаете в кучу особенности разных архитектур и эффект от применения ассемблера по сравнению с C.Чтобы просто поменять значение ноги на порту, нужно:
1. Загрузить в регистр адрес.
2. Загрузить в регистр значение по этому адресу.
3. Изменить значение.
4. Записать обратно.
В том же STM8 это можно сделать одной командой bset/bres
Три простых примера. Тут компилятор раскрутил цикл.
Спойлер
Код: Выделить всё
using namespace IOPORTS;
PA_1 NOGA;
for(auto i=0; i<8; i++)
{
NOGA=1;
NOGA=0;
}Код: Выделить всё
LDR.N R5,??DataTable4_2 ;; 0x40010810
MOVS R0,#+2
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]
STR R0,[R5, #+0]
STR R0,[R5, #+4]Сделаем цикл подлиннее, не дадим ему самовольничать
Спойлер
Код: Выделить всё
using namespace IOPORTS;
PA_1 NOGA;
for(auto i=0; i<32; i++)
{
NOGA=1;
NOGA=0;
}Код: Выделить всё
MOVS R0,#+32
LDR.N R5,??DataTable4_2 ;; 0x40010810
MOVS R1,#+2
??main_0:
STR R1,[R5, #+0]
SUBS R0,R0,#+1
STR R1,[R5, #+4]
BNE.N ??main_0И всё же с раскруткой было быстрее, поможем ему чутка
Спойлер
Код: Выделить всё
void NogoDryg()
{
using namespace IOPORTS;
PA_1 NOGA;
NOGA=1;
NOGA=0;
}
int main()
{
for(;;)
{
Repeat<NogoDryg,32>();
}
}Код: Выделить всё
LDR.N R0,??DataTable4_2 ;; 0x40010810
MOVS R1,#+2
??main_0:
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
STR R1,[R0, #+0]
STR R1,[R0, #+4]
B.N ??main_0А вот ещё панкуха. Поменяем на обратный порядок бит на 32-битной шине.
Спойлер
Код: Выделить всё
using namespace IOPORTS;
typedef PinList<PA_0, PA_1, PA_2, PA_3, PA_4, PA_5, PA_6, PA_7,
PA_8, PA_9, PA_10, PA_11, PA_12, PA_13, PA_14, PA_15,
PB_0, PB_1, PB_2, PB_3, PB_4, PB_5, PB_6, PB_7,
PB_8, PB_9, PB_10, PB_11, PB_12, PB_13, PB_14, PB_15> DATA_BUS;
DATA_BUS bus;
bus = __RBIT(bus);Код: Выделить всё
LDR.N R5,??DataTable4_3 ;; 0x40010808
LDR R0,[R5, #+0]
LDR R1,[R5, #+1024]
UXTH R0,R0
ORR R0,R0,R1, LSL #+16
RBIT R0,R0
UXTH R1,R0
STR R1,[R5, #+4]
LSRS R0,R0,#+16
STR R0,[R5, #+1028]
Или вот то же самое на 8-битной.
Спойлер
Код: Выделить всё
using namespace IOPORTS;
typedef PinList<PA_5, PA_6, PA_7, PA_8, PA_9, PA_10, PA_11, PA_12> DATA_BUS;
DATA_BUS bus;
bus = __RBIT(bus) >> 24;Код: Выделить всё
LDR.N R5,??DataTable4_3 ;; 0x40010808
LDR R0,[R5, #+0]
UBFX R0,R0,#+5,#+8
RBIT R0,R0
LSRS R0,R0,#+24
LSLS R0,R0,#+5
ORR R0,R0,#0x1FE00000
STR R0,[R5, #+8]
Резюме! Всё нужно применять к месту. Ассемблер там где без него действительно не обойтись. Ногодрыг, собственно, тоже.
Re: Кто то доставал до дна производительности STM32F1 ?
Неправда, будет то же самое. С-ные компиляторы сейчас умные.
Вы можете выложить скриншот с осциллографа или лог. анализатора с результатом 12МГц на F103 72МГц с простым кодом - переключение туда сюда одной ноги в бесконечном цикле?
Умный компилятор все равно не умнее человека
Последний раз редактировалось dekus Ср июл 03, 2019 08:15:06, всего редактировалось 2 раза.
Re: Кто то доставал до дна производительности STM32F1 ?
Вы можете выложить скриншот с осциллографа или лог. анализатора с результатом 12МГц на F103 72МГц с простым кодом - переключение туда сюда одной ноги в бесконечном цикле?
STM32 - это далеко не один устаревший F1, у меня F3 при 120MHz за 2 такта берет данные с порта и складывает в массив, т.е. наверняка можно получить меандр частотой 60MHz(при запуске из CCM), если без цикла, конечно. Опять же быстрый ногодрыг у мк на ядре M0+, там при обращении к портам идет работа напрямую с ними, минуя шину.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Кто то доставал до дна производительности STM32F1 ?
Вы можете выложить скриншот с осциллографа или лог. анализатора с результатом 12МГц на F103 72МГц с простым кодом - переключение туда сюда одной ноги в бесконечном цикле (что может быть проще)? Я не говорю что это не возможно, просто убедиться.
Железок сегодня под рукой нет, но нет оснований не доверять листингамКод: Выделить всё
for(PA_1 NOGA;;)
{
NOGA=1;
NOGA=0;
}
Код: Выделить всё
LDR.N R0,??DataTable4_2 ;; 0x40010810
MOVS R1,#+2
??main_0:
STR R1,[R0, #+0]
STR R1,[R0, #+4]
B.N ??main_0
Re: Кто то доставал до дна производительности STM32F1 ?
Действительно 12 МГц 

Код: Выделить всё
void setup() {
GPIOA_BASE->CRL = 0x33 ;//PA0 -выход
asm volatile (
"mov R0, %[port]" "\n\t"
"mov R1, 0x1" "\n\t"
"loop:" "\n\t"
"str R1, [R0,#+0]" "\n\t" // BSRR <- (1 << 0)
"str R1, [R0,#+4]" "\n\t" // BSR <- (1 << 0)
"B.N loop" "\n\t"
: : [port]"r" (&GPIOA_BASE->BSRR)
: "r0","r1"
);

Re: Кто то доставал до дна производительности STM32F1 ?
Не поленился. Кейл, оптимизация O3, speed. Да, 2 STR в цикле. Это все понятно. Но это был вопрос с подвохом. Но я же не просто так специально дописал про конвеер до этого.
И обращаем внимание на адрес перехода. Не повезло.
И получаем 10МГц
.
Тот же самый код, только добавляем перед циклом 2 NOP, чтобы выровнять переход до 0x08000330
Теперь обращаем внимание на адрес перехода.
И о чудо, уже 12МГц.
И это только один простой пример и только работы конвеера. Куча нюансов где никакой компилятор не справится, по сравнению с человеком.
Код: Выделить всё
#include <stm32f10x.h>
#define TEST_PIN 4
int main()
{
RCC->APB2ENR = RCC_APB2ENR_IOPAEN;
GPIOA->CRL = 0x03 << (TEST_PIN*4);
while(1) {
GPIOA->BRR = 1<<TEST_PIN;
GPIOA->BSRR = 1<<TEST_PIN;
}
}Код: Выделить всё
10: while(1) {
0x0800031E 4906 LDR r1,[pc,#24] ; @0x08000338
0x08000320 F44F3040 MOV r0,#0x30000
0x08000324 6008 STR r0,[r1,#0x00]
11: GPIOA->BRR = 1<<TEST_PIN;
0x08000326 4905 LDR r1,[pc,#20] ; @0x0800033C
0x08000328 2010 MOVS r0,#0x10
12: GPIOA->BSRR = 1<<TEST_PIN;
0x0800032A 1F0A SUBS r2,r1,#4
0x0800032C 6008 STR r0,[r1,#0x00]
0x0800032E 6010 STR r0,[r2,#0x00]
10: while(1) {
0x08000330 E7FC B 0x0800032CИ обращаем внимание на адрес перехода. Не повезло.
И получаем 10МГц
Тот же самый код, только добавляем перед циклом 2 NOP, чтобы выровнять переход до 0x08000330
Код: Выделить всё
11: GPIOA->BRR = 1<<TEST_PIN;
0x0800032A 2010 MOVS r0,#0x10
0x0800032C 4904 LDR r1,[pc,#16] ; @0x08000340
12: GPIOA->BSRR = 1<<TEST_PIN;
0x0800032E 1F0A SUBS r2,r1,#4
0x08000330 6008 STR r0,[r1,#0x00]
0x08000332 6010 STR r0,[r2,#0x00]
10: while(1) {
0x08000334 E7FC B 0x08000330Теперь обращаем внимание на адрес перехода.
И о чудо, уже 12МГц.
И это только один простой пример и только работы конвеера. Куча нюансов где никакой компилятор не справится, по сравнению с человеком.
Последний раз редактировалось dekus Ср июл 03, 2019 10:42:00, всего редактировалось 2 раза.
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Кто то доставал до дна производительности STM32F1 ?
И это только один простой пример и только работы конвеера. Куча нюансов где никакой компилятор не справится, по сравнению с человеком.
Это тоже неправда. Многократно замечал "выкрутасы" компилятора по изменению очерёдности исполнения команд и выравниванию nop-ами как раз с целью оптимизации доступа и работы конвейера. Компиляторы уже давно это всё понимают. Их разработчики годами занимаются повышением эффективности. Я вот не могу похвастаться, что завсегда сделаю лучше компилятора. Да, часто можно сделать лучше, но только потому что я знаю про код который пишу немного больше, чем говорю компилятору.Re: Кто то доставал до дна производительности STM32F1 ?
Вам конкретный пример привел про отсутствие 2Мгц из 12 со всеми листингами для повторения.
Последний раз редактировалось dekus Ср июл 03, 2019 10:35:37, всего редактировалось 1 раз.
Re: Кто то доставал до дна производительности STM32F1 ?
"Ага! — сказали суровые сибирские лесорубы. И ушли рубить лес топорами." 
"Вся военная пропаганда, все крики, ложь и ненависть исходят от людей, которые на эту войну не пойдут !" / Джордж Оруэлл /
"Война - это,когда за интересы других,гибнут совершенно безвинные люди." / Уинстон Черчилль /
"Война - это,когда за интересы других,гибнут совершенно безвинные люди." / Уинстон Черчилль /
- VladislavS
- Собутыльник Кота
- Сообщения: 2562
- Зарегистрирован: Вт май 01, 2018 19:44:47
Re: Кто то доставал до дна производительности STM32F1 ?
Вам конкретный пример привел про отсутствие 2Мгц из 12 со всеми листингами для повторения.
На эти "грабли" с одинаковым успехом можно наступить и на асме. И если вы о них знаете, то костылять их будете одинаково что на сишечке, что на асме.Кстати, 2 МГц у вас слизали, скорее всего, не конвейер, а синхронизация между разными шинами.