Перейти к содержанию
    

упаковка данных в структуре

 

2 минуты назад, natsu сказал:

Тогда две структуры описывать не нужно, на все сгодится упакованная.

Не совсем. Думаю - размер у них будет разным.

2 минуты назад, natsu сказал:

И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)?

Надо для кого/чего? Сначала на этот вопрос ответьте.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

10 минут назад, natsu сказал:

Тогда получается что (обычная) структура из упакованных структур будет всегда содержать выровненные данные?

Увы нет. Упакованные (в т.ч. разные) структуры ложатся по невыравненным адресам.

9 минут назад, jcxz сказал:
Цитата

И остается изначальный вопрос, а надо ли после чтения блока данных извлекать структуру и копировать ее в гарантированно выравненную область памяти (та самая структура для структур из предыдущего абзаца)?

Надо для кого/чего? Сначала на этот вопрос ответьте.

Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу.

 

Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

42 минуты назад, jcxz сказал:

Какие-то чудеса рассказываете. На Cortex-M невыровненность доступа добавит наверное 1 такт к длительности команды чтения...

Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа). А на "настоящих" ARM-ах любой unaligned access - это Data Abort.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

50 минут назад, Arlleex сказал:

Ну как сказать... Cortex-M разные бывают, и unaligned access в M0 - это Fault, а в других ядрах - задается специальным битом в регистрах настройки ядра CPU (по умолчанию - поддержка невыровненного доступа).

Ну естественно я имел в виду Cortex-M >= Cortex-M3. В тех МК, о которых шла речь, нету M0.

53 минуты назад, iiv сказал:

это совершенно не вяжется с тем, что я наблюдаю на IMXRT1062, конкретно на teensy 4.1

Ну так значит - читаем п.2:  :biggrin:

1 час назад, jcxz сказал:

PS: Может у вас там (на ESP32) тупо разрешена генерация fault-ов при невыровненном доступе? :biggrin: И вызовы их обработчика и замедляют работу программы.

55 минут назад, iiv сказал:

и скорость падает в разы, а не с 2 на 3 такта, а если включить блок копирования структур, то все падает сразу. В esp32 все точно также с той лишь разницей, что доступ к памяти там существенно медленнее.

У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут.  :unknw:

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, jcxz said:

У Вас эмулятор есть? Если есть, то с ним причина выясняется за несколько минут.  :unknw:

у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1 час назад, natsu сказал:

Для данного конкретного случая. После чтения блока данных внутри него окажется требуемая структура с произвольного адреса. А данные надо обработать и передать по другому интерфейсу.

Меня интересуют критерии, на основании которых можно будет принять решения. Я не прошу принять решения за меня. Я прошу помочь мне научиться самому принимать обоснованные решения.

Критерии вы сами определяете. Исходя из того, как используете данные. Здесь ясновидцев нету.

Если Вы полученную структуру потом 1000 раз читаете/пишете, то наверное есть выигрыш в скорости от того, чтобы скопировать её в отдельное место и работать с ней уже выровненной. А если вы её всего несколько раз читаете/пишете - ну добавляет вам невыровненный доступ десяток лишних тактов - и что? А копирование - занимает несколько десятков тактов как минимум. Так есть выигрыш или проигрыш от копирования? Мы же не знаем сколько раз вы её читаете/пишете.

 

PS: Да и вообще - в вашем МК есть все средства чтобы измерить время. И самому посмотреть разницу между работой с выровненной и невыровненной структурой. Достаточно нескольких минут чтобы сравнить.  :unknw:

 

16 минут назад, iiv сказал:

у меня не эмулятор, а натурные эксперименты, которые показывают падение скорости на teensy 4.1 c IMXRT1062 почти в 10 раз при копировании по структуре, а при доступе через 4-байтовые вызывают фаулт. Я не понимаю, что вы припераетесь?

Вы поняли что я писал? Судя по всему - нет. Советую ещё раз внимательно перечитать мой пост и внимательно подумать.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

возвращаясь к вопросу выравнивания...

 

Сделал я упакованные структуры, поместил их в обычную структуру с атрибутом aligned каждую и все вроде бы хорошо, компилятор все структуры выровнял, теперь можно копировать и работать  с выровненными данными. Все данные внутри от большего размера к меньшему - т.е. если выровнен первый элемент, то остальные и подавно. Но несмотря на то, что я явно запросил align, компилятор выводит предупреждения (иногда сразу, иногда только во время компиляции) и их много. Что не так или как подавить эти предупреждения?

 

\fdata.c(326): warning: padding struct 'struct my' with 4 bytes to align 'ennow' [-Wpadded]
                __attribute__((aligned (8))) double ennow[2][3];

                                                    ^

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

6 minutes ago, natsu said:

                __attribute__((aligned (8))) double ennow[2][3];

я бы double тоже по 8 байт выравнивал бы, ну а если структура с оными, то и структуру тоже. Я за все контроллеры не овечаю, но это очень распространенная проблема потери скорости и на обычных процессорах, и на контроллерах. Основная причина - попадание одного double в две строки кеша.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

3 минуты назад, iiv сказал:

я бы double тоже по 8 байт выравнивал бы

так aligned (8) разве не оно?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

28 minutes ago, natsu said:

так aligned (8) разве не оно?

Оно-то и оно. Так надо и саму структуру тоже также выравнивать. ИМХО, компиллер именно из-за этого и ругается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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];
        };

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А я бы по-другому написал бы, и все выровнялось бы само собой:

struct my
{ double ennow[2][3];
  datprof_t dat; // она у вас 4 байта?
  zagprof_t zag; // а эта 2 байта?
  char pad1[2]; // а это окончательное выравнивание всей структуры
};

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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]; но как то не выглядит это разумным.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...