Лучше не использовать типы char в stm32?

Кто любит RISC в жизни, заходим, не стесняемся.
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Лучше не использовать типы char в stm32?

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

Принудительная вакцинация вторым умножением, максимальный изврат: 40 байт на функцию, 7 тактов на цикл.
https://godbolt.org/z/c1MYarv43
Без оптимизации -Os - второе умножение не появляется.

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

__attribute__ ((optimize("-Os"))) char* u32_char (uint32_t value, char* tail_txt) /// 40 байт
{
    *tail_txt = 0;
    uint32_t tmp, exx;
    do{
        tmp = ((uint64_t) value * 429496730UL >> 32);
        exx = value - tmp * 10;
        exx += '0';
        *(--tail_txt) = exx;
        value = tmp;
    }while (value != 0);
    return tail_txt;
};
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4110095#p4110095"]Разве L151 это М0? Да нет, сейчас перепроверил: все stm'ки, на которых я могу протестировать - F100, F103, L151 - относятся к М3.[/uquote]
Изначально Eddy_Em просил потестить на F0(M0), у тебя таких нет, потому появился тест [только] для L151(M3), я же написал, что на M0 функция с делением и взятием остатка будет медленно работать и на требование предоставить доказательства потестил на G0(M0+). Нигде не звучало, что L151 - это M0, сказано было, что L151 - это тоже STM32. Все трое обсуждали STM32, двое конкретно говорили про ядро M0 и все было хорошо пока не оказалось, что тесты оказывается нужны для AVR. Не буду говорить за других, но лично я не настолько прозорливый :)

COKPOWEHEU писал(а):А в 2.7 раза это сколько в тактах? Может, там как и в AVR десять тысяч тактов и оба варианта годятся только отладочную информацию раз в вечность передавать. То есть не "данные для любознательных" закопаны под спойлер, а просто какие-то сырые данные без пояснений.
Спор был про скорость, а не нужность, числа на печать выводили и на 8051 исполняющих инструкции за 12 тактов, что уж говорить про 32-х битные мк c 32-х битным умножением разгоняющиеся до 140MHz. И вообще информация про 2.7 раза уже устарела, новый рекорд для M0 - 6.2 раза вот с такой функцией деления:

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

static int remu10(uint32_t n)
{
	const static int8_t table[16] = { 0, 1, 2, 2, 3, 3, 4, 5, 5, 6, 7, 7, 8, 8, 9, 0 };
	n = (0x19999999 * n + (n >> 1) + (n >> 3)) >> 28;
	return table[n];
}

static uint32_t divu10(uint32_t n)
{
	return ((n - remu10(n)) >> 1) * 0xCCCCCCCD;
}
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Лучше не использовать типы char в stm32?

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

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4109799#p4109799"]А вот на stm32L151 не удержался и проверил.[/uquote]
Проверяй ещё раз, твоё умножение требует сдвига на 35, ну или на 3 в старшем регистре. Хотя можно умножать на число не требующее дополнительной обработки результата.
И я его нашёл 429496730UL.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

AVI-crak, gcc не зря когда заменяет деление на 10 сдвигает на 35 бит, простейший тест на пк обнаруживает тьму ошибок:

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

uint32_t divu10(uint32_t val) { return (uint64_t)val * 429496730UL >> 32; }

for(uint64_t i = 0; i <= 0xFFFF'FFFF; i++)
{
   if(divu10(i) != i / 10)
   {
        printf("Error: %u, %u, %u\n", i, divu10(i), i / 10);
        return 0;
   }
}
printf("OK!\n");
Первая из них такая: Error: 1073741829, 107374183, 107374182
Последний раз редактировалось Reflector Сб окт 23, 2021 23:56:38, всего редактировалось 1 раз.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Лучше не использовать типы char в stm32?

Сообщение Eddy_Em »

А если расфигачить STM32 на uint128_t? ☺
Да не, чего ходить вокруг да около? Давайте операции через uint256_t делать!!!
Вай, да: на современных процах с AVX2 и uint512_t реализовать не проблема. Давайте ими насиловать 32-битные МК!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110145#p4110145"]Вай, да: на современных процах с AVX2 и uint512_t реализовать не проблема. Давайте ими насиловать 32-битные МК![/uquote]
На новых Cortex-M55 есть MVE - это как раз векторная фигня типа SSE, восемь 128-ми битных регистров :)
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Лучше не использовать типы char в stm32?

Сообщение Eddy_Em »

Reflector, подозреваю, что уж такие навороченные, но таки "M" никому нафиг не нужны будут! Уж дешевле тогда "A" взять, поставить нормальный линукс, да работать! А в качестве рилтайма по-старинке использовать те же самые M0 или M3.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110173#p4110173"]подозреваю, что уж такие навороченные, но таки "M" никому нафиг не нужны будут![/uquote]
У M55 просто этот MVE есть, ну и ядро новое Armv8-M с небольшим количеством новых инструкций, а в остальном M7 так самым производительным и остался и до подорожания китайцы 480MHz H750 по $4-5 продавали и его очень даже брали, я, например :)
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: Лучше не использовать типы char в stm32?

Сообщение COKPOWEHEU »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4110136#p4110136"]Проверяй ещё раз, твоё умножение требует сдвига на 35, ну или на 3 в старшем регистре[/uquote]
Несколько раз перечитал сообщение, но так и не понял что вы хотите. Что именно проверять, о каком умножении речь?
Изначально Eddy_Em просил потестить на F0(M0), у тебя таких нет, потому появился тест [только] для L151(M3)
Нет, тест появился не из-за EddyEm, тест появился, поскольку я подобными функциями пользуюсь, и было интересно узнать насколько они лучше или хуже альтернатив.
Спор был про скорость
Так для вас это всего лишь спор? Соревнование на самый быстрый код? Меня-то вопрос интересует в практическом смысле: стоит ли использовать и для каких задач.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="COKPOWEHEU",url="/forum/viewtopic.php?p=4110316#p4110316"]Нет, тест появился не из-за EddyEm, тест появился, поскольку я подобными функциями пользуюсь, и было интересно узнать насколько они лучше или хуже альтернатив.[/uquote]
Появились тесты из-за Eddy_Em, не из-за Eddy_Em или частично из него - это в принципе недоказуемо и уже только поэтому не существенно. Я описывал последовательность событий когда шло обсуждения тестов для STM32 и подключившись к обсуждению я говорил о них же, делая акцент на том, что на M0, которые интересуют Eddy_Em, функция с делением и взятием остатка будет работать медленно, что в последствии и было убедительно доказано. Ни о каких AVR в той череде постов не говорилось и, соответственно, ни к каким постоянным попыткам извернуться и съехать с AVR на M0 я не причастен :) И да, если бы мне написали, что моя функция работает в 2.7 раза медленнее, то я бы определенно разобрался в чем там дело, а когда если спойлер и открыл, то сразу его и закрыл, то можно говорить что угодно, но степень заинтересованности налицо :)
COKPOWEHEU писал(а):Так для вас это всего лишь спор? Соревнование на самый быстрый код? Меня-то вопрос интересует в практическом смысле: стоит ли использовать и для каких задач.
Это был спор по факту. Можно сказать и соревнование на самый быстрый или лучший код тоже. У многих есть подобные функции, после таких обсуждений кто-то пересмотрит подходы, код ускорит, уменьшит, устранит возможные ошибки и продолжит его использовать на практике.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Лучше не использовать типы char в stm32?

Сообщение Eddy_Em »

Ну вот я глянул, что производительность деления uint32_t и умножений/сдвигов uint64_t не очень-то сильно отличается.
Да, если нужно будет многократно делить на константы, можно попробовать оптимизировать через умножения и сдвиги. А в отдельных случаях, наверное, можно и не волноваться.
Еще есть деления вроде как на константу, но она берется в рантайме, а не вычисляется компилятором. Скажем, вычисление температуры:

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

int32_t getMCUtemp(){ // return MCU temperature (degrees of celsius * 10)
    int32_t ADval = getADCval(2);
    int32_t temperature = (int32_t) *TEMP30_CAL_ADDR - ADval;
    temperature *= (int32_t)(1100 - 300);
    temperature /= (int32_t)(*TEMP30_CAL_ADDR - *TEMP110_CAL_ADDR);
    temperature += 300;
    return(temperature);
}
А в вычислении Vdd наоборот: константа делится на изменяющееся число:

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

uint32_t getVdd(){ // return Vdd * 100 (V)
    uint32_t vdd = ((uint32_t) *VREFINT_CAL_ADDR) * (uint32_t)330; // 3.3V
    vdd /= getADCval(3);
    return vdd;
}
А в случае, если я захочу перевести ADU в Вольты, придется минимум два деления использовать.
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
Аватара пользователя
AVI-crak
Прорезались зубы
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17
Контактная информация:

Re: Лучше не использовать типы char в stm32?

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

[uquote="Reflector",url="/forum/viewtopic.php?p=4110141#p4110141"]AVI-crak, gcc не зря когда заменяет деление на 10 сдвигает на 35 бит, простейший тест на пк обнаруживает тьму ошибок:[/uquote]
Ок, животина оказалась бракованной, пришлось пристрелить. Хотя выглядело очень красиво.
Вывод из всего этого безобразия - нужно писать максимально просто.
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Лучше не использовать типы char в stm32?

Сообщение jcxz »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110439#p4110439"]Ну вот я глянул, что производительность деления uint32_t и умножений/сдвигов uint64_t не очень-то сильно отличается.[/uquote]
Ну если в 12 раз - это не "очень-то", то наверное. Cortex-M4:
Изображение
Так же как тут некоторые и между ARM и AVR разницы не видят, также для кого-то "в 12 раз" - это "не сильно отличаются".
Последний раз редактировалось jcxz Вс окт 24, 2021 13:40:45, всего редактировалось 1 раз.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110439#p4110439"]Ну вот я глянул, что производительность деления uint32_t и умножений/сдвигов uint64_t не очень-то сильно отличается.[/uquote]
В целом да, но если взять мою последнюю функцию деления на 10, которая табличная и потому можно обойтись без 64 бит, то она на M0 отрабатывает всегда за 29 тактов, в то время как обычное деление медленнее и при небольших числах, а если делить максимальное 32-х битное значение, то уже будет 225 тактов...

Добавлено after 9 minutes 16 seconds:
[uquote="jcxz",url="/forum/viewtopic.php?p=4110467#p4110467"]Ну если в 12 раз - это не "очень-то", то наверное. Cortex-M4:[/uquote]
Для M4 и напрягаться особо не нужно, компилятор обычно сам все делает, а M0 не только при делении на константы косячит, помню всякие аналоги CLZ там тоже были в разы медленнее самописных.
Аватара пользователя
Eddy_Em
Собутыльник Кота
Сообщения: 2516
Зарегистрирован: Пт июл 12, 2019 22:52:01
Контактная информация:

Re: Лучше не использовать типы char в stm32?

Сообщение Eddy_Em »

[uquote="jcxz",url="/forum/viewtopic.php?p=4110467#p4110467"]Ну если в 12 раз - это не "очень-то"[/uquote]
Я верю своим глазам, а не рекламациям! А глаза мне показали в тесте Reflector разницу всего в полтора раза между делением uint32_t и умножением/сдвигами uint64_t.
И при чем здесь M4, когда мы обсуждаем M0, у которого нет аппаратного деления?
Что до М4, то приведенная таблица наглядно показывает: нет смысла на таком крутом ядре городить всякие умножения/сдвиги, когда реализация деления в среднем займет всего лишь 7 тактов! А на перемещение данных между регистрами, умножения и сдвиги уйдет не меньше!
Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда.
Я на гитхабе, в ЖЖ
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Лучше не использовать типы char в stm32?

Сообщение jcxz »

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110485#p4110485"]Я верю своим глазам, а не рекламациям! А глаза мне показали в тесте Reflector разницу всего в полтора раза между делением uint32_t и умножением/сдвигами uint64_t.[/uquote]Тесты на реальном железе подтверждают данные таблицы. Достаточно запустить отладчик и посмотреть. IAR, CM4: Изображение
Смотрим на строчку "CCSTEP".

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110485#p4110485"]И при чем здесь M4, когда мы обсуждаем M0, у которого нет аппаратного деления?[/uquote]Если аппаратного деления нет, то разница будет ещё больше, кэп. Уже видимо - во много десятков раз. Или ещё больше.

[uquote="Eddy_Em",url="/forum/viewtopic.php?p=4110485#p4110485"]нет смысла на таком крутом ядре городить всякие умножения/сдвиги, когда реализация деления в среднем займет всего лишь 7 тактов![/uquote]Всегда имеет смысл писать ПО, работающее быстрее. Даже если разница всего в несколько %. А когда разница в 7 раз(!), то тут даже вопроса не возникает - это должно быть очевидно.

PS: Да, и в реальных программах, работающих в реал-тайм, смотрят не на "среднее по больнице", а на худший случай (максимальное время выполнения). Т.е. - не 7 тактов, а 12 тактов.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

[uquote="jcxz",url="/forum/viewtopic.php?p=4110500#p4110500"]Если аппаратного деления нет, то разница будет ещё больше, кэп. Уже видимо - во много десятков раз. Или ещё больше.[/uquote]
На M0 не только деления нет, но и длинного умножения, потому для деления на 10 через умножение получаем порядка 60-ти инструкций и все они будут выполняться даже если нужно 10 на 10 поделить.
Аватара пользователя
COKPOWEHEU
Говорящий с текстолитом
Сообщения: 1525
Зарегистрирован: Чт июн 10, 2010 20:11:19

Re: Лучше не использовать типы char в stm32?

Сообщение COKPOWEHEU »

[uquote="Reflector",url="/forum/viewtopic.php?p=4110372#p4110372"]И да, если бы мне написали, что моя функция работает в 2.7 раза медленнее, то[/uquote]
...то, учитывая уже имеющиеся данные, логично предположить либо ошибку эксперимента, либо особенность компилятора, либо что-то еще. Потому что на двух более выраженных крайностях особой разницы нет. Вы этого не сделали.
а когда если спойлер и открыл, то сразу его и закрыл, то можно говорить что угодно, но степень заинтересованности налицо :)
Да понял я , что вам результат не интересен, раз вы ни экспериментальных данных толком не привели, ни выводов, ни ввопросе разобраться не попытались - откуда такая разница. Ну не хотите и ладно, свой вывод я озвучил: разница в десяток процентов на чловеко-читаемом выводе несущественна.
Reflector
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Re: Лучше не использовать типы char в stm32?

Сообщение Reflector »

Так, вытащил из закромов функцию длинного умножения для M0 на замену той жести что генерит gcc и divu10() стала отрабатывать за 27 тактов:
Спойлер

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

uint64_t umul_32_64(uint32_t u, uint32_t v)	// u32 * u32 -> u64
{
	uint32_t a, b, c;

	__asm volatile("uxth %[a], %[u]\n"
				   "lsrs %[u], %[u], #16\n"
				   "lsrs %[b], %[v], #16\n"
				   "uxth %[v], %[v]\n"
				   "movs %[c], %[v]\n"
				   "muls %[v], %[a]\n"
				   "muls %[c], %[u]\n"
				   "muls %[u], %[b]\n"
				   "muls %[b], %[a]\n"
				   "lsls %[a], %[c], #16\n"
				   "lsrs %[c], %[c], #16\n"
				   "adds %[v], %[a]\n"
				   "adcs %[u], %[c]\n"
				   "lsls %[a], %[b], #16\n"
				   "lsrs %[b], %[b], #16\n"
				   "adds %[v], %[a]\n"
				   "adcs %[u], %[b]\n"
				   : [u] "+l" (u), [v] "+l" (v), [a] "=l" (a), [b] "=l" (b), [c] "=l" (c) :: "cc"
	);

	return uint64_t(u) << 32 | v;
}

uint32_t divu10(uint32_t val) { return umul_32_64(val, ((1ULL << 35) + 5) / 10) >> 35; }
jcxz
Мудрый кот
Сообщения: 1717
Зарегистрирован: Вт авг 15, 2017 10:51:13

Re: Лучше не использовать типы char в stm32?

Сообщение jcxz »

[uquote="Reflector",url="/forum/viewtopic.php?p=4110510#p4110510"]На M0 не только деления нет, но и длинного умножения, потому для деления на 10 через умножение получаем порядка 60-ти инструкций и все они будут выполняться даже если нужно 10 на 10 поделить.[/uquote]Уверены? Что-то многовато как-то...
Проверил (в наличии у меня M0 нет), поэтому под симулятором. Написал такую функцию:

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

               PUBLIC   umull
umull:         MOV      R12, R4
               LSRS     R2, R0, #16
               LSRS     R3, R1, #16
               UXTH     R0, R0
               UXTH     R1, R1
               MOV      R4, R2
               MULS     R4, R4, R3
               MULS     R2, R2, R1
               MULS     R3, R3, R0
               MULS     R0, R0, R1
               LSRS     R0, R0, #16
               MOVS     R1, #0
               ADDS     R2, R2, R3
               MOV      R3, R1
               ADCS     R3, R3, R1
               ADDS     R2, R2, R0
               ADCS     R3, R3, R1
               LSRS     R2, R2, #16
               ADDS     R4, R4, R2
               LSLS     R3, R3, #16
               ADDS     R0, R3, R4
               MOV      R4, R12
               BX       LR
Если где-то не напутал, вроде считает правильно.
Вызываем:

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

  umull(0x1234567u, 0x23456789u);
Всё вместе (вместе с вызовом BL и возвратом) по данным симулятора выполняется за 24 такта. Это далеко не 60....
Ответить

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