Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: На что бы перейти...
Форум разработчиков электроники ELECTRONIX.ru > Сайт и форум > В помощь начинающему > ARM, 32bit
Страницы: 1, 2
Arlleex
Итак, ради интереса сделал тест.
Использую аппаратный регистр CYCCNT для подсчета реального количества тактов, затрачиваемых на исполнение кода.
Предварительно процессор настраивается на 180МГц, количество тактов процессора, затрачиваемое на чтение 128 бит из Flash - 6 циклов (5WS).
Код теста:
Код
        AREA MY_PROGRAM, CODE, READONLY
        
        ENTRY
        
MyProg    PROC
        
        EXPORT Main
        
DWT_CYCCNT    EQU    0xE0001004
DWT_CONTROL    EQU    0xE0001000
SCB_DEMCR    EQU    0xE000EDFC

Main
        ldr r0, =SCB_DEMCR
        mov r1, #0x01000000
        str r1, [r0]
        
        ldr r0, =DWT_CONTROL
        ldr r1, [r0]
        mov r2, #0x1
        orr r1, r2
        str r1, [r0]
        
        ldr r0, =DWT_CYCCNT
        mov r1, #0x0

        b loop
        
        LTORG

loop
        str.w r1, [r0]
        
        mul.w r3, r4, r5
    ; ...
    ; ТЫСЯЧА ТАКИХ ИНСТРУКЦИЙ
    ; ...
        mul.w r3, r4, r5
        
        ldr.w r2, [r0]
        
        b.w loop
        
        ENDP

        END

Инструкции как раз подобраны наихудшие: 1 такт исполнение, 32-разрядные из набора Thumb-2.

1. Отключаю кэш инструкций и данных, отключаю prefetch-buffer выборки.
2. Запускаю код на исполнение под отладчиком без точек останова.
3. Пока код выполняется, ставлю точку останова на строку
Код
b.w loop

и смотрю содержимое регистра R2 (считанное значение в 180МГц тактах): 0x8CB = 2251.
4. Время математики: 1000 однотактных 32-разрядных команд, 1000/4=250 циклов обращения к Flash-памяти по 128 бит. С учетом того, что WS=5, 5*250=1250 тактов накладных расходов на ожидание доступа к данным. Прибавляем такты выполнения команд: 1250 + 1000 = 2250. Что на 1 такт меньше считанного показания с системного регистра. Двигаемся дальше.
5. Включаем prefetch-buffer выборки и повторяем шаги 2-3. Содержимое CYCCNT = 1501.
6. Выключаем prefetch-buffer, включаем кэш. Содержимое CYCCNT = 2250. По-моему логично, поскольку в кэше хранятся адреса команд начала последних использованных подпрограмм и веток кода, а не сам код (в документации вроде про это написано).
7. Включаем prefetch-buffer и кэш. Содержимое CYCCNT = 1501.

Как видно, при включенном буфере предвыборки будет потеря производительности, однако если в коде будут использованы не только 32-разрядные инструкции Thumb-2, а 16-разрядные, скорее всего количество тактов совпадет с количеством инструкций между метками замера. Замерил - CYCCNT = 1001.
Отключаю prefetch - CYCCNT = 1251. Интересно, почему сейчас 1251, ведь 8 однотактных инструкций перекрывают 5WS при доступе к Flash... Это пока под вопросом, я разберусь.

Собственно говоря, этих сведений мне достаточно, чтобы полагать, что большого толку от широкой шины на Tiva-C не будет. Она сделана точно для таких же целей, для каких и ART-ускоритель в STM32 - обеспечить нулевое состояние задержки при выполнении смешанного (32-разрядного и 16-разрядного) кодов Thumb и Thumb-2.
Если сравнивать производительность выполнения 32-битного кода Thumb-2 STM32, работающего на частоте, допустим, 150МГц, над производительностью Tiva-C, работающего на 120МГц при выполнении того же 32-битного кода, то плюс широкой шине - бесспорно предвыборка 8 команд лучше чем предвыборка 4. Однако на реальной практике код представляет из себя смесь 16- и 32-разрядных инструкций, поэтому подобный метод расчета производительности не годится, нужны данные CoreMark или Dhrystone.
jcxz
Цитата(Arlleex @ May 7 2018, 22:56) *
7. Включаем prefetch-buffer и кэш. Содержимое CYCCNT = 1501.

Только зачем было делать столько телодвижений если уже из теории и следует эта цифра (250_выборок * 6_тактов_на_выборку = 1500) ? laughing.gif
Ваши измерения как раз и совпадают с теорией - значит выполнены правильно. laughing.gif

Цитата(Arlleex @ May 7 2018, 22:56) *
Как видно, при включенном буфере предвыборки будет потеря производительности, однако если в коде будут использованы не только 32-разрядные инструкции Thumb-2, а 16-разрядные, скорее всего количество тактов совпадет с количеством инструкций между метками замера. Замерил - CYCCNT = 1001.

Опять-же - берём в руки калькулятор и считаем:
Чтобы при длительности выборки ==6 тактов не было простоев из-за недозагрузки prefetch, нужно чтобы команды из этой выборки выполнялись как минимум те же 6 тактов.
А это возможно при 2*4+4*2 - т.е. в prefetch-пакете 2 шт. 32-битных команд + 4 шт. 16-битных. Т.е. - соотношение 32-битных к 16-битным должно быть как минимум 1/2.
А теперь возьмите и посмотрите код любого тяжёлого фильтра или какого-то другого тяжёлого алгоритма обработки данных, либо просто - большую сложную и хорошо оптимизированную функцию (в которой используется много регистров). Увидите, что подавляющее большинство команд как раз - 32-битные.
Только в простых функциях, где используется мало регистров, только в них бОльшее большинство команд 16-битные.
Если же написать на си какие-то операции с матрицами к примеру, в которых задействовано много переменных и скомпилировать с максимальным уровнем оптимизации, то там вообще почти все команды (с выхода компилятора IAR) будут 32-битные (IAR, имхо, плохо размещает данные по регистрам, не учитывая длину получающихся команд).
Конечно в таком потоке команд не будут все команды только однотактные. Предположим что в prefetch-блоке одна инструкция типа LDR или STR. Но тогда всё равно получается:
по размеру 3*4+2*2 = 16байт; по тактам 2+1+1+1+1 = 6тактов - только если в prefetch-блоке 3 команды 32-битные (одна из них - LDR/STR) + 2команды 16-битные - это граничный случай когда всё будет ещё успевать работать без остановок выполнения. А в реальном коде тяжёлых вычислений процентная доля 32-битных команд будет (имхо) всё-таки повыше.
А теперь ещё осталось вспомнить, что разговор идёт о Cortex-M4F. И вычисления с большой вероятностью будут не целочисленные, а с плавающей точкой. А где Вы видели 16-битные инструкции с float? А теперь ещё вспомним что регистров FPU гораздо больше чем целочисленных, что позволяет строить код с малым числом обращений с памяти, т.е. - на однотактных инструкциях в основном. Вот здесь то и получим существенную разницу.

Цитата(Arlleex @ May 7 2018, 22:56) *
Однако на реальной практике код представляет из себя смесь 16- и 32-разрядных инструкций

Да, Вы как-нить посмотрите на реальный код тяжёлых вычислений. Не тот код, который в обычных функциях со множеством ветвлений и малым количеством регистровых переменных, а на действительно вычислительный код (тем более с float). Ибо для обычных задач этих 120МГц и так - за глаза, а производительность я оценивал только для вычислительных задач.
Да, и ещё раз повторю: когда мы выбирали Tiva, не было STM32 на 180МГц, а были только максимум на 168МГц. А это разница по частоте всего на 40%. И часть из этих 40% покроется за счёт более широкой шины Tiva, так что останется выигрыш может процентов 20% (а в каких-то отдельных случаях может быть ещё и проигрыш, например - ISR со множеством переменных, редко выполняющийся (вытесненный из кеша) на Tiva может выполниться даже быстрее). А разница в 20% уже была для нас несущественна, на фоне выигрыша по ОЗУ и лучшей периферии.

Да и вообще: более слабая периферия приводит к дополнительным накладным вычислительным расходам (в случае STM32), что ещё сокращает разницу в скорости ядер. Уж не говоря о том, что многое из того, что мы сделали на Tiva, было невозможно сделать на STM32 (даже нонешних 180МГц). Это множество последовательных интерфейсов с полноценным FIFO и DMA, а также dual-SPI который позволили увеличить скорость работы с SPI-FLASH. А на STM32 мы бы ещё скорей всего не пролезли по скорости доступа к SPI-FLASH.
COMA
Я для себя определил два варианта для перехода:
серия i.MX RT либо серия STM32H7
Arlleex
Цитата
Только зачем было делать столько телодвижений если уже из теории и следует эта цифра (250_выборок * 6_тактов_на_выборку = 1500) ?
Ваши измерения как раз и совпадают с теорией - значит выполнены правильно.

Теория, подтвержденная практикой - залог хорошего понимания природы вещей biggrin.gif
Просто очень любопытно стало, и протестил, пока время есть.
А вот насчет 1250 тактов при всех инструкциях в 16 бит не могу понять, как так получается. Перерыл кучу документации, есть даже вот такая картинка:


Но как бы я ни строил график растактовки конвейера, все равно не получается там 1250. Даже при учете, что процессор считывает сразу 2 инструкции, но декодинг все-таки последовательный, все равно не совпадают расчеты. Откуда там два лишних такта берется на выборку каждых 128 бит из Flash - не пойму.
Да и рисунок выше какой-то не шибко понятный, слова "инструкции, после того как извлечены, могут несколько тактов тупить прежде чем процессор их декодировать начнет" - с чего бы это, казалось бы? "До двух инструкций может быть выбрано за одно чтение" - а вот этот механизм вообще интересен. Как процессор понимает, что перед ним 32-битная или 16-битная команда? По идее он всегда читает 32 бита и смотрит на поле кода операции, ну да ладно, с этим понятно. Ну а если он читает такой порядок:
1. instr 1 (16 bit);
2. instr 2 (16 bit);
3. instr 3 (16 bit);
4. instr 4 (32 bit);
5. instr 5 (32 bit);
6. instr 6 (16 bit).

Вот забирает он первые 32 бита и понимает, что там первая инструкция 16-битная, и потом декодирует вторую инструкцию - понимает, что она 16-битная тоже.
Забирает он следующие 32 бита. Декодирует первую команду, смотрит на код операции второй команды - а она 32-битная оказывается. Надо дочитать еще 16 бит с шины. Считывает 32 вместо 16. Декодирует уже полное слово. В буфере у него остались 16 бит 5-й инструкции. Она тоже 32-битная - он опять делает такие махинации. Потом из буфера забирает шестую инструкцию и декодирует, она 16-битная, все в порядке.
Однако вроде как утверждается, что даже рядом стоящие команды смешанной разрядности не влияют на количество тактов их выполнения. Как оно тогда устроено?

P.S. Отвечаю сам себе на второй вопрос. Логика придумалась в голове + наблюдения за PC в отладчике:
1. Процессор всегда считывает целое слово в регистр команды по адресу, который хранится в PC.
2. Процессор декодирует старшее полуслово (см. ARMv7M Architecture Reference Manual) и смотрит, 16- или 32-битная эта команда:
- если 16-битная, процессор ее выполняет и увеличивает PC на 2;
- если 32-битная, процессор обрабатывает ее как 32-битную и увеличивает PC на 4.
После этого логика переходит на п.1 и так по кругу.

На первый вопрос (откуда 1250 тактов) ответа пока что не нашел.
Arlleex
Итак, выложу сюда две растактовки из экспериментов.
1. WS = 5, Prefetch-OFF, 32-bit Thumb-2 command.

Здесь A - Addressing cycle, F - Fetch, D - Decode, E - Execution.

Для выполнения 4 полноценных 32-битных команд необходимо 9 тактов.
1000/4 = 250 обращений к памяти, соответственно, 9*250 = 2250 тактов - это время выполнения 1000 32-битных команд.

2. WS = 5, Prefetch-ON, 32-bit Thumb-2 command.

Здесь A - Addressing cycle, F - Fetch, D - Decode, E - Execution.

Для выполнения 4 полноценных 32-битных команд необходимо 6 тактов, поскольку при первом Fetch адресуются следующие 128 бит Flash-памяти устройством Prefatch-ера, и в итоге мы получаем перехлест в 2 такта в сторону понижения производительности.
1000/4 = 250 обращений к памяти, соответственно, 6*250 = 1500 тактов - это время выполнения 1000 32-битных команд.

3. WS = 5, Prefetch-OFF, 16-bit Thumb-2 command.
Пока что пусто, т.к. не понимаю как ведет себя процессор и подсистема pipeline с 16-битными инструкциями.
4. WS = 5, Prefetch-ON, 16-bit Thumb-2 command.
Очевидно, станет понятно, если прояснится п. 3.
jcxz
Цитата(Arlleex @ May 9 2018, 18:26) *
Итак, выложу сюда две растактовки из экспериментов.
1. WS = 5, Prefetch-OFF, 32-bit Thumb-2 command.

А какой практический смысл в отключении предвыборки?
Arlleex
Никакого абсолютно. У меня в проектах он всегда включен.
Поэтому чисто спортивный интерес к поведению процессорного устройства.

Пишут в документации, что при напряжении питания менее 2.1В prefetch необходимо отключать. При этом процессор может тактироваться до 120МГц. Поэтому в некоторых случаях и будет необходимо знать растактовку CPU на 16-битных командах.

Вот еще пример, когда предвыборку отключать желательно. Я понимаю, что это косяк только STM32, скорее всего, но чем не причина...
Arlleex
Подниму свою же тему.
1. Программировал платку с XMC4800. И хотел найти ревизию MCU - беглым взглядом кроме как в обозначении самой микросхемы не нашел в Datasheet. На сайте у них все XMC4800 имеют последние две буквы AA. Глянул на МК помладше - там есть позиции AA, AB, AC... Я так понял это и есть ревизия?
2. Где узнать, какая ревизия ядра Cortex-M4F там стоит? Тоже довольно немаловажная информация, по которой лучше сразу скачать документацию нужной ревизии.

P.S. Отвечаю сам себе же.
Так же как и во всех других Cortex-Mx - в регистре IDCODE ревизия MCU, в CPUID - версия CPU.
jcxz
Цитата(Arlleex @ Jul 6 2018, 08:17) *
1. Программировал платку с XMC4800. И хотел найти ревизию MCU - беглым взглядом кроме как в обозначении самой микросхемы не нашел в Datasheet. На сайте у них все XMC4800 имеют последние две буквы AA. Глянул на МК помладше - там есть позиции AA, AB, AC... Я так понял это и есть ревизия?

Да. Для XMC4500 и XMC4700 - так и есть. Пишется в 3-й строчке на корпусе чипа.

PS: Ну и как впечатления от чипа? cool.gif
Arlleex
Цитата(jcxz @ Jul 6 2018, 12:05) *
PS: Ну и как впечатления от чипа? cool.gif

Ага, спасибо.
А впечатления, ммм, ну как бы кратко так сказать - это не STM32. Регистров действительно дофига и все расплывается в голове. Но это, думаю, временно laughing.gif
jcxz
Цитата(Arlleex @ Jul 6 2018, 11:25) *
А впечатления, ммм, ну как бы кратко так сказать - это не STM32. Регистров действительно дофига и все расплывается в голове. Но это, думаю, временно laughing.gif

Да, через полгодика-годик уже в целом многое запомнится и будет казаться "как это я раньше без всего этого великолепия обходился?" biggrin.gif
Arlleex
Цитата(jcxz @ Jul 6 2018, 12:30) *
Да, через полгодика-годик уже в целом многое запомнится и будет казаться "как это я раньше без всего этого великолепия обходился?" biggrin.gif

Кстати попутно вопрос позвольте задать.
Вы используете XMCLib или только хардкорный XMC4xxx.h и погнали кодить с референсом перед глазами? rolleyes.gif Я тут просто бегло глянул эту библиотеку - не совсем прикинул что к чему.
jcxz
Цитата(Arlleex @ Jul 6 2018, 11:35) *
Вы используете XMCLib или только хардкорный XMC4xxx.h и погнали кодить с референсом перед глазами? rolleyes.gif Я тут просто бегло глянул эту библиотеку - не совсем прикинул что к чему.

3-й вариант. У меня все структуры-определения IO-периферии - свои.
Arlleex
Боюсь мне начальство не выделит времени на такие процедуры maniac.gif
jcxz
Цитата(Arlleex @ Jul 6 2018, 12:07) *
Боюсь мне начальство не выделит времени на такие процедуры maniac.gif

Начальство стоит над Вами с секундомером и мониторит все телодвижения??? maniac.gif
Бежать надо с такой работы! sm.gif
А вообще такая структура делается на лету по ходу изучения соответствующего периферийного блока, не занимая времени. Надеюсь - на изучение периферии время Вам выделяют? wink.gif
Arlleex
Цитата(jcxz @ Jul 6 2018, 13:50) *
Начальство стоит над Вами с секундомером и мониторит все телодвижения??? maniac.gif
Бежать надо с такой работы! sm.gif
А вообще такая структура делается на лету по ходу изучения соответствующего периферийного блока, не занимая времени. Надеюсь - на изучение периферии время Вам выделяют? wink.gif

Ну как сказать с секундомером... Спешка всегда и всюду laughing.gif Отсюда и бывают не до конца выловленные баги (по вечерам после работы вычищаю, если есть). Всегда хочется посидеть, лучше продумать алгоритм, поковырять досконально МК, узнать плюшки и фишки, но нужен только результат и никого не волнует, насколько крутой программный автомат я сделал.
Бежать, да вот куда? Везде такая суета, ИМХО wacko.gif
А описывать структуры - я на самом деле когда-то делал, но для AVR/PIC/ARM7. Времени у меня было побольше тогда sm.gif
Ну это все так, лирика. Больше склоняюсь к варианту, что файла описания регистров IO-периферии мне хватает. Но другое дело, если они по-уродски будут структурированы в XMC или названия не понравятся - буду переписывать. Благо с XMC я занимаюсь чисто для себя, для расширения кругозора в области существующих МК.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.