jcxz 243 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 2 минуты назад, natsu сказал: Тогда две структуры описывать не нужно, на все сгодится упакованная. Не совсем. Думаю - размер у них будет разным. 2 минуты назад, natsu сказал: И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)? Надо для кого/чего? Сначала на этот вопрос ответьте. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 10 минут назад, natsu сказал: Тогда получается что (обычная) структура из упакованных структур будет всегда содержать выровненные данные? Увы нет. Упакованные (в т.ч. разные) структуры ложатся по невыравненным адресам. 9 минут назад, jcxz сказал: Цитата И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)? Надо для кого/чего? Сначала на этот вопрос ответьте. Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу. Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 34 minutes ago, jcxz said: На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения. И всё. Вместо 2 тактов станет 3. это совершенно не вяжется с тем, что я наблюдаю на IMXRT1062, конкретно на teensy 4.1. Возьмите пример #pragma GCC push_options #pragma GCC optimize ("Ofast") #include <stdio.h> #include <stdlib.h> #include <string.h> #include <math.h> #include <Arduino.h> unsigned char DMAMEM DmaMem[480*1024]; unsigned char EXTMEM ExtMem[16*1024*1024]; unsigned char GenMem[460*1024]; // each class is only 8 bytes class cTestData1 { public: unsigned char A1, A2, A3, A4, A5, A6, A7, A8; }; class cTestData2 { public: unsigned short A1, A2, A3, A4; }; class cTestData3 { public: unsigned int A1:24, A2:20, A3:13, A4:7; }; class cTestData4 { public: unsigned int A1, A2; }; void TestDataS(unsigned char *p1, unsigned char *p2) // copy data from one test memory block to other and measure the total amount of CPU tacts for 64K transfer { unsigned long begin, end; unsigned int *pI1, *pI2; #if 0 // если поставить здесь 1, то падает при копировании этих структур cTestData1 *pT1; cTestData2 *pT2; cTestData3 *pT3; cTestData4 *pT4; cTestData4 *pT41; pT1=(cTestData1*)p1; pT2=(cTestData2*)p2; begin=ARM_DWT_CYCCNT; for(int i=0; i<8192; i++) { pT2[i].A1=pT1[i].A1; pT2[i].A2=pT1[i].A2; pT2[i].A3=pT1[i].A3; pT2[i].A4=pT1[i].A4+pT1[i].A5+pT1[i].A6+pT1[i].A7+pT1[i].A8; } end=ARM_DWT_CYCCNT; Serial.print(end-begin); Serial.print(" "); pT2=(cTestData2*)p2; pT3=(cTestData3*)p1; begin=ARM_DWT_CYCCNT; for(int i=0; i<8192; i++) { pT3[i].A1=pT2[i].A1; pT3[i].A2=pT2[i].A2; pT3[i].A3=pT2[i].A3; pT3[i].A4=pT2[i].A4; } end=ARM_DWT_CYCCNT; Serial.print(end-begin); Serial.print(" "); pT3=(cTestData3*)p1; pT4=(cTestData4*)p2; begin=ARM_DWT_CYCCNT; for(int i=0; i<8192; i++) { pT4[i].A1=pT3[i].A1; pT4[i].A2=pT3[i].A2+pT3[i].A3+pT3[i].A4; } end=ARM_DWT_CYCCNT; Serial.print(end-begin); Serial.print(" "); pT4=(cTestData4*)p2; pT1=(cTestData1*)p1; begin=ARM_DWT_CYCCNT; for(int i=0; i<8192; i++) { pT1[i].A1=pT4[i].A1; pT1[i].A2=pT4[i].A1; pT1[i].A3=pT4[i].A1; pT1[i].A4=pT4[i].A1; pT1[i].A5=pT4[i].A2; pT1[i].A6=pT4[i].A2; pT1[i].A7=pT4[i].A2; pT1[i].A8=pT4[i].A2; } end=ARM_DWT_CYCCNT; Serial.print(end-begin); Serial.print(" "); pT4=(cTestData4*)p1; pT41=(cTestData4*)p2; begin=ARM_DWT_CYCCNT; for(int i=0; i<8192; i++) { pT41[i].A1=pT4[i].A1; pT41[i].A2=pT4[i].A2; } end=ARM_DWT_CYCCNT; Serial.print(end-begin); Serial.print(" "); #endif pI1=(unsigned int*)p2; pI2=(unsigned int*)p1; begin=ARM_DWT_CYCCNT; for(int i=0; i<32768; i++) pI2[i]=pI1[i]; end=ARM_DWT_CYCCNT; Serial.print(((end-begin)/16384+1)/2); Serial.print(" "); Serial.print(end-begin); Serial.print(" "); pI1=(unsigned int*)p2; begin=ARM_DWT_CYCCNT; for(int i=0; i<32768; i++) pI1[i]=i; end=ARM_DWT_CYCCNT; Serial.print(((end-begin)/16384+1)/2); Serial.print(" "); Serial.println(end-begin); } int ShiftList1[] = {0, 4, 8, 12, 16, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3}; int ShiftList2[] = {0, 4, 8, 12, 16, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3}; void TestData(unsigned char *p) { Serial.printf("Testing memory of %p\n", p); for(int i=0; i<5; i++) //for(int i=0; i<sizeof(ShiftList1)/sizeof(ShiftList1[0]); i++) { Serial.printf("%p(%d) to %p(%d) started\n", p+ShiftList1[i], ShiftList1[i], p+65536+ShiftList1[i], 65536+ShiftList1[i]); TestDataS(p+ShiftList1[i], p+(256*1024)+ShiftList1[i]); } } void setup() { while(!Serial); if (CrashReport) { Serial.print(CrashReport); delay(10000); } } void loop() { Serial.println("GenMem"); TestData(GenMem); Serial.println("DmaMem"); TestData(DmaMem); Serial.println("ExtMem"); TestData(ExtMem); Serial.println("GenDma"); TestDataS(GenMem, DmaMem); Serial.println("DmaExt"); TestDataS(DmaMem, ExtMem); Serial.println("GenExt"); TestDataS(GenMem, ExtMem); Serial.println("DmaGen"); TestDataS(DmaMem, GenMem); Serial.println("ExtDma"); TestDataS(ExtMem, DmaMem); Serial.println("ExtGen"); TestDataS(ExtMem, GenMem); delay(1000); } #pragma GCC pop_options что я как-то на форуме teensy 4.1эту проблему рассматривал, в этом примере измеряется скорость доступа к разной памяти с точным "allign" и нет и скорость падает в разы, а не с 2 на 3 такта, а если включить блок копирования структур, то все падает сразу. В esp32 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 42 минуты назад, jcxz сказал: Какие-то чудеса рассказываете. На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения... Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа). А на "настоящих" ARM-ах любой unaligned access - это Data Abort. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 50 минут назад, Arlleex сказал: Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа). Ну естественно я имел в виду Cortex-M >= Cortex-M3. В тех МК, о которых шла речь, нету M0. 53 минуты назад, iiv сказал: это совершенно не вяжется с тем, что я наблюдаю на IMXRT1062, конкретно на teensy 4.1 Ну так значит - читаем п.2: 1 час назад, jcxz сказал: PS: Может у вас там (на ESP32) тупо разрешена генерация fault-ов при невыровненном доступе? И вызовы их обработчика и замедляют работу программы. 55 минут назад, iiv сказал: и скорость падает в разы, а не с 2 на 3 такта, а если включить блок копирования структур, то все падает сразу. В esp32 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее. У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 6 minutes ago, jcxz said: У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут. у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
jcxz 243 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 1 час назад, natsu сказал: Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу. Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения. Критерии вы сами определяете. Исходя из того, как используете данные. Здесь ясновидцев нету. Если Вы полученную структуру потом 1000 раз читаете/пишете, то наверное есть выигрыш в скорости от того, чтобы скопировать её в отдельное место и работать с ней уже выровненной. А если вы её всего несколько раз читаете/пишете - ну добавляет вам невыровненный доступ десяток лишних тактов - и что? А копирование - занимает несколько десятков тактов как минимум. Так есть выигрыш или проигрыш от копирования? Мы же не знаем сколько раз вы её читаете/пишете. PS: Да и вообще - в вашем МК есть все средства чтобы измерить время. И самому посмотреть разницу между работой с выровненной и невыровненной структурой. Достаточно нескольких минут чтобы сравнить. 16 минут назад, iiv сказал: у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь? Вы поняли что я писал? Судя по всему - нет. Советую ещё раз внимательно перечитать мой пост и внимательно подумать. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба возвращаясь к вопросу выравнивания... Сделал я упакованные структуры, поместил их в обычную структуру с атрибутом aligned каждую и все вроде бы хорошо, компилятор все структуры выровнял, теперь можно копировать и работать с выровненными данными. Все данные внутри от большего размера к меньшему - т.е. если выровнен первый элемент, то остальные и подавно. Но несмотря на то, что я явно запросил align, компилятор выводит предупреждения (иногда сразу, иногда только во время компиляции) и их много. Что не так или как подавить эти предупреждения? \fdata.c(326): warning: padding struct 'struct my' with 4 bytes to align 'ennow' [-Wpadded] __attribute__((aligned (8))) double ennow[2][3]; ^ Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 6 minutes ago, natsu said: __attribute__((aligned (8))) double ennow[2][3]; я бы double тоже по 8 байт выравнивал бы, ну а если структура с оными, то и структуру тоже. Я за все контроллеры не овечаю, но это очень распространенная проблема потери скорости и на обычных процессорах, и на контроллерах. Основная причина - попадание одного double в две строки кеша. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 3 минуты назад, iiv сказал: я бы double тоже по 8 байт выравнивал бы так aligned (8) разве не оно? Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 28 minutes ago, natsu said: так aligned (8) разве не оно? Оно-то и оно. Так надо и саму структуру тоже также выравнивать. ИМХО, компиллер именно из-за этого и ругается. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба 6 минут назад, iiv сказал: так надо и саму структуру тоже также выравнивать У меня собирательная структура состоит из нескольких структур и одного массива double как описано выше, у всех элементов структуры атрибут aligned(8). Что еще надо выровнять? Обнаружил, что если я вставляю между элементами в одном месте char pad[4]; в другом char pad2[6]; то предупреждения исчезают. Вот только зачем они там? struct my { __attribute__((aligned (8))) zagprof_t zag; char pad1[6]; __attribute__((aligned (8))) datprof_t dat; char pad2[4]; __attribute__((aligned (8))) double ennow[2][3]; }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
iiv 29 26 апреля, 2022 Опубликовано 26 апреля, 2022 · Жалоба А я бы по-другому написал бы, и все выровнялось бы само собой: struct my { double ennow[2][3]; datprof_t dat; // она у вас 4 байта? zagprof_t zag; // а эта 2 байта? char pad1[2]; // а это окончательное выравнивание всей структуры }; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Arlleex 190 27 апреля, 2022 Опубликовано 27 апреля, 2022 · Жалоба 9 часов назад, natsu сказал: Вот только зачем они там? zagprof_t и datprof_t покажите. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
natsu 0 27 апреля, 2022 Опубликовано 27 апреля, 2022 · Жалоба typedef struct {double energy[2][3];uint16_t mask;} __attribute__((packed)) zagprof_t; typedef struct {uint32_t stamp;float data[16];} __attribute__((packed)) datprof_t; 10 часов назад, iiv сказал: А я бы по-другому написал бы, и все выровнялось бы само собой: а вот так не получается. Правда одна из ошибок исчезает, если в конце структуры добавить char pad[8]; но как то не выглядит это разумным. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться