Pull to refresh

О переходе на QingKeV4. Тесты CoreMark в разных областях флэша для СH32V2/V3 и что же такое non-zero wait

Level of difficultyMedium
Reading time8 min
Views464

Про внешний SPI флэш внутри чипов WCH уже везде написали, ситуацию с реальным объемом я описывал https://habr.com/ru/articles/859 054/. Но какая там скорость и как она влияет на производительность системы? WCH на эту тему официально ничего не писал, но на китайском саппорте информация есть. Общий смысл всех ответов саппорта: для кода используйте кэшируемый флэш zero‑wait, все остальное это для пользовательских данных, но если вы уж прям не влезаете в кэш, то можно использовать область non zero-wait для кода. Крайне содержательно. Чтобы окончательно раскрыть тему, я вооружился тестами производительности CoreMark и в целом получил ответы на 2 своих главных вопроса: какая частота доступа к физическому SPI флэшу и как стратегия его применения в реальных проектах. Сейчас расскажу.

Итак, исходные данные. Прошивка запускалась в zero-wait. Код бенчмарка, исполняемый между функциями замера времени - мапился в верхние адреса за пределы кэшируемого флэша. Компилятор GCC8.2.0, оптимизация -O3, все остальное по дефолту из IDE. Время считалось на SysTick. Тесты проводились для стандартных частоты 48,56,72,96,120 и 144Mhz. На каждой частоте бенчмарк прогонялся 3 раза: в zero-wait, non zero-wait и non zero-wait с включенным режимом ускорения чтения из флэша (Flash Enhanced Read Mode). Кол-во итераций во всех тестах 4000. Это важно, поскольку на разном кол-ве итераций результат бенчмарка немного отличается.

Для CH32V203C8T6 rev0 получилось:

zero-wait флэш

non-zero wait флэш

non zero-wait флэш (FERM)

Частота

Цикл CoreMark в сек

Цикл CoreMark на Mhz

Цикл CoreMark в сек

Цикл CoreMark на Mhz

Цикл CoreMark в сек

Цикл CoreMark на Mhz

144Mhz

375,768584

2,60950405

34,664655

0,24072677

37,351394

0,25938468

120Mhz

313,140486

2,60950405

29,190354

0,24325295

31,126162

0,25938468

96Mhz

250,512389

2,60950405

23,172174

0,24137681

24,90093

0,25938468

72Mhz

187,88429

2,60950402

17,332327

0,24072676

18,675697

0,25938468

56Mhz

146,132227

2,60950405

13,4806991

0,24072677

14,525542

0,25938467

48Mhz

125,256195

2,60950406

11,554885

0,24072677

12,4504645

0,25938467

Репорт для 144Mhz zero-wait

SystemClk:144 000 000 
ChipID:20 310 500 
2K performance run parameters for coremark.
CoreMark Size: 666 
Total ticks: 191 607 290 
Total time (secs): 10.644 849 
Iterations/Sec: 375.768 584 
Iterations: 4000 
Compiler version: GCC8.2.0 
Compiler flags: o3 
Memory location: STACK
seedcrc: 0xe9f5 
[0]crclist: 0xe714 
[0]crcmatrix: 0×1fd7 
[0]crcstate: 0×8e3a
[0]crcfinal: 0×65c5 
Correct operation validated. See README.md for run and reporting rules.
CoreMark 1.0: 375.768 584 / GCC8.2.0 o3 / STACK

Репорт для 144Mhz non zero-wait Flash Enhanced Read Mode

SystemClk:144000000
ChipID:20310500
2K performance run parameters for coremark.
CoreMark Size : 666
Total ticks : 1927638880
Total time (secs): 107.091049
Iterations/Sec : 37.351394
Iterations : 4000
Compiler version : GCC8.2.0
Compiler flags : o3
Memory location : STACK
seedcrc : 0xe9f5
[0]crclist : 0xe714
[0]crcmatrix : 0x1fd7
[0]crcstate : 0x8e3a
[0]crcfinal : 0x65c5
Correct operation validated. See
README.md for run and reporting rules.
CoreMark 1.0 : 37.351394 / GCC8.2.0 o3 / STACK

Остальные репорты публиковать смысла не вижу.

Теперь V303 и V307. Результаты идентичны.

zero wait флэш

non zero wait флэш

non zero wait флэш (FERM)

Частота

Цикл в сек

Цикл на Mhz

Цикл в сек

Цикл на Mhz

Цикл в сек

Цикл на Mhz

144

366,415588

2,54455269

60,813471

0,42231577

68,385467

0,47489907

120

305,346324

2,5445527

50,677894

0,42231578

56,987889

0,47489907

96

244,277059

2,54455269

40,542315

0,42231578

45,590311

0,47489907

72

183,207794

2,54455269

30,406736

0,42231577

34,192733

0,47489906

56

142,494953

2,54455273

23,649683

0,42231576

26,594348

0,47489907

48

122,13853

2,54455270

20,271157

0,42231577

22,795156

0,47489908

Репорт для СH32V303/V307 144Mhz zero-wait

SystemClk:144000000
ChipID:30330514
2K performance run parameters for coremark.
CoreMark Size : 666
Total ticks : 196498191
Total time (secs): 10.916566
Iterations/Sec : 366.415587
Iterations : 4000
Compiler version : GCC8.2.0
Compiler flags : o3
Memory location : STACK
seedcrc : 0xe9f5
[0]crclist : 0xe714
[0]crcmatrix : 0x1fd7
[0]crcstate : 0x8e3a
[0]crcfinal : 0x65c5
Correct operation validated. See
README.md for run and reporting rules.
CoreMark 1.0 : 366.415587 / GCC8.2.0 o3 / STACK

Репорт для СH32V303/V307 non zero-wait Flash Enhanced Read Mode

SystemClk:144000000
ChipID:30330514
2K performance run parameters for coremark.
CoreMark Size : 666
Total ticks : 1052855275
Total time (secs): 58.491960
Iterations/Sec : 68.385467
Iterations : 4000
Compiler version : GCC8.2.0
Compiler flags : o3
Memory location : STACK
seedcrc : 0xe9f5
[0]crclist : 0xe714
[0]crcmatrix : 0x1fd7
[0]crcstate : 0x8e3a
[0]crcfinal : 0x65c5
Correct operation validated. See
README.md for run and reporting rules.
CoreMark 1.0 : 68.385467 / GCC8.2.0 o3 / STACK

Валидация результата

Для начала соотнесем результаты с тем, что известно на эту тему по CH32V307 в zero-wait 144Mhz.

https://gitee.com/elecb/ch32v307_core-mark - CoreMark 1.0: 380.662352 / GCC8.2.0 -o3 / СТЕК

https://zhuanlan.zhihu.com/p/496255489 - CoreMark 1.0: 379.982521 / GCC8.2.0 -o3 / STACK

https://bbs.21ic.com/icview-3164492-1-1.html CoreMark 1.0: 382.464221 / GCC8.2.0 -ofast -o3 / STACK

https://www.eembc.org/viewer/?benchmark_seq=13505. CoreMark 1.0: 459.16 / GCC12.1.0 --O3 -funroll-all-loops -finline-limit=600 -ftree-dominator-opts -fno-if-conversion2 -fselective-scheduling -fno-code-hoisting

Последние мое любимое, цифра даже выше чем у CortexM4F 160Mhz. Но это хардкорные ключи оптимизации по скорости (на них я получал аналогичный результат), просто люди погнались за красивой итоговой цифрой. Порядок сходиться, можно считать что для zero-wait я получил валидный результат. Разница объясняется количеством итераций и разрядностью счетчика времени. Я считаю время по SysTick с делителем 8 (т.е. 18Mhz). Во всех приведенных выше примерах - таймер на 1кHZ или около того. Т.е. инструмент измерения (таймер) на 5 и более порядков меньшей разрядности, чем измеряемый процесс. Что могло у них пойти не так ?:) Но для быстрого флэша это не так критично. Теперь интереснее.

Те, кто интересуется контроллерами WCH, могли встречать различные оценки скорости флэша в верхних адресах. Для V203 я таких данных не находил, а вот V307 тестировали. Я встречал оценки в 10 и даже 18 раз медленнее. Удалось найти репорт по этому поводу https://blog.csdn.net/mx1117/article/details/126094948

Из репорта видно, что компилируется бенчмарк на оптимизации -Os. Если залезть в ASM, то видно в чем отличие. Поcкольку компилятор при -O3 разворачивает циклы, поток команд теста по большей части состоит из команд работы с регистрами. А вот при компиляции с -Os большая часть команд - команды работы с операндами в тот же самом медленном флэше. При тестах на оптимизации -O3 замедление происходит на выборке команды и результат характеризует в большей степени производительность флэш. В случае тестов на оптимизации -Os замедление происходит еще и на выборке операнда, т.е. дважды. Что характеризуют результаты тестов с оптимизацией -Os аллах его знает. Формально производительность системы, но медленного флэша в WCH в 3 раза больше чем кэшируемого, какой практический смысл исполняться там с оптимизацией по размеру?

Проблем с валидостью тестов коллегам подкидывает использование для расчета времени таймера, а не SysTick. А еще, видимо что бы не ждать или что бы не переполнять таймер, они сокращают кол-во итераций теста при исполнении в верхних адресах. Все это приводит к некорректным результатам тестирования. Мне лень повторять тесты при таких же условиях. Но на оптимизации -Os я тем не менее эксперимент провел, результат для верхних адресов предсказуемо в 2 раза медленнее чем при оптимизации -O3.

Анализ результатов

С валидностью надеюсь разобрались. Теперь можно попробовать накинуть аналитики. Первое и самое неожиданное, V3 медленнее в тестах чем V2. Чуть чуть, но тем не менее. Для верности я сравнил оба проекта на тему настроек IDE, размера кода исполняемого бенчамарака и бегло глянул .lst. Все идентично рубль в рубль. Тогда какого? Может не прав, но тут 2 разных ядра QingKeV4B и QingKeV4F. Помимо FPU, который не используется в тестах, на 4F есть модуль защиты памяти. Т.е. по идее это дополнительный блок в цепочке ядро-память. Не однозначно, но MPU единственное видимое отличие, и вроде как логично объясняет небольшую разницу в скорости.

Но это мелочь, главное что же там за флэш то? Я думаю ответ тут. https://www.eembc.org/viewer/?benchmark_seq=13659 Получается что тесты для V203 144Mhz из верхних адресов и CH32X033F8P6 48Mhz дают очень близкие результаты. Оба чипа на ядре QingKeV4, в обоих случаях код исполняется из внешнего флэш, с частотой доступа меньше частоты ядра, т.е. по факту производительность ограничена шиной доступа к флэш. У CH32X033F8P6 однозначно определена частота доступа по системной шине к данным- это 20Mhz. Для частот ядра выше 20Мhz есть регистр Latensy, в котором нужно установкой wait-stait ограничивать скорость доступа к памяти. Не похоже на совпадение. Я думаю в случае с CH32V203 мы имеет дело с 20Mhz внешнем SPI флэшем ( имеется ввиду не скорость физического доступа к микросхеме, а что по итогу обеспечивается на шине ядра). И загадочным контроллером Flash, который копирует при старте часть флэша в SRAM, а в процессе работы, в случае обращения со стороны ядра за пределы кэша, автоматом накидывает условно 10 wait-stait. Поэтому мы получаем равномерное падение производительности в верхних адресах на всех частотах. Еще одно отличие от CH32X033F8P6 , это тактирование записи во флэш. Во всех младших семействах WCH тактирование идет от HSI напрямую, в случае CH32X033F8P6 от всторенного 8Mhz. А вот на V2 и V3 тактирование с системной шины APH, через делитель, но с ограничением в 60Mhz. Если принять, что в V203 частота обращения к флэш 20Mhz, то на кой черт контроллеру флэш 60, при том что аналогичное ядро справляется с тем же самым на 8? А видимо для синхронизации кэша при записи. Допустим спорное утверждение, но логика в этом есть.

А что с V3? Ну там падение производительности в 5 раз. Это в 2 раза меньше чем на V2. Если поискать в закромах WCH, то находиться CH32L103 на ядре QingKeV4C. Там есть регистр latency, но частота обращения к флэш 40Mhz.Так что очень похоже, что в случае с V303/ V307 мы имеем дело как раз с флэшем на 40Mhz.

Выводы

Помимо размещения данных в верхних адресах, волне можно придумать части кода для переноса в non zero-wait зону флэш. Разницы по сути нет, при размещение данных замедление идет на выборке операнда, при размещение кода - точно такое же при выборке команды. Поэтому для кода оптимизация по скорости ( желательно максимально хардкорная, см. ссылку выше, CoreMark 459 против 380 на просто O3). Ну и Flash Enhanced Read Mode для верхних адресов желателен, поскольку добавляет около 8% ускорения. В случае с V3 имеет падение скорости доступа в 5 раз, в случае с V2 - в 10 раз. Не стоит путать эти цифры с падением производительности. Она может быть выше если код исполняемый в верхних адресах использует данные из той же зоны флэш. Как в случае с оптимизацией по размеру. Тогда падение производительности будет выше чем разница в скорости доступа.

UPD: Рекомендации для проведения аналогичных экспериментов.

  1. Ни когда не сравнивайте свои результаты с любыми другими, если не видите репорта и не понимайте в каких условиях проводились тесты. Люди творят дичь.

  2. Желательно, а если вы в первый раз делайте тесты то обязательно, делать сравнения на разны частотах тактирования. Удельная производительность ( кол-во циклов на 1Mhz) наше все. В общем случае она одинакова до последнего знака на разных частотах . Если есть расхождения и вы не можете их объяснить, то либо вы творите дичь, либо наткнулись на какую-то новую для себя особенность МК. В обоих случая получите полезные знания. Когда нет опыта, без массива данных найти ошибки и валидировать свои результаты не реально.

  3. Разное кол-во итераций бенчмарака дает разные результаты. Ждать пока оно прокрутиться 10 минут на низкой частоте трудно, но таков путь.

  4. Соотносите разрядность таймера замера времени с задачей. Результат CoreMark - кол-во итераций теста деленое на кол-во тиков таймера. Прикиньте формулу, посмотрите как оно считается в бенчмарке. Нет ли где потери данных?

Tags:
Hubs:
+13
Comments5

Articles